Cocos2d - 接入 Android 原生广告、统计SDK.

4,336 阅读17分钟

一、本文环境.

1. 电脑: Mac mini (Late 2014).

2. 系统: Mac OS X 10.15.1

3. 开发工具:

  • Cocos Creator 2.2.1(当下最新的稳定版本,Cocos2d游戏开发工具).
  • Visual Studio Code 1.40.2(简称: VSCode,很好用的代码编辑器,搭配Creator进行代码编辑).
  • Android Studio 3.5.2(Android 原生开发工具,NDK-r17.2 应 Cocos 文档说明 2.0.9 以下不能安装r18 以上的版本).

4. 本次对接的广告是 穿山甲(v2.5.2.6), 头条-巨量引擎(v3.3.12)腾讯联盟(广点通)(v4.10.19) 两家的.

5. 本次对接的统计是 友盟统计(v8.1.4).

6. 介绍手动打包和使用 Fastlane 工具进行自动化打包.

二、环境安装.

注:会安装环境的,或已经安装好环境的可以直接跳过查看 下一点 - 对接SDK.

安装 Android Studio,由于 Cocos Creator 不同的版本对 Android 环境有不同的要求,所以请移步 Cocos 文档-安装配置原生开发环境 根据文档说明一步步下载安装配置。文档说的很详细,这边就不再说明了.

  • 注意:修改右上方的 Version: 2.0,改成跟你的版本对应的版本文档,因为版本不一样,要求很可能也不一样.

Cocos 文档-安装配置原生开发环境

三、导出 Android 项目工程(会的可以跳过).

1. 安装好 Android 开发环境后,在 Creator 上打开对应的项目,然后在 Creator偏好设置 -> 原生开发环境 面板设置 NDKAndroid SDK 的路径.

偏好设置 -> 原生开发环境
只有设置完了这两个路径,才能正常完好的导出 Android 项目工程.

2. 设置完之后,选择 项目 -> 构建发布(Mac快捷键 Common + Shift + B) 打开构建面板.

  • 发布平台选择 Android.
  • 模板选择 link.
  • 填入 Android 的包名(一般为三级: com.xxxx.xxxxx).
  • Target API Level 这个大概是一个API 等级,选择一个.
  • APP ABI 为项目架构,如果要在模拟器上运行,一定要勾起 x86。 如果要在真机上运行,要把上面两个 arm 勾起来(别问为什么,勾起来就对了).
  • 设备方向选择游戏对应的方向,依次是正方向竖屏、反方向竖屏、左横屏、右横屏.
  • 取消勾选加密脚本,方便调试,而且在 Android 上也可以进行项目混淆加密,当然,如果是为了发布,不需要调试,可以勾选.
  • 其他保持默认的就行,不要去乱动,不然报错了不给你 报销 .
  • 上面的设置完毕之后,点击构建,构建导入 Android 项目.
    项目 -> 构建发布
    当构建完成之后,可以在 项目/build/jsb-link/frameworks/runtime-src/ 目录下看到我们导出的工程。
    导出的 Android 工程目录
    可以看到除了 Android 工程之外,连 iOS、Mac、Windows 的项目工程也帮我们一起导出了.

3. 导出工程后,先不急着对接,用 Android Studio 打开运行,确定导出的项目工程可以正常运行,没有任何问题后,再继续看下面的 对接SDK.

注: 不会用 Android Studio 打开项目的自行百度,也不难,我就不在一步步说明了.

导出之后,如果运行报错,可以尝试修改 build.gradle 里面几个版本配置的值.

默认情况如下:

修改 SDK 相关的值.
如果版本没改对,可能会报这个错误
报错.
根据提示,继续修改,下面是我修改之后,能运行的版本.
能运行的版本.

如果报下面这个错误的,解决方案: 添加录音权限.

报错-录音权限
大致就是在 app 目录下的 AndroidManifest.xml 文件内 添加下面这句权限代码.

<uses-permission android:name="android.permission.RECORD_AUDIO"/>

添加录音权限

四、 对接 穿山甲广告SDK - 对接文档.

1. 下载 穿山甲 Android SDK ,下载下来的是一个包含 SDK 和 Demo 的压缩包,双击解压缩.

下载 穿山甲 Android SDK
解压缩后的目录

2. 解压缩之后,回到项目,在 app 目录下 新建 libs 文件夹 ,然后把 open_ad_sdk.aar 复制到 libs 目录下.

导入项目
在 Android 工程中查看

3. 然后,打开 app/build.gradle 滚动到文件底部在 depedencies 内添加下面这句代码.

implementation 'pl.droidsonroids.gif:android-gif-drawable:1.2.6'

添加完,点击右上方的 Sync Now 同步一下,然后运行一下项目,保证不报错,再进行下一步.

depedencies
如果报错:Error:Execution failed for task':app:transformDexArchiveWithExternalLibsDexMergerForDebug'
大意是资源重复了。这个错误我弄了大半天,最后还是求助我一个做 Android 的朋友远程帮我解决的(他只用了小半个小时就搞定了,大佬就是大佬).
解决方案,大致就是在 app/build.gradle 文件的 android 添加下面这句代码. 添加完别忘了 Sync Now.

multiDexEnabled true

解决-资源重复

4. 确认 SDK 导入没有问题后,开始进行配置,首先是添加权限,可以根据项目自身情况在 AndroidManifest.xml 文件内添加相关的权限.

<!-- 获取网络权限. -->
<uses-permission android:name="android.permission.INTERNET"/>
<!-- 获取网络信息状态权限. -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<!-- 获取 Wi-Fi 信息状态权限. -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>

<!-- 上边三个默认帮我们配置好了,我们需要添加以下的权限. -->

<!-- 可选权限. -->
<!-- 获取电话状态权限(敏感权限,上架 Google pay 可能会被拒绝,可以去掉,不影响使用). -->
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<!-- 允许程序写入外部存储权限. -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<!-- 通过WiFi或移动基站的方式获取用户错略的经纬度信息. -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<!-- 请求安装包权限. -->
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
<!-- 允许程序获取当前或最近运行的应用. -->
<uses-permission android:name="android.permission.GET_TASKS"/>
<!-- 可选,通过GPS芯片接收卫星的定位信息,穿山甲将依据此权限投放精准广告. -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<!-- 如果有视频相关的广告且使用textureView播放,请务必添加,否则黑屏. -->
<!-- 允许程序在手机屏幕关闭后后台进程仍然运行. -->
<uses-permission android:name="android.permission.WAKE_LOCK"/>

<!-- 运行环境配置(运行于 Android4.0 (API Level 14) 及以上版本). -->
<!-- <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="24"/> -->

5. 添加完权限之后,在 <Application> 标签内添加以下代码.

<provider
    android:name="com.bytedance.sdk.openadsdk.TTFileProvider"
    android:authorities="${applicationId}.TTFileProvider"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/file_paths" />
</provider>
<provider
    android:name="com.bytedance.sdk.openadsdk.multipro.TTMultiProvider"
    android:authorities="${applicationId}.TTMultiProvider"
    android:exported="false" />

6. 然后在 app/res 目录下添加 xml 文件夹,并在 xml 文件夹内新建 file_paths.xml.

新建 file_paths.xml

7. 创建完替换文件内容为以下内容.

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <!--为了适配所有路径可以设置 path = "." -->
    <external-files-path name="external_files_path" path="." />
</paths>

8. 然后,为了适配下载和安装相关功能,回到 app/build.gradle 文件,在 dependencies 内添加

implementation 'com.android.support:support-v4:23.0.0'

如果项目还有需要别的权限,可以看 这篇文章 添加对应的权限.
慎重起见,每做完一个步骤,需要运行一下项目,确认没有问题后,再进行下一步操作(后面不再提示)!
这边真机运行可能会报下面这个错误(模拟器太卡没有开...),那么,你很可能是跟我一样,手贱不知道改了什么,这时候,我推荐你删掉重来吧,反正我是这么解决的!

异常报错
到这里,SDK的配置就完成了。接下来初始化SDK后就可以开始接入各种广告了.

9. 初始化SDK需要在 穿山甲后台 注册账号,注册应用,拿到 AppID ;后续的广告位也是要在这边创建,然后拿到广告代码位,项目里的广告才能正常显示!不懂的这边有教程: 注册认证流程.

穿山甲-流量管理


广告代码位
注册完应用,就可以在项目里面初始化SDK了.

10. 在 res/org.cocos2dx.javescript/AppActivityonCreate 方法内添加下面的初始化代码(替换 appIDappName).

// 请求权限.
TTAdSdk.getAdManager().requestPermissionIfNecessary(this);

// appId 应用ID.
// useTextureView 使用 TextureView 控件播放视频, 默认为 SurfaceView, 当有 SurfaceView 冲突的场景,可以使用 TextureView.
// allowShowNotify 是否允许 SDK 展示通知栏提示.// allowShowPageWhenScreenLock 是否在锁屏场景支持展示广告落地页.
// debug 测试阶段打开,可以通过日志排查问题,上线时去除该调用.// directDownloadNetworkType 允许直接下载的网络状态集合.
// supportMultiProcess是否支持多进程,true支持.
TTAdConfig config = new TTAdConfig.Builder()
    .appId("5001121")
    .useTextureView(false)
    .appName("APP测试媒体")
    .titleBarTheme(TTAdConstant.TITLE_BAR_THEME_DARK)
    .allowShowNotify(true)
    .allowShowPageWhenScreenLock(true)
    .debug(debug)
    .directDownloadNetworkType(TTAdConstant.NETWORK_STATE_WIFI, TTAdConstant.NETWORK_STATE_3G)
    .supportMultiProcess(false)
    .build();

// 初始化穿山甲SDK.
TTAdSdk.init(this, config);

当在控制台看见下面的 log 信息时,就代表初始化成功,可以开始接入具体广告了.

初始化成功
限于篇幅,穿山甲广告 SDK 接入的介绍就到此为止了!
后面就是一些具体的广告组件了,对着官方的 接入文档 拷贝代码就行了,没有太大的难度,毕竟我这个完全不会安卓的都接完了(代码质量请忽略).
我是将穿山甲 SDK 的广告组件等的实现代码封装成了工具类,方便公司内部同事使用;由于是内部使用代码,这边就不公开了!下面是我封装过程中遇到的一些问题的解决方案:
JsonObject 解析值为 null.
Android 中获取当前正在显示的 Activity 实例.
Android 在布局中动态添加 view 的两种方法.
Android 控件 view 的可见,不可见,隐藏的设置和区别.
Android 获取控件宽高和屏幕宽高.
Android中实现延时执行操作的几种方法.

五、对接 头条-巨量引擎 - 对接文档.

1. 导入SDK.

1.1 这边采取手动引入的方式,因为远端引入的方式这边报错了,首先下载SDK文件: 下载地址.

SDK下载页
解压缩之后的目录
1.2 将解压缩出来的 RangersAppLog-Lite-cn-3.3.12.aar 文件拷贝到 项目/app/libs/ 目录下.
拷贝 .aar 文件
1.3 打开项目文件夹下的 build.gradle,确保 repositories 中包含 jcenter()
jcenter()

2. 导入SDK后,可以开始初始化SDK了!

ApplicationonCreate 中初始化 RangersAppLog (初始化需要尽可能早)

提示: SDK默认支持多进程初始化.

/* 初始化开始. */
// appid和渠道,appid须保证与广告后台申请记录一致.
// 渠道可自定义,如有多个马甲包建议设置渠道号唯一标识一个马甲包.
final InitConfig config = new InitConfig("App ID", "Channel");
/**
 * 域名默认国内: DEFAULT, 新加坡:SINGAPORE, 美东:AMERICA.
 * 注意:国内外不同vendor服务注册的did不一样。由DEFAULT切换到SINGAPORE或者AMERICA,会发生变化.
 * 切回来也会发生变化。因此vendor的切换一定要慎重,随意切换导致用户新增和统计的问题,需要自行评估.
 */
config.setUriConfig(UriConfig.DEFAULT);
// 是否在控制台输出日志,可用于观察用户行为日志上报情况,建议仅在调试时使用,release版本请设置为false.
AppLog.setEnableLog(true);

// 设置 AppName 与在后台申请 AppID 时填的名称一样.
config.setAppName("App Name");
// 游戏模式,YES会开始 playSession 上报,每隔一分钟上报心跳日志.
config.setEnablePlay(true);
// 是否在控制台输出日志,可用于观察用户行为日志上报情况,建议仅在调试时使用,release版本请设置为false.
AppLog.setEnableLog(true);
// 日志加密,release 版本请设置为 true.
AppLog.setEncryptAndCompress(true);
// 调用初始化函数.
AppLog.init(this, config);
/* 初始化结束. */
// 自定义 “用户公共属性”(可选,初始化后调用, key相同会覆盖).
Map<String,Object> headerMap = new HashMap<String, Object>();
headerMap.put("level", 8);
headerMap.put("gender", "female");
AppLog.setHeaderInfo((HashMap<String, Object>)headerMap);

3. 初始化完成后,就是上报埋点的 API 调用了, 比较简单, 这边就不做说明了, 结合自身情况接入即可! 没有什么难度, 基本就是拷贝粘贴代码! 请参照: 文档 -> Android 端 SDK 使用说明.

六、 对接 友盟统计SDK - 对接文档.

1. 导入 SDK,由于官方支持 自动集成(推荐) 和 手动集成 两种方式;我这边选择 自动集成 方式,避免了手动下载 SDK 导入项目工程的麻烦。如果你要 手动集成 可以打开的 对接文档-手动集成 照着文档操作即可.

1.1 在工程 build.gradle 配置脚本中 buildscriptallprojects 段中添加【友盟+】SDK 新 maven 仓库地址,添加完记得点击 Sync Now 同步.
maven { url 'https://dl.bintray.com/umsdk/release' }

添加 maven 仓库地址

1.2 同步完之后,在工程 App 对应 build.gradle 配置脚本 dependencies 段中添加 基础组件库和 统计 SDK 库依赖!同样的添加完记得点击 Sync Now 同步.
implementation 'com.umeng.umsdk:analytics:8.1.4'
implementation 'com.umeng.umsdk:common:2.1.8'

注意:这边是在 app 目录下,不是上边那个项目工程的!文件名一样,容易搞混.

添加 基础组件库和 统计 SDK 库依赖
上边配置完之后,文档需要我们在 AndroidManifest.xml 添加以下几个必要和可选的权限。而我们上边在穿山甲那边已经添加过大部分的权限了,这里需要我们再添加的只有一个

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<!-- 必要的权限. -->
<!-- 检测联网方式,在网络异常状态下避免数据发送,节省流量和电量. -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<!-- 获取用户设备的 IMEI,通过 IMEI 对用户进行唯一标识,以便提供统计分析服务. -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<!-- 获取 WIFI mac 地址,在平板设备或电视盒子上,无法通过 IMEI 标识设备,我们会将 WIFI mac 地址作为用户的唯一标识,以便正常提供统计分析服务. -->
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<!-- 允许应用程序联网和发送统计数据的权限,以便提供统计分析服务. --><uses-permission android:name="android.permission.INTERNET"/>

<!-- 可选的权限. -->
<!-- 为开发者提供反作弊功能,剔除作弊设备,让统计数据(如新增用户数)更加准确. -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<!-- 为开发者提供反作弊功能,剔除作弊设备,让统计数据(如新增用户数)更加准确. -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<!-- 通过获取位置信息,为开发者提供反作弊功能,剔除作弊设备;同时校正用户的地域分布数据,使报表数据更加准确. -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<!-- 通过获取位置信息,为开发者提供反作弊功能,剔除作弊设备;同时校正用户的地域分布数据,使报表数据更加准确. -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>

添加权限

2. 添加完权限就可以开始初始化 SDK 了,在 app/src/ 下的 AppActivityonCreate 方法内添加初始化代码.

/**
 * context 上下文环境(this).
 * appkey 在友盟后台创建App后得到的应用唯一标识符.
 * channel 渠道字符串,不要用中文.
 * deviceType 设备类型,UMConfigure.DEVICE_TYPE_PHONE 为手机、UMConfigure.DEVICE_TYPE_BOX 为盒子,默认为手机.
 * pushSecret 推送业务的 secret,需要集成 Push 功能时必须传入 Push 的 secret,否则传空.
 */
UMConfigure.init(this, "appkey", "channel", UMConfigure.DEVICE_TYPE_PHONE, null);
// 使用 MANUAL 页面采集模式.
MobclickAgent.setPageCollectionMode(MobclickAgent.PageMode.MANUAL);
// 支持在子进程中统计自定义事件.
UMConfigure.setProcessEvent(true);

3. 设置 log 日志打印开关,如果想要查看初始化过程中的 log,一定要在调用初始化方法前将 log 开关打开.

UMConfigure.setLogEnabled(true);

4. Session启动、App使用时长等基础数据统计接口API.\

App 中每个 ActivityonResume 方法中调用 MobclickAgent.onResume(context), onPause 方法中调用 MobclickAgent.onPause(context).

@Override
public void onResume() {
    super.onResume();
    MobclickAgent.onResume(this);
}

@Override
public void onPause() {
    super.onPause();
    MobclickAgent.onPause(this);
}

5. 发送自定义事件,比较麻烦的就是需要在应用后台创建统计事件,拿到 事件ID(eventId) !只有在后台创建的事件才会统计.

/**
 * 发送自定义事件.
 * @param context 上下文.
 * @param eventId 事件ID.
 * @param name 事件名称.
 */
MobclickAgent.onEvent(context, eventId, name);

6. 发送自定义事件 - 自定义参数.

/**
 * 发送自定义事件.
 * @param context 上下文.
 * @param eventId 事件ID.
 * @param map 自定义参数.
 */
MobclickAgent.onEventObject(activity, eventId, map);

7. 发送自定义事件 - 自定义计数.

/**
 * 发送自定义事件.
 * @param context 上下文.
 * @param eventId 事件ID.
 * @param map 自定义参数.
 * @param count 自定义计数.
 */
MobclickAgent.onEventObject(activity, eventId, map, count);

统计使用到的内容不多,到此就结束了.

七、对接 腾讯联盟(广点通) - 接入文档.

  • 因为最近工作繁忙,腾讯联盟(广点通) 部分暂时没空整理!后续空出时间了会再更新!

八、打包导出 APK.

当要接的 SDK 都接完之后,就是打包 APK 了!

1. 选择工具栏的 Build -> Generate Signed Bundle / APK, 打开 Generate Signed Bundle / APK 面板.

打开编译签名面板.

2. 选择 APK,然后点击 Next 按钮进入下一步.

APK -> Next.

3. 接着进入签名密钥信息界面.

密钥信息.
因为是第一次打包,没有密钥文件,所以先点击 Create new... 按钮进入创建面板创建一个密钥文件.

4. 进入 New Key Store 面板.

  • Key store path: 密钥文件的导出路径,点击后面的文件夹图标选择存放路径.
  • Password: 文件密码.
  • Confirm: 确认密码.
  • Alias: 别名(无特殊要求,保持默认即可).
  • Password && Confirm: 密码,最好跟上面的密码一致.
  • Validity(years): 密钥文件的有效年限.
  • Certificate Info: 证书信息,可以不填.
  • 填完信息点击 OK 按钮生成密钥文件.

这边的密码可以设置的简单好记一点,以后还会用到!比如:123456

New Key Store 面板.
迁移 PKCS12.
点击 OK 按钮之后,可能会报这个错误,根据提示运行命令行即可.

  • 打开命令行界面,输入以下命令:
keytool -importkeystore -srckeystore 原文件路径 -destkeystore 导出文件路径 -deststoretype pkcs12
  • 原文件路径与导出文件路径可以是同一个,会自动帮我们生成一个 .old 的备份文件.
  • 输完命令回车之后,要求输入密钥文件的密码(就是上面生成文件时输入的密码), 输完密码出现以下输出就成功迁移到 PKCS12 了.
    命令行.

5. 生成完密钥文件会自动回到上一个 签名密钥信息 界面.

  • 可以看到自动帮我们填完了相关信息,直接点击 Next 按钮进入下一步骤即可.
    密钥信息.

6. 下一步后进入编译面板,选择完相关选项之后,点击 Finish 按钮,之后会自动关闭这个弹出面板, 进入打包状态,然后等就行了.

编译面板.

7. 可以在 app/build.gradle 文件末尾加入以下代码修改导出的 APK 文件名.

def releaseTime() {
    // GMT+8是因为北京时间和GMT有8个小时时差.
    return new Date().format("yyyy-MM-dd HHMM", TimeZone.getTimeZone("GMT+8"))
}
android.applicationVariants.all {
    variant ->
        variant.outputs.all {
            // 这里修改apk文件名.
            def fileName = "package_v${variant.versionName}_${variant.name}_${releaseTime()}.apk"
            outputFileName = fileName
        }
}

打包成功.
release 目录.
打包成功后,就可以在导出的目录内看到 release 文件夹, 进入 release 就可以看到导出的 APK 了.

8. 前面打包一直报错 java.io.IOException: Please correct the above warnings first.,百度找了很多资料都不对,最后请教了一下大佬才解决.

打包报错.
Android编译运行项目时报错 java.io.IOException: Please correct the above warnings first.

就是在 app/proguard-rules.pro 文件内加入以下代码忽略警告:

-ignorewarnings

proguard-rules.pro

9. 使用 Fastlane 打包.

没有听过或用过 Fastlane 这个工具的,可以看 这篇文章 了解,或自行百度也行,网上关于 Fastlane 的介绍还是很多的.

总的来说, Fastlane 就是一个自动化打包的命令行工具, 只要配置好项目, 一句命令行就能帮你做好签名、编译、导出、上传等的事情, 不用每次打包都需要你一步步手动操作的一个工具.

然而,Fastlane 对 Android 平台支持有限;Fastlane 更适用于 iOS!Android 只适合上传到 Google Play。

用法参考资料:
Fastlane 官方文档 - Android.
fastlane 实现 Android 自动化打包.
Fastlane Actions - gradle.
Fastlane Actions - build_android_app.

Fastfile:

  • 其中签名文件需要在项目 根目录 和 app 目录下都放一个,否则会报错.
default_platform(:android)

platform :android do

  lane :product do
    puts "=====> 开始打包 APK."
    gradle(task: "clean")
    gradle(
        task: "assemble",
        build_type: "Release",
        properties: {
            "android.injected.signing.store.file" => "签名文件.",
            "android.injected.signing.store.password" => "文件密码.",
            "android.injected.signing.key.alias" => "别名.",
            "android.injected.signing.key.password" => "别名密码.",
        }
    )
  end

end

配置完,终端执行以下命令,然后等待执行完成即可.

fastlane product

命令执行完成.
如果没有配置错误,应能看见 fastlane.tools finished successfully 🎉 就代表命令执行完成,并且打包成功! 而且上面也显示了执行总时长与各 Action 的执行时长.

之后就可以在项目的 app/build/outputs/apk/release 目录下看到我们导出的 APK 安装包了.

Android Studio.
Finder.