《快速集成指南》
Android 接入
获取 AnySDK Framework
为了集成 AnySDK Framework,请在 AnySDK 客户端的 安妮市场 里,选择 C++(Android) 框架进行下载,打开以后可以看到如下图的目录结构:
下载得到的 AnySDK Framework 框架资源目录内各部分介绍如下图所示:
导入 AnySDK Framework
关于 Cocos2d-x 引擎接入 AnySDK 框架的示例代码,可以参考 Sample_CPP_Cocos2dx 项目( Sample 版本为 Cocos2d-x 3.3rc0)
选择 AnySDK Framework 版本并导入到工程目录
-
查看游戏项目使用 STL 库的版本
以 Cocos2d-x 框架为例,开发者可以在工程目录下 jni/Application.mk 文件第一行找到 STL 库类型设置,如果此处设置的是APP_STL := gnustl_static
,则表示当前工程以 GNU 静态库的方式引入使用 STL 标准库,此时应选择集成 protocols_gnustl_static 这个文件夹中的框架资源。反之,则选择相应的集成 protocols_stlport_static、protocols_c++_static 文件夹中的框架资源。 -
在 Android 工程目录下面新建 protocols 目录,然后将上一步选择的对应版本框架目录下的 include 文件夹和 Android 文件夹拷贝到 protocols 下面。如下图:
-
将框架目录下的 res 文件夹中的所有资源文件拷贝到 Android 项目对应的文件中。
修改 Android.mk 文件配置 Framework 编译选项
这一步是修改游戏工程中 C++ 代码的 ndk 编译配置文件 Android.mk,将 AnySDK 提供的 Framework 库链接到游戏工程的库中。
1.将 protocols 目录添加到 NDK_MODULE_PATH 环境变量中:在 Android.mk 第一行 LOCAL_PATH := $(call my-dir)
下面新加一行代码
LOCAL_PATH := $(call my-dir)
$(call import-add-path,$(LOCAL_PATH)/../)
2.添加 AnySDK Framework 静态库声明:在 Android.mk 文件的 LOCAL_C_INCLUDES 声明下面添加一行代码
LOCAL_WHOLE_STATIC_LIBRARIES := PluginProtocolStatic
注:1. 此处注意语法规则,如果工程原有 mk 文件中没有其他 LOCAL_WHOLE_STATIC_LIBRARIES 声明,则添加上面的代码即可,如果 mk 文件中原来就有其他的 LOCAL_WHOLE_STATIC_LIBRARIES 声明,那么就需要加在原有声明之后,并且将 := 修改为 +=。
2. PluginProtocolStatic 请勿使用 LOCAL_STATIC_LIBRARIES,否则会导致 AnySDK 部分函数找不到。
3.添加库路径声明代码:在 Android.mk 文件的最后一行添加以下代码
$(call import-module,protocols/android)
导入框架自带的 jar 包并勾选 export 选项
步骤如下: 右键点击您的工程,选择 Properties 后选择 Java Build Path,在面板上点击 Libraries,通过 Add JARs... 将 libPluginProtocol.jar 引进游戏工程,如图:
注:游戏工程 API 最小支持 10
Cocos2d-x 命令编译的话,需要将 jar 包放在 libs 里(部分版本是放在 jars 里)。
配置 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" />
一般来说,即便不集成 AnySDK Framework,大部分的项目也都会注册申请这些权限。
初始化 AnySDK Framework
初始化 JavaVM
首先,要在游戏工程加载 jni 的时候为 AnySDK framework 设置 JavaVM 引用。先找到 JNI_OnLoad
函数,此函数是 jni 被加载时会首先被调用的函数。
以 Cocos2d-x 2.x 版本引擎为例,JNI_OnLoad
函数定义在 jni 目录下的 hellocpp/main.cpp 中,如下图所示:
1.导入头文件并声明命名空间
#include "PluginJniHelper.h"
using namespace anysdk::framework;
2.添加设置javaVM代码
PluginJniHelper::setJavaVM(vm);
若此处已有其他引擎初始化 JavaVM 的代码,保留其代码并在后面添加 PluginJniHelper::setJavaVM(vm);
即可。
以 Cocos2d-x 为例,设置如下
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/hellocpp/main.cpp)、3.3r0 之前版本(例如 3.2 在 cocos2d/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 "../../../../proj.android/protocols/android/PluginJniHelper.h"
。
在 JAVA 层初始化 AnySDK Framework 框架
1.首先找到游戏工程的主 Activity
,以 Cocos2d-x 引擎游戏为例,主 Activity
即是继承了 Cocos2dxActivity
的 Activity
。
2.然后在主 Activity
的 onCreate
方法中新增如下代码来初始化 AnySDK Framework:
import com.anysdk.framework.PluginWrapper;
public class MainActivity extends Activity {
protected void onCreate(Bundle savedState) {
super.onCreate(savedState);
PluginWrapper.init(this);
}
}
注:AnySDK 的回调函数默认是在主线程,使用 Cocos2d-x
的话,可以在 onCreate
加上 PluginWrapper.setGLSurfaceView(Cocos2dxGLSurfaceView.getInstance());
将回调改成在 GL 线程,不在 GL 线程里操作界面会有问题。
3.重写 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();
}
注:在 Cocos2d-x 3.0 之后的版本中集成 Cocos2dxActivity
之后已经不需要手动实现 Activity
里的生命周期方法,因此如果开发者发现主 Activity
没有这些方法,就需要自己去重写这个方法(直接拷贝上面的代码片段也可以)。且 super.onCreate(savedState);
请在 PluginWrapper.init(this);
之前调用,因为 init
的时候需要调用 C++ 函数,而 so 文件是在 onCreate
时加载。
在 C++ 层初始化AnySDK Framework 框架
在 C++ 层调用任何 AnySDK Framework 函数之前都需要调用 init 函数进行框架初始化,推荐在 Java 层初始化完成之后通知 C++ 层初始化框架,代码如下:
#include "AgentManager.h"
using namespace anysdk::framework;
std::string appKey = "BC26F841-OOOO-OOOO-OOOO-OOOOOOOOOOOO";
std::string appSecret = "1dff378a8f254ecOOOOOOOOOOOOO";
std::string privateKey = "696064B29E9A0OOOOOOOOOOOOO";
std::string oauthLoginServer = "http://oauth.anysdk.com/api/OauthLoginDemo/Login.php";
AgentManager::getInstance()->init(appKey,appSecret,privateKey,oauthLoginServer);
注:appKey、appSecret、privateKey 这三个参数是在 AnySDK 客户端创建游戏之后生成的游戏唯一参数,可以在 AnySDK 客户端 游戏管理 界面查看到,如下图:
而 oauthLoginServer
参数是游戏服务提供的用来做登陆验证转发的接口地址,在此处配置的接口地址仅用于 SIM SDK 测试模式下(即直接运行母包时)做登录时框架请求的地址,而在正式打出渠道包的时候会被替换成相应渠道在打包工具中配置的地址参数。
加载及卸载 SDK 插件
1.在初始化框架完成之后加载所有集成的sdk,代码如下:
AgentManager::getInstance()->loadAllPlugins(); // 对插件进行初始化,包括对各个 SDK 的初始化
注:由于部分 SDK 在初始化时涉及到 SDK 闪屏的操作强烈建议在 onCreate
就调用 loadAllPlugins
接口(新框架在 Java 层也提供了该接口)
import com.anysdk.framework.PluginWrapper;
public class MainActivity extends Activity{
protected void onCreate(Bundle savedState){
super.onCreate(savedState);
PluginWrapper.init(this);
PluginWrapper.loadAllPlugins();
}
2.卸载插件
当游戏不需要插件时,可进行卸载:
AgentManager::getInstance()->unloadAllPlugins(); //对插件进行卸载,需要卸载时可调用
代码混淆
如果要混淆 java 代码,请不要混淆联编的 jar 包中的类。可以添加以下类到 proguard 配置,排除在混淆之外:
-keep class com.anysdk.framework.** {*;}
-keep class com.anysdk.Util.SdkHttpListener {*;}
iOS 接入
参数示例: Sample_Cpp
获取 AnySDK Framework
为了集成 AnySDK Framework,请在 AnySDK客 户端的 安妮市场 里,选择 C++(iOS) 框架进行下载
下载后建议将框架拷贝到其他位置,由于下载文件夹带有空格(目前已去掉目录的空格),可能会导致工程库的搜索路径因为空格被分成两部分,导致编译错误
删除多余的 Targets
目前打包工具只支持单个 Target,若有多个 Targets 会导致打包出来的工程文件缺失,无法正常运行
可在目标上右键选择删除
如果有其他 Target 所需要用到的同名 .plist 文件,也需要删除,否则打包后工程 AnySDK 文件夹下可能会缺失 .plist 文件
若不想在原工程文件上操作,可以在同级目录下拷贝一份 .xcodeproj,并且打开其包内容,删除 xcuserdata 文件夹和 project.xcworkspace 下的 xcuserdata 文件夹,修改 /project.xcworkspace/contents.xcworkspacedata 文件中的 location 值,为改名后的文件名,再对拷贝后的工程文件进行操作。
将图标转为 Asset Catalog 形式
在母工程中需要将 Icon 转为 Asset Catalog 形式,否则可能导致打包后图标替换错误或者闪屏替换出现问题
若按钮为此样式,点击该 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文件夹要手动添加到项目中,按照第一种方式)
注:iOS 静态库说明: .a 文件的体积(46.8 M) = 真机用的 .a(28.1 M) + 模拟器用的 .a(18.7 M),当然每个 .a 文件还支持了不同架构:arm64 armv7 armv7s i386 x86_64。.a 文件只包含了代码的部分,静态库是在编译时链接二进制代码,对产生的二进制文件的大小并不会有太大的影响,目前 iOS 的 Sample 引入 AnySDK Framework 产生二进制文件也只有 1 M 的大小。
框架依赖库
libPluginProtocol 需要依赖以下这几个系统库
CFNetwork.framework
CoreFoundation.framework
MobileCoreServices.framework
SystemConfiguration.framework
libz.dylib(Xcode7:libz.tbd)
Security.framework
添加工程配置
打开项目工程配置,添加库的链接参数,在项目工程配置中,找到 Linking 中的 Linking Other Linker Flags,添加参数: -ObjC
注意:如果您使用的是 Cocos2d-x 引擎,在添加 -ObjC 后,可能会有编译报错,类似:
此时就要根据不同情况,来添加相应的类库。这里的这个报错,是需要添加库 MediaPlayer.framework 和 GameController.framework。
在项目中调用 AnySDK 的方法
在项目加载插件
在您项目的类(例:AppDelegate
来里面)里面。引用 头文件
#include "AgentManager.h"
例: 在
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
里面调用 AgentManager
,记得使用命名空间:
using namespace anysdk::framework;
//获取AgentManager
AgentManager* agent = AgentManager::getInstance();
std::string appKey = "Your APPKEY";
std::string appSecret = "Your APPSECRET";
std::string privateKey = "Your PRIVITEKEY";
std::string oauthLoginServer = "http://oauth.anysdk.com/api/OauthLoginDemo/Login.php";
//初始化agent
agent->init(appKey, appSecret, privateKey, oauthLoginServer);
//加载插件
agent->loadAllPlugins();
示例
注意不要在 .m 文件中调用 AnySDK 的 Framework
注意不要在 .m 文件中调用 AnySDK 的 Framework,需要修改成 .mm 文件。
Cocos2dx 2.2.x 集成注意事项
在修改 other linker flag(添加 -ObjC)和引入 AnySDK 的 Framewrok 之后,有可能会报类似 library not found lluajit 的错误。如图
需做如下修改:
此时在编译,会报类似 std::** 的错误,如图:
解决办法如图:
再次编译后,会报如下图的错误:
解决办法如图: