《快速集成指南》

本文介绍的是 AnySDK Framework 在 cocos2d-x lua 的集成流程和注意事项(适用于 Quick-x)。

Android 接入

主要流程

  1. 获取 AnySDK Framework;
  2. 获取 AnySDK Lua 绑定文件;
  3. 配置 AnySDK Framework 到项目中;
  4. 配置 AnySDK Lua 文件到项目中;
  5. 初始化 AnySDK;
  6. 使用各个接口;
  7. Sample:https://github.com/AnySDK/Sample_Lua (Sample 版本为 Cocos2d-x 3.3rc0)。
  8. 如果使用的 Quick-x 版本有自带 AnySDK 库,请更新 AnySDK 最新的库,并改用 AnySDK 的 Lua 脚本绑定。
  9. 使用 AnySDK Lua 框架的时候,版本 2.x:建议使用 Cocos2d-x v2.2.0 及以上的版本;版本 3.x,建议使用 Cocos2d-x v3.0 及以上的版本。

获取 AnySDK Framework

为了集成 AnySDK Framework,请在 AnySDK 客户端的 安妮市场 里,选择 Lua(Android) 框架进行下载目录打开如下:
Lua 框架目录
查看游戏项目使用 STL 库的版本:
以 Cocos2d-x 框架为例,开发者可以在工程目录下 jni/Application.mk 文件第一行找到 STL 库类型设置。
如果此处设置的是 APP_STL := gnustl_static,则表示当前工程以 GNU 静态库的方式引入使用 STL 标准库,此时应选择集成 protocols_gnustl_static 这个文件夹中的框架资源。
如果是 APP_STL := c++_static,则选择集成 protocols_c++_static 文件夹中的框架资源。
如果是 APP_STL := stlport_static,则应选择集成 protocols_stlport_static 文件夹中的框架资源。

下载得到的 AnySDK Framework 框架资源目录内各部分介绍如下图所示:
框架目录结构

获取 AnySDK Lua 绑定文件

下载 AnySDK Framework for Lua 包后,解压,会有两个 2.x 和 3.x 的包,根据使用的 Cocos2d-x 的版本,来选择相应的绑定文件。
src 下面则是一个 anysdkConst.lua 文件,该文件是对应 C++ 里面定义的枚举变量。(使用的时候,需要在文件里面引用 require "anysdkConst"

拷贝 AnySDK Framework STL 库到 protocols 文件夹

protocols 文件

首先,查看项目的 frameworks/runtime-src/proj.android/jni/Application.mk 文件(注:Cocos2d-x v2.x 和 v3.x,该文件所在文件夹路径不同),第一行找到 STL 库类型设置。 如下图: STL 库类型设置
然后,进入项目的 frameworks/runtime-src/proj.android 目录,新建 protocols 文件夹。根据上面查看到的 STL 类型,选取 AnySDK_Framework_Lua/framework/protocols_gnustl_static 库,然后将该目录下的 android 和 include 文件夹拷贝到 protocols 目录。

res 文件

将 AnySDK_Framework_Lua/framework/protocols_gnustl_static 目录下的 res 文件里的资源,拷贝到 proj.android/res 目录下,注意选择合并,避免文件覆盖。

class 文件

将 AnySDK_Framework_Lua/3.x 目录下的文件拷贝到 frameworks/runtime-src/Classes 目录下

放置 libPluginProtocol.jar 包

cocos 命令编译的时候,jar 包需要在 libs 目录里,在 proj.android 目录下新建 libs 文件夹,然后将 proj.android/protocols/android 目录下的 libPluginProtocol.jar 移到该目录下。
PS:部分版本 jar 包是放在 jars 目录里。

编辑 Android.mk 文件

Android.mk 文件在 frameworks/runtime-src/proj.android/jni 下面。(注意 v2.x 和 v3.x 的 Cocos2d-x,这个文件的目录不一样)

增加 NDK_MODULE_PATH:

不同版本不同编译方式有不同的添加方法,在此提供一个通用的添加方法,不管是哪种方法,只要编译能找到 AnySDK 的库即可。
在 Android.mk 第一行 LOCAL_PATH := $(call my-dir) 下面新加一行代码。

LOCAL_PATH := $(call my-dir)
$(call import-add-path,$(LOCAL_PATH)/../)

修改 LOCAL_SRC_FILES

在 LOCAL_SRC_FILES 新增 Lua 绑定的 cpp 文件:anysdkbindings.cpp 和 anysdk_manual_bindings.cpp,例:

LOCAL_SRC_FILES := hellolua/main.cpp \
                   ../../Classes/AppDelegate.cpp \
                   ../../Classes/anysdkbindings.cpp \
                   ../../Classes/anysdk_manual_bindings.cpp

新增 static lib

例:

LOCAL_WHOLE_STATIC_LIBRARIES += PluginProtocolStatic

注:PluginProtocolStatic 请勿使用 LOCAL_STATIC_LIBRARIES,否则会导致 AnySDK 部分函数找不到。

新增 modules

例:

$(call import-module,protocols/android)

添加设置 javaVM 代码

修改 main.cpp 文件

3.3rc0 及其以上版本:

#include "PluginJniHelper.h"

#define  LOG_TAG    "main"
#define  LOGD(...)  __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)

using namespace cocos2d;
using namespace anysdk::framework;

void cocos_android_app_init (JNIEnv* env, jobject thiz) {
    LOGD("cocos_android_app_init");
    AppDelegate *pAppDelegate = new AppDelegate();
    JavaVM* vm;
    env->GetJavaVM(&vm);
    PluginJniHelper::setJavaVM(vm);
}

2.x 版本(proj.android/jni/hellolua/main.cpp)、3.3rc0 之前版本(例如 3.2 在 frameworks/cocos2d-x/cocos/platform/android/javaactivity.cpp):

#include "PluginJniHelper.h"

#define  LOG_TAG    "main"
#define  LOGD(...)  __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)

using namespace cocos2d;
using namespace anysdk::framework;

jint JNI_OnLoad(JavaVM *vm, void *reserved)
{
  JniHelper::setJavaVM(vm);
  PluginJniHelper::setJavaVM(vm);
  return JNI_VERSION_1_4;
}

注:因为 setJavaVM 需要在 onCreate 之前,所以写在 JNI_OnLoad 里肯定没错。3.3rc0 及其以上版本的 cocos_android_app_init 是在 onCreate 之前的,所以也可以写在这里。3.x 版本头文件需要写全路径,例如 3.2 版本 #include "../../../../runtime-src/proj.android/protocols/android/PluginJniHelper.h"

示例如图

设置 JavaVM

配置 AndroidManifest.xml 添加框架需要的权限

  <uses-permission android:name="android.permission.INTERNET" />
  <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
  <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
  <uses-permission android:name="android.permission.RESTART_PACKAGES" />
  <uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES" />

在 JAVA 层初始化 AnySDK Framework 框架

初始化 AnySDK Framework

首先找到游戏工程的主 Activity,以 Cocos2d-x 引擎游戏为例,主 Activity 即是继承了 Cocos2dxActivity 的 Activity。 并在主 Activity 的 onCreate() 方法中新增如下代码来初始化 AnySDK Framework:修改 proj.android/src/org/cocos2dx/javascript/AppActivity.java 文件。

import com.anysdk.framework.PluginWrapper;

public class MainActivity extends Activity{
   protected void onCreate(Bundle savedState)
   {
      super.onCreate(savedState);
      PluginWrapper.init(this); // for plugins
      PluginWrapper.loadAllPlugins(); // 建议在 onCreate 里加载插件,此时会对 SDK 进行初始化
   }
}

注:

  1. 在 Cocos2d-x 3.0 版本中集成 Cocos2dxActivity 之后已经不需要手动实现其他方法,因此如果开发者发现主 Activity 没有 onCreate 方法,就需要自己去重写这个方法(直接拷贝上面的代码片段也可以)。且 super.onCreate(savedState); 请在 PluginWrapper.init(this); 之前调用,因为 init 的时候需要调用 C++ 函数,而 so 文件是在 onCreate 时加载。
  2. AnySDK 的回调函数默认是在主线程,可以在 onCreate 加上 PluginWrapper.setGLSurfaceView(Cocos2dxGLSurfaceView.getInstance()); 将回调改成在 GL 线程,不在 GL 线程里操作界面会有问题。

重写 Activity 生命周期相关方法

重写 Activity 生命周期相关方法,代码如下:

import android.content.Intent;
import android.os.Bundle;
import android.content.res.Configuration;

import com.anysdk.framework.PluginWrapper;
@Override
protected void onDestroy() {
    PluginWrapper.onDestroy();
    super.onDestroy();
}

@Override
protected void onPause() {
    PluginWrapper.onPause();
    super.onPause();
}

@Override
protected void onResume() {
    PluginWrapper.onResume();
    super.onResume();
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    PluginWrapper.onActivityResult(requestCode, resultCode, data);
    super.onActivityResult(requestCode, resultCode, data);
}

@Override
protected void onNewIntent(Intent intent) {
    PluginWrapper.onNewIntent(intent);
    super.onNewIntent(intent);
}

@Override
protected void onStop() {
    PluginWrapper.onStop();
    super.onStop();
}

@Override
protected void onRestart() {
    PluginWrapper.onRestart();
    super.onRestart();
}

@Override
public void onBackPressed() {
    PluginWrapper.onBackPressed();
    super.onBackPressed();
}

@Override
public void onConfigurationChanged(Configuration newConfig) {
    PluginWrapper.onConfigurationChanged(newConfig);
    super.onConfigurationChanged(newConfig);
}

@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
    PluginWrapper.onRestoreInstanceState(savedInstanceState);
    super.onRestoreInstanceState(savedInstanceState);
}

@Override
protected void onSaveInstanceState(Bundle outState) {
    PluginWrapper.onSaveInstanceState(outState);
    super.onSaveInstanceState(outState);
}

@Override
protected void onStart() {
    PluginWrapper.onStart();
    super.onStart();
}

配置 AnySDK Lua 文件到项目中

修改 AppDelegate 文件

  1. 放置 anysdkbindings.h、anysdkbindings.cpp、anysdk_manual_bindings.h、anysdk_manual_bindings.cpp 这 4 个文件到 Classes 文件夹下。
  2. 修改 AppDelegate.cpp 文件(3.x 路径是:frameworks/runtime-src/Classes/AppDelegate.cpp,2.x 路径是 Classes/AppDelegate.cpp)

在 executeScriptFile 之前新增:
3.x 版本如下:

LuaStack* stack = engine->getLuaStack();
lua_getglobal(stack->getLuaState(), "_G");
tolua_anysdk_open(stack->getLuaState());
tolua_anysdk_manual_open(stack->getLuaState());
lua_pop(stack->getLuaState(), 1);

2.x 版本如下:

CCLuaStack *pStack = pEngine->getLuaStack();
lua_State *tolua_s = pStack->getLuaState();
lua_getglobal(tolua_s, "_G");
tolua_anysdk_open(tolua_s);
tolua_anysdk_manual_open(tolua_s);
lua_pop(tolua_s, 1);

并引用对应的头文件:

#include "anysdkbindings.h"
#include "anysdk_manual_bindings.h"

示例

修改 AppDelegate 文件
注:随着 Cocos2d-x 的版本升级,这个文件的内容可能不同,但是都是可以添加自定义绑定方法的。

在项目中初始化并加载 AnySDK

在 Lua 文件里面使用下面几行初始化 AnySDK:

--注意:这里 appKey,appSecret,privateKey,要替换成自己打包工具里面的值(登录打包工具,游戏管理界面上显示的那三个参数)。
local appKey = "CED525C0-8D41-F514-96D8-90092EB3899A"
local appSecret = "a29b4f22aa63b8274f7f6e2dd5893d9b"
local privateKey = "963C4B4DA71BC51C69EB11D24D0C7D49"
local oauthLoginServer = "http://oauth.anysdk.com/api/OauthLoginDemo/Login.php"
local agent = AgentManager:getInstance()
--init
agent:init(appKey,appSecret,privateKey,oauthLoginServer)
--load
--Android 建议在 onCreate 里调用 PluginWrapper.loadAllPlugins(); 来进行插件初始化
--agent:loadAllPlugins()

卸载SDK插件

在游戏结束或者适当的时候,调用 unloadAllPlugins 来卸载 SDK 插件。

agent:unloadAllPlugins();

注意事项

isFunctionSupported 的使用

并不是所有的函数都需要这样判断是否支持。像 login,就直接调用即可。

IOS 接入

获取 AnySDK Framework

为了集成 AnySDK Framework,请在 AnySDK 客户端的 安妮市场 里,选择 Lua(iOS) 框架进行下载。
下载后建议将框架拷贝到其他位置,由于下载文件夹带有空格(目前已去掉目录的空格),可能会导致工程库的搜索路径因为空格被分成两部分,导致编译错误。
打开文件夹,内容如下:
框架目录

删除多余的 Targets

目前打包工具只支持单个 Target,若有多个 Targets 会导致打包出来的工程文件缺失,无法正常运行。
可在目标上右键选择删除。
 Target 配置
如果有其他 Target 所需要用到的同名 .plist 文件,也需要删除,否则打包后工程 AnySDK 文件夹下可能会缺失 .plist 文件。
 info.plist 位置
若不想在原工程文件上操作,可以在同级目录下拷贝一份 .xcodeproj,并且打开其包内容,删除 xcuserdata 文件夹和 project.xcworkspace 下的 xcuserdata 文件夹,修改 /project.xcworkspace/contents.xcworkspacedata 文件中的 location 值,为改名后的文件名,再对拷贝后的工程文件进行操作。
 xcworkspacedata 拷贝

将图标转为 Asset Catalog 形式

在母工程中需要将 icon 转为 Asset Catalog 形式,否则可能导致打包后图标替换错误或者闪屏替换出现问题。
设置 Icon
若按钮为此样式,点击该 Use Asset Catalog 按钮,Xcode 会自动转化原有图标,生成一个 Images.xcassets 文件夹。

在项目中引用 libPluginProtocol

打开您的 iOS 项目(也就是 your-project-name.xcodeproj),一般有两种方式可以引入一个外部的 Framework 文件(参考下面的 1. 添加文件到项目中,2. 添加 lib 到项目中),两种方式都可以。

1. 添加文件到项目中

右键点击项目中的 lib 文件夹,点击 Add Files to “your project name”,之后会弹出选择文件的框,找到 protocols, 选取它,并点击 add,添加 libPluginProtocol.a 就成功了。请不要修改 .a 的文件名(不同框架下文件名可能为 "libPluginProtocol.a","libPluginProtocol_libc++.a" 或 "libPluginProtocol_libstdc++.a"),否则打包时检测框架版本号时会报错。
添加库
添加 protocols 注意要选择 Create groups
添加库
PS:如何选择框架版本。
开发者可以在工程配置查询 C++ Standard Library 中查看是 libc++libstdc++compiler-default 来选择相应的库文件。
库配置

2. 添加 lib 到项目中

在 xcode 里面选中你的项目,选择 TARGETS -> Build Phases -> Link Binary With Libraries,点击 +,(如图红色箭头所指),弹出一个界面,点击 Add Other...,之后会弹出选择文件的框,找到 libPluginProtocol.a, 选取它,并点击 open,添加 libPluginProtocol.a 就成功了。(include 文件夹要手动添加到项目中,按照第一种方式)
链接库

引入框架之后如图

引入框架

添加工程配置

打开项目工程配置,添加库的链接参数,在项目⼯程配置,找到 Linking 中的 Linking Other Linker Flags,添加参数:-ObjC
链接设置
注意:如果您使用的是 Cocos2d-x 引擎,在添加 -ObjC 后,可能会有编译报错,类似:
错误提示
此时就要根据不同情况,来添加相应的类库。这里的这个报错,是需要添加库 MediaPlayer.frameworkGameController.framework

框架依赖库

libPluginProtocol 需要依赖以下这几个库:

CFNetwork.framework
CoreFoundation.framework
MobileCoreServices.framework
SystemConfiguration.framework
libz.dylib(Xcode7:libz.tbd)
Security.framework

配置 AnySDK Lua 文件到项目中

修改 AppDelegate 文件

  1. 放置 anysdkbindings.h、anysdkbindings.cpp、anysdk_manual_bindings.h、anysdk_manual_bindings.cpp 这 4 个文件到 Classes 文件夹下。
  2. 修改 AppDelegate.cpp 文件(3.x 路径是:frameworks/runtime-src/Classes/AppDelegate.cpp,2.x 路径是 Classes/AppDelegate.cpp)

在 executeScriptFile 之前新增。
3.x 版本如下:

LuaStack* stack = engine->getLuaStack();
lua_getglobal(stack->getLuaState(), "_G");
tolua_anysdk_open(stack->getLuaState());
tolua_anysdk_manual_open(stack->getLuaState());
lua_pop(stack->getLuaState(), 1);

2.x 版本如下:

CCLuaStack *pStack = pEngine->getLuaStack();
lua_State *tolua_s = pStack->getLuaState();
lua_getglobal(tolua_s, "_G");
tolua_anysdk_open(tolua_s);
tolua_anysdk_manual_open(tolua_s);
lua_pop(tolua_s, 1);

并引用对应的头文件:

#include "anysdkbindings.h"
#include "anysdk_manual_bindings.h"

示例

修改 AppDelegate 文件
注:随着 Cocos2d-x 的版本升级,这个文件的内容可能不同,但是都是可以添加自定义绑定方法的。

在项目中初始化并加载 AnySDK

在 Lua 文件里面使用下面几行初始化 AnySDK:

--注意:这里 appKey,appSecret,privateKey,要替换成自己打包工具里面的值(登录打包工具,游戏管理界面上显示的那三个参数)。
local appKey = "CED525C0-8D41-F514-96D8-90092EB3899A"
local appSecret = "a29b4f22aa63b8274f7f6e2dd5893d9b"
local privateKey = "963C4B4DA71BC51C69EB11D24D0C7D49"
local oauthLoginServer = "http://oauth.anysdk.com/api/OauthLoginDemo/Login.php"
local agent = AgentManager:getInstance()
--init
agent:init(appKey,appSecret,privateKey,oauthLoginServer)
--load
agent:loadAllPlugins()

卸载 SDK 插件

在游戏结束或者适当的时候,调用 unloadAllPlugins 来卸载 SDK 插件。

agent:unloadAllPlugins();

注意不要在 .m 文件中调用 AnySDK 的 Framework

注意不要在 .m 文件中调用 AnySDK 的 Framework,需要修改成 .mm 文件。

Cocos2dx(V2.2.x) 集成注意事项

在修改 other linker flag(添加 -ObjC)和引入 AnySDK 的 Framewrok 之后,有可能会报类似 library not found lluajit 的错误。如图:
错误提示
需做如下修改:
修改配置
此时在编译,会报类似 std::** 的错误,如图:
错误提示
解决办法如图:
修改配置 再次编译后,会报如下图的错误:
错误提示
解决办法如图:
修改配置
至此,编译错误搞定。

【评论区】