跳到主要内容

集成 SDK

集成须知

警告
  1. 新项目请直接使用 API v3
  2. OmniSDK 本身不会申请任何权限,权限一律由游戏或渠道 SDK 申请。
  3. OmniSDK 最低兼容 Android 版本为 Android 5.0(API Level 21)
  4. Unity 工程建议将和 OmniSDK 交互的代码放入到 launcher 模块

开始集成

导出中间工程

  1. 根据游戏引擎文档 导出 Gradle 工程结构 章节,导出 Android 工程结构(选择 AndroidX,如果有)。
  2. OmniSDK 目前最低支持 AGP 3.4.3 & Gradle 5.3.1,请确认引擎导出的 Gradle 版本号。
  3. 使用 Android Studio 打开导出的中间工程,根路径要有 settings.gradle 文件。
  4. 检查根路径下 gradle.properties 文件内 AndroidX 配置是否开启,如果没有则添加:
# AndroidX package structure to make it clearer which packages are bundled with the
# Android operating system, and which are packaged with your app"s APK
# https://developer.android.com/topic/libraries/support-library/androidx-rn
android.useAndroidX=true
# Automatically convert third-party libraries to use AndroidX
android.enableJetifier=true

GUI 工具配置

根据 GUI 工具指南 初始化 Android 工程配置。

提示

GUI 工具首次是必须使用的,需要通过 GUI 工具初始化 Android 工程所依赖的配置,后续可以通过命令行进行指令操作

Gradle 配置

警告
  • 注意高亮内容,同时注意写入顺序
  • rootProject.rootDir 直接复制,不需要替换

注册 classpath

root-level (根目录) 的 build.gradle,添加如下配置

buildscript {
repositories {
mavenCentral()
google()

// OmniSDK 仓库
apply from: ("${rootProject.rootDir}/kssyOmniBuildscriptRepositories.gradle")
// 如果有用到类似阿里的镜像库,需要放在最后
}
dependencies {
classpath 'com.android.tools.build:gradle:4.2.1'

// OmniSDK 相关的 classpath
apply from: ("${rootProject.rootDir}/kssyOmniBuildscriptDependencies.gradle")
}
}

allprojects {
repositories {
mavenCentral()
google()

// 如果有用到类似阿里的镜像库,需要放在最后
}
}

// OmniSDK 渠道仓库
apply from: ("${rootProject.rootDir}/kssyOmniChannelsRoot.gradle")

声明 OmniSDK 依赖

提示

app-level: Unity 导出 Android 工程的 launcher 目录

app-level 的 build.gradle (注册了 apply plugin: 'com.android.application' ),添加如下配置:

apply plugin: 'com.android.application' 

// 声明 KSSYOmniPlugin
apply from: ("${rootProject.rootDir}/kssyOmniPlugin.gradle")

// 声明 OmniSDK 依赖
apply from: ("${rootProject.rootDir}/kssyOmniChannelsApp.gradle")

// 在需要使用 OmniSDK API 代码的 Module 声明kssyOmniChannels.gradle。
// 声明 渠道 依赖
apply from: ("${rootProject.rootDir}/kssyOmniChannels.gradle")

// 签名配置,为保证安全,密钥密码不要明文配置在这里,而是通过文件读取方式配置。比如 signing.properties
def signingPro = new Properties()
signingPro.load(new FileInputStream(file(rootProject.file("signing.properties"))))

// 签名变量,注意这里加 ext. 以便全局可以引用到
ext.signing_keystoreFile = file("${rootProject.rootDir}/${signingPro["storeFilePath"]}")
ext.signing_keystorePassword = signingPro["storePassword"]
ext.signing_keyAlias = signingPro["keyAlias"]
ext.signing_keyPassword = signingPro["keyPassword"]

android {
compileSdkVersion 31 // 这里因部分Android官方依赖库要求最低 31
// buildToolsVersion 如果引擎导出有此配置请直接注释删除,由 compileSdkVersion 控制

defaultConfig {
// applicationId "游戏包名" // 本行删除,不要自己配置,编译脚本会自动读取 project_config.json#package_name。
// 包名必须 project_config.json#package_name、OmniSDK后台、相关第三方SDK后台,保持一致;
// 变更包名时需要同步所有地方的包名及相应申请的参数。
minSdkVersion 21 // 最低版本仅支持21
targetSdkVersion 28 // 国内最低28,海外最低31,渠道指定版本由OmniSDK编译插件处理。

versionCode 1
versionName "1.0"

ndk {
abiFilters "arm64-v8a" // 64位适配,扩展阅读:https://docs.seayoo.com/sdk/package/android/build-gui#arm64-config
}
}

// 开启 Java8 兼容性编译(必选)(不得低于8,除非游戏引擎要求更高版本)
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}

signingConfigs {
release {
storeFile signing_keystoreFile
storePassword signing_keystorePassword
keyAlias signing_keyAlias
keyPassword signing_keyPassword
}
}

buildTypes {
release {
minifyEnabled true // 开启代码混淆:保护代码、减少包大小
// multiDexKeepProguard = file("multidex-config.pro") // 分包配置,如果需要
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.release // release签名(引用kssyOmniSigning.gradle时需要注释掉)
}
}
}

dependencies {
implementation(project(":library"))
}

在需要使用 OmniSDK API 的模块内可以声明 kssyOmniChannels.gradle

apply plugin: 'com.android.library' 

// 在需要使用 OmniSDK API 代码的 Module 声明kssyOmniChannels.gradle。
// 声明 渠道 依赖
apply from: ("${rootProject.rootDir}/kssyOmniChannels.gradle")

同步依赖【同步Gradle依赖-的几种操作方法】

签名配置

  1. 查看文件 kssyOmniSigning.gradle,如果有接入需要 v1 签名渠道,则按下面的方法配置处理。
  2. 即没有接入 v1 签名渠道,也可以按下面的方法处理。
  3. 这样出包时,自动根据渠道要求使用对应签名版本,不需要再手动签名。
  • app-level 的 build.gradle (注册了 apply plugin: 'com.android.application' ),添加如下配置:
// 要完成上面步骤的配置后

android {
buildTypes {
release {
...
// signingConfig signingConfigs.release // 注释掉这行,其他不变,签名版本由 kssyOmniSigning.gradle 配置控制
}
}
}

// 注意这行的顺序,是在 android{} 下方声明
apply from: ("${rootProject.rootDir}/kssyOmniSigning.gradle")

Application 接入

OmniSDK 支持两种方式接入 Application

  • 游戏侧没有自定义的 Application,则需要创建 GameApplication.java 并继承 OmniApplication
  • 游戏侧有自定义的 Application,但继承的基类是 android.app.Application,或者游戏接入的渠道包含特殊渠道,可将继承的基类直接改为 OmniApplication
import com.kingsoft.shiyou.omnisdk.api.OmniApplication;

public class GameApplication extends OmniApplication {
@Override
public void attachBaseContext(Context base) {
super.attachBaseContext(base);
......
}
}

如果游戏的 Application 继承了其它 SDK 的 Application 类,则不能直接继承 OmniApplication,需要在其中添加如下代码:

Show Code
@Override
public void attachBaseContext(Context context) {
super.attachBaseContext(context);
MultiDex.install(context); // 64k方法数
OmniSDKv3.getInstance().onApplicationAttachBaseContext(context);
}

@Override
public void onCreate() {
super.onCreate();
OmniSDKv3.getInstance().onApplicationCreate(context);
}

@Override
public void onLowMemory() {
super.onLowMemory();
OmniSDKv3.getInstance().onApplicationLowMemory();
}

@Override
public void onTrimMemory(int level) {
super.onTrimMemory(level);
OmniSDKv3.getInstance().onApplicationTrimMemory();
}

@Override
public void onTerminate() {
super.onTerminate();
OmniSDKv3.getInstance().onApplicationTerminate();
}

特殊渠道列表

渠道名渠道唯一标识
魅拓meituo
海南澎湃互动pphd
多酷duoku
MuMuyofun
游戏狗gamedog
汇智huizhi
熊猫侠xmxia

AndroidManifest

提示
  • android:name 需要替换为游戏的 Application (如 GameApplication)
  • android:icon="@mipmap/omni_ic_launcher" 不同的渠道会有不同的 icon,所以设置为 omni_ic_launcher 作为动态替换的标记位
  • 添加 tools:replace 元素、并为其设置属性
<application
android:name="[YOUR_PACKAGE_PATH].GameApplication"
android:icon="@mipmap/omni_ic_launcher"
android:label="@string/app_name"
tools:replace="android:icon,android:label,android:theme,android:allowBackup">
...

<activity
android:name="[YOUR_PACKAGE_PATH].GameActivity"
android:configChanges="keyboard|keyboardHidden|screenLayout|screenSize|orientation"
android:exported="true"
android:screenOrientation="sensor"
android:theme="@style/Theme.GameActivity.Fullscreen">

<intent-filter>
<!-- 主Activity即启动Activity,需要至少声明这两个属性 -->
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

GameActivity 接入

提示

如果游戏侧有依赖第三方的 SDK,同时也已经过修改 Activity,推荐使用 方式二

需要修改 Android 工程的 Activity,一般是由游戏引擎生成 GameActivityUnityPlayerActivity,需要手动修改将继承的基类变更为 OmniSdkActivity

public class GameActivity extends OmniSdkActivity {}



public class UnityPlayerActivity extends OmniSdkActivity {}

游戏侧已经创建好了 Activity,那只需要在该类中添加 OmniSDK 的生命周期方法,即 OmniSdkActivity 里所有的方法

Show Code
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.util.Log;

import com.unity3d.player.UnityPlayerActivity;
import com.kingsoft.shiyou.omnisdk.api.OmniApplication;

public class GameActivity extends UnityPlayerActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
OmniSDKv3.getInstance().onCreate(this, savedInstanceState);
}

@Override
protected void onNewIntent(Intent intent)
{
super.onNewIntent(intent);
OmniSDKv3.getInstance().onNewIntent(this, intent);
}

@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
OmniSDKv3.getInstance().onSaveInstanceState(this, outState);
}

@Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
OmniSDKv3.getInstance().onRestoreInstanceState(this, savedInstanceState);
}

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

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
OmniSDKv3.getInstance().onRequestPermissionsResult(this, requestCode, permissions, grantResults);
}

@Override
public void onBackPressed() {
super.onBackPressed();
OmniSDKv3.getInstance().onBackPressed(this);
}

@Override
protected void onDestroy ()
{
super.onDestroy();
OmniSDKv3.getInstance().onDestroy(this);
}

@Override
protected void onStart()
{
super.onStart();
OmniSDKv3.getInstance().onStart(this);
}

@Override
protected void onPause()
{
super.onPause();
OmniSDKv3.getInstance().onPause(this);
}

@Override
protected void onResume()
{
super.onResume();
OmniSDKv3.getInstance().onResume(this);
}

@Override
protected void onRestart() {
super.onStart();
OmniSDKv3.getInstance().onRestart(this);
}

@Override
protected void onStop() {
super.onStop();
OmniSDKv3.getInstance().onStop(this);
}

@Override
public void onLowMemory()
{
super.onLowMemory();
}

@Override
public void onTrimMemory(int level)
{
super.onTrimMemory(level);
}

@Override
public void onConfigurationChanged(Configuration newConfig)
{
super.onConfigurationChanged(newConfig);
OmniSDKv3.getInstance().onConfigurationChanged(this, newConfig);
}

@Override
public void onWindowFocusChanged(boolean hasFocus)
{
super.onWindowFocusChanged(hasFocus);
}

@Override
public boolean dispatchKeyEvent(KeyEvent event)
{
return super.dispatchKeyEvent(event);
}

@Override
public boolean onKeyUp(int keyCode, KeyEvent event)
{
return super.onKeyUp(keyCode, event);
}

@Override
public boolean onKeyDown(int keyCode, KeyEvent event)
{
if (OmniSDKv3.getInstance().onKeyDown(this, keyCode, event)) {
return true;
} else {
return super.onKeyDown(
keyCode,
event
);
}
}

@Override
public boolean onTouchEvent(MotionEvent event)
{
return super.onTouchEvent(event);
}
}

混淆配置

混淆说明

OmniSDK 及各渠道的混淆配置,集成在依赖包内,游戏无需额外配置。

64k 方法数分包需要游戏自身配置,请参考multidex-config.pro 下载

开启行号

开启 proguard-rules.pro 行号配置,方便准确定位问题代码。

# Uncomment this to preserve the line number information for
# debugging stack traces.
-keepattributes SourceFile,LineNumberTable

# If you keep the line number information, uncomment this to
# hide the original source file name.
-renamesourcefileattribute SourceFile

游戏运行时混淆问题

如果 Debug 包 没有问题,Release 包 编译无问题,但是运行时有问题,通常是混淆原因。

如果游戏有接入其他第三方 SDK,请根据其接入文档增加对应的混淆配置。

线程

提示
  • OmniSDK 对线程的调用无要求,游戏调用接口时无需开启新线程
  • 回调时,无需额外切换线程

自动化

Unity

可以使用 Unity 的 Post Build 机制去 Setup Android 工程,可以避免因更换机器或者清理 Workspace 导致需要重新配置

警告

当 OmniSDK 有 BREAKING CHANGES,可能需要通过 GUI 重新初始化配置

Step 1

需要通过 GUI 工具 完成工程的初始化,会获取如下配置文件

img

Step 2

可以将初始化完成后的文件放置于 Unity 项目的某个位置,通过 Unity Post Build 机制可以将文件拷贝到 Android Workspace

Examples

示例: 文件存放在 NativeAssets/Android 目录内

img

AndroidPostBuildProcessor.cs

class AndroidPostBuildProcessor : IPostGenerateGradleAndroidProject
{
public int callbackOrder { get { return 0; } }

public void OnPostGenerateGradleAndroidProject(string path)
{
var rootPath = GetRootPath();

var nativeAssetsPath = Path.Combine(rootPath, "NativeAssets", "Android");
Debug.Log(nativeAssetsPath);

var targetPath = GetOutputPath(path);

CopyDirectory(nativeAssetsPath, targetPath);
}

private static string GetRootPath()
{
string projectRootPath = Path.GetFullPath(Application.dataPath);
return Path.GetDirectoryName(projectRootPath);
}

private static string GetOutputPath(string path)
{
return Path.GetDirectoryName(path);
}

public static void CopyDirectory(string sourceDirectory, string targetDirectory)
{
DirectoryInfo diSource = new DirectoryInfo(sourceDirectory);
DirectoryInfo diTarget = new DirectoryInfo(targetDirectory);

CopyAll(diSource, diTarget);
}

public static void CopyAll(DirectoryInfo source, DirectoryInfo target)
{
Directory.CreateDirectory(target.FullName);

// Copy each file into the new directory.
foreach (FileInfo fi in source.GetFiles())
{
fi.CopyTo(Path.Combine(target.FullName, fi.Name), true);
}

// Copy each subdirectory using recursion.
foreach (DirectoryInfo diSourceSubDir in source.GetDirectories())
{
DirectoryInfo nextTargetSubDir =
target.CreateSubdirectory(diSourceSubDir.Name);
CopyAll(diSourceSubDir, nextTargetSubDir);
}
}
}

Step 3

后续可通过命令行 自助出包