安装与配置
下载并安装插件
下载方式:
导入至 Cocos Create 项目:
打开 Extension Manger (Extension -> Extension Manager)
- 目录导入: `Import Extension Folder`
- ZIP包导入:`Import Extension File`
进入项目插件目录:
{PROJECT_ROOT}/extension/athana-cocos
编译插件
1 2 3
| # 执行命令 npm install npm run build
|
设置插件
打开配置面板:
Android 平台:Project -> Build -> New Build Task -> 创建 Android 构建配置 -> Build
iOS 平台:Project -> Build -> New Build Task -> 创建 iOS 构建配置 -> Build
填选相应的项:

构建配置
Android Studio 项目配置
编辑 Gradle 构建脚本
修改 {COCOS_PROJECT}/build/{ANDROID_STUDIO_PROJECT}/proj/build.gradle
1 2 3 4 5 6 7 8 9 10 11
| buildscript {
... dependencies { classpath 'com.android.tools.build:gradle:<AGP_VERSION>'
... } }
...
|
修改 {COCOS_PROJECT}/build/{ANDROID_STUDIO_PROJECT}/proj/gradle/wrapper/gradle-wrapper.properties
1 2 3 4
| ...
distributionUrl=https\://services.gradle.org/distributions/gradle-<GRADLE_VERSION>-bin.zip ...
|
配置 Kotlin 运行环境
修改 {COCOS_PROJECT}/build/{ANDROID_STUDIO_PROJECT}/proj/build.gradle
1 2 3 4 5 6 7 8 9 10 11 12 13
| buildscript {
... dependencies { classpath 'com.android.tools.build:gradle:<AGP_VERSION>' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:2.0.21"
... } }
...
|
修改构建工具版本
修改{COCOS_PROJECT}/build/{ANDROID_STUDIO_PROJECT}/proj/gradle.properties
1 2 3 4 5 6
| ...
PROP_MIN_SDK_VERSION=23
PROP_BUILD_TOOLS_VERSION=36.0.0 ...
|
Firebase 集成配置
如果需要集成 Firebase,将 google-srvices.json 文件放置在以下目录:
1
| {COCOS_PROJECT}/native/engine/android/app
|
修改 {COCOS_PROJECT}/build/{ANDROID_STUDIO_PROJECT}/proj/build.gradle
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| buildscript {
... dependencies { classpath 'com.android.tools.build:gradle:<AGP_VERSION>' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:2.0.21" classpath 'com.google.gms:google-services:4.4.1' classpath 'com.google.firebase:firebase-crashlytics-gradle:3.0.6'
... } }
...
|
AppActivity 插入 SDK 初始化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| package com.cocos.game;
import android.os.Bundle; import android.content.Intent; import android.content.res.Configuration;
import com.cocos.service.SDKWrapper; import com.cocos.lib.CocosActivity;
import com.inonesdk.athana.cocos.AthanaCocosPlugin;
public class AppActivity extends CocosActivity {
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); SDKWrapper.shared().init(this); AthanaCocosPlugin.initBridge(); } ... }
|
AndroidManifest.xml 冲突解决
1 2 3 4 5 6 7 8 9 10 11 12
| <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" android:installLocation="auto" xmlns:tools="http://schemas.android.com/tools"> ... <application ...> <meta-data tools:replace="android:value" android:name="com.google.android.gms.games.APP_ID" android:value="${GMS_GAMES_ID}"/> ... </application> </manifest>
|
XCode 项目配置
依赖管理
本插件支持 CocoaPods 或 Swift Package Manager 进行依赖管理,其它依赖管理方案请自行处理。
使用本插件后,测试、打包,需要通过打开 {COCOS_PROJECT}/build/ios/proj/{ProjectName}.xcworkspace 工作空间进行
CocoaPods 方案
安装与配置 CocoaPods:见 CocoaPods Getting Started
Swift Package Manager 方案
引入依赖库
打开 {COCOS_PROJECT}/build/ios/proj/{ProjectName}.xcworkspace 工作空间,在主 target 的 Build Settings 中,找到Runpath Search Paths,在值末尾添加:@executable_path/Frameworks
添加桥接头文件
- 在 Source Files 组下创建 {ProjectName}-Bridging-Header.h 文件
- 设置 Build Setting
- Swift Compiler - Genereal
- Objectiv-C Bridging Header 设置 ../../../native/engine/ios/{ProjectName}-Bridging-Header.h
编辑 {ProjectName}-Bridging-Header.h 文件:
1 2
| #include "platform/apple/JsbBridgeWrapper.h"
|
添加桥接源码
引入 {COCOS_PROJECT}/native/engine/ios/libAthana 到 {ProjectName}/Source Files,在 Action 中选择 Reference files in place
引入 {COCOS_PROJECT}/native/engine/ios/GoogleService-Info.plist 到 {ProjectName}/Resources,在 Action 中选择 Reference files in place
Signing & Capabilities 配置
- 添加 Associated Domains
- 添加 Game Center
- 添加 In-App Purchase
- 添加 Push Notifications
- 添加 Sign In with Apple
Info 配置
- Custom iOS Target Properties 添加 Key :Privacy - Tracking Usage Description,value 则可以参考:
This identifier will be used to deliver personalized ads to you.
Build Settings 配置
- Packaging - Defines Module 设置为 Yes
- Swift Compiler - General
- Generated Header Name 设置 {projectName}-Swift.h
- Objective-C Bridging Header 设置
../../../native/engine/ios/{projectName}-Bridging-Header.h
- Swift Compiler - Language
- Swift Language Version 设置为 Swift 5
引入 SDK
在 XCode 编辑 {COCOS_PROJECT}/native/engine/ios/AppDelegate.mm 文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| ... #import "service/SDKWrapper.h"
#import "libAthana/JsbBridgeUtils.h" #import "{ProjectName}-Swift.h"
@implementation AppDelegate @synthesize window; @synthesize appDelegateBridge;
#pragma mark - #pragma mark Application lifecycle
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { [[AthanaCocos shared] application:application didFinishLaunchingWithOptions:launchOptions]; JsbBridgeUtils *bridgeUtils = [[JsbBridgeUtils alloc] init]; [bridgeUtils registerCallback:^(NSString * _Nonnull methodName, NSString * _Nullable arg) { [[AthanaCocos shared] dispatch:methodName arg:arg]; }];
[[SDKWrapper shared] application:application didFinishLaunchingWithOptions:launchOptions]; ... }
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options { return [[AthanaCocos shared] application:application open:url options:options]; }
...
|
可能会遇到的问题及解决方法
问题1:
1
| Assertion failed: (it != _dylibToOrdinal.end()), function dylibToOrdinal, file OutputFile.cpp, line 5196.
|
解决方法:
在 XCode 修改 Build Settings
- Linking - Genneral
- Other Linker Flags,
'-WI, -ld_classic' 修改为 -Xlinker -dead_strip -Xlinker -allow_dead_duplicates
使用
初始化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
| import { _decorator, Component } from 'cc'; import { Athana, AthanaConfig, AccountServiceConfig, AdServiceConfigs, MaxAdServiceConfig, ConversionServiceConfigs, AppsFlyerServiceConfig } from 'db://athana-cocos/athana';
const { ccclass } = _decorator;
@ccclass('SdkDemoComponent') export class SdkDemoComponent extends Component {
onLoad() { const appId = "****************"; const appKey = "****************"; const appSecret = "****************";
const afDevKey = "****************"; const maxDevKey = "****************"; const googleWebClientId = "****************"; const debug = true;
Athana.init( new AthanaConfig( appId, appKey, appSecret, new AccountServiceConfig(googleWebClientId), new AdServiceConfigs( new MaxAdServiceConfig( maxDevKey, null, null, new Map<AdType, string>([ [AdType.AppOpen, "****************"], [AdType.Interstitial, "****************"], [AdType.Rewarded, "****************"], ]), debug) ), new ConversionServiceConfigs( new AppsFlyerServiceConfig(afDevKey) ), null, debug) ); } start() { var privacyGrant = false; Athana.start(privacyGrant);
Athana.currentUser({ onSuccess: (data) => { if (data != null) { } else { registerUser(); } }, onError: (error) => { this.showToast("Faied to get Current User: " + error.message); }); }
update(deltaTime: number) {
}
private registerUser() { Athana.registerUser(new RegisterUserParam(SignInType.ANONYMOUS), { onSuccess: (data) => { }, onError: (error) => { console.log(`Athana Cocos - Register User Error: type=${error.type}, code=${error.code}, msg=${error.message}`); } }); } }
|
账号服务
登入
指定三方账号登入:
1 2 3 4 5 6 7 8 9 10 11 12
| const signInType = SignInType.FACEBOOK;
Athana.signIn(new SignInParam(signInType), { onSuccess: (data) => { }, onError: (error) => { } });
|
使用内置登录界面:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| const enableSignTypes = [SignInType.GOOGLE, SignInType.FACEBOOK];
var customUserId: number = null;
const privacyPolicyUrl: string = null;
const termsOfServiceUrl: string = null;
Athana.signInWithUI(new SignInWithUIParam( enableSignTypes, customUserId, privacyPolicyUrl, termsOfServiceUrl ), { onSuccess: (data) => { }, onError: (error) => { } });
|
登出
1 2 3 4 5 6 7 8 9
| Athana.signOut({ onSuccess: (data) => { }, onError: (error) => { } });
|
查询绑定
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| Athana.queryAllAccountBind({ onSuccess: (data) => { if (data.Facebook != null) { data.Facebook?.open_id; } if (data.Apple != null) { } if (data.Google != null) { } if (data.GoogleGameV2 != null) { } if (data.Firebase != null) { } }, onError: (error) => { } });
|
绑定
1 2 3 4 5 6 7 8 9 10 11
| const signInType = SignInType.FACEBOOK;
Athana.accountBinding(new AccountBindingParam(signInType), { onSuccess: (data) => { }, onError: (error) => { } });
|
解绑
1 2 3 4 5 6 7 8 9 10 11 12
| const signInType = SignInType.FACEBOOK;
const openId = "********"; Athana.accountUnbind(new AccountBindingParam(signInType, openId), { onSuccess: (data) => { }, onError: (error) => { } });
|
广告服务
应用启动广告
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| private _onLoadedListener?: (ad: ProxyAd) => void = null; private _onLoadFailedListener?: (event: AdEventResult) => void = null; private _adType = AdType.AppOpen;
private setListener() { this._onLoadedListener = (ad: ProxyAd) => { this.show(); } Athana.adService.registerOnLoaded(this._adType, this._onLoadedListener);
this._onLoadFailedListener = (event: AdEventResult) => { } Athana.adService.registerOnLoadFailed(this._adType, this._onLoadFailedListener); }
private show() { const adUnitId = "************"; Athana.adService.isReadyAppOpenAd(adUnitId).then((isReady) => { if (isReady) { Athana.adService.showAppOpenAd(adUnitId); } else { Athana.adService.loadAppOpenAd(adUnitId); } }).catch((error) => { }); }
private destroy() { if (this._onLoadedListener != null) { Athana.adService.unregisterOnLoaded(this._adType, this._onLoadedListener); this._onLoadedListener = null; } if (this._onLoadFailedListener != null) { Athana.adService.unregisterOnLoadFailed(this._adType, this._onLoadFailedListener); this._onLoadFailedListener = null; } }
|
激励广告
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
| private _onLoadedListener?: (ad: ProxyAd) => void = null; private _onLoadFailedListener?: (event: AdEventResult) => void = null; private _onRewardedListener?: (ad: ProxyAd) => void = null; private _adType = AdType.Rewarded;
private setListener() { this._onLoadedListener = (ad: ProxyAd) => { this.show(); } Athana.adService.registerOnLoaded(this._adType, this._onLoadedListener);
this._onLoadFailedListener = (event: AdEventResult) => { } Athana.adService.registerOnLoadFailed(this._adType, this._onLoadFailedListener);
this._onRewardedListener = (ad: ProxyAd) => { } Athana.adService.registerOnRewarded(this._adType, this._onRewardedListener); }
private show() { const adUnitId = "************"; Athana.adService.isReadyRewardedAd(adUnitId).then((isReady) => { if (isReady) { Athana.adService.showRewardedAd(adUnitId); } else { Athana.adService.loadRewardedAd(adUnitId); } }).catch((error) => { }); }
private destroy() { if (this._onLoadedListener != null) { Athana.adService.unregisterOnLoaded(this._adType, this._onLoadedListener); this._onLoadedListener = null; } if (this._onLoadFailedListener != null) { Athana.adService.unregisterOnLoadFailed(this._adType, this._onLoadFailedListener); this._onLoadFailedListener = null; } if (this._onRewardedListener != null) { Athana.adService.unregisterOnRewarded(this._adType, this._onRewardedListener); this._onRewardedListener = null; } }
|
插屏广告
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| private _onLoadedListener?: (ad: ProxyAd) => void = null; private _onLoadFailedListener?: (event: AdEventResult) => void = null; private _adType = AdType.Interstitial;
private setListener() { this._onLoadedListener = (ad: ProxyAd) => { this.show(); } Athana.adService.registerOnLoaded(this._adType, this._onLoadedListener);
this._onLoadFailedListener = (event: AdEventResult) => { } Athana.adService.registerOnLoadFailed(this._adType, this._onLoadFailedListener); }
private show() { const adUnitId = "************"; Athana.adService.isReadyInterstitialAd(adUnitId).then((isReady) => { if (isReady) { Athana.adService.showInterstitialAd(adUnitId); } else { Athana.adService.loadInterstitialAd(adUnitId); } }).catch((error) => { }); }
private destroy() { if (this._onLoadedListener != null) { Athana.adService.unregisterOnLoaded(this._adType, this._onLoadedListener); this._onLoadedListener = null; } if (this._onLoadFailedListener != null) { Athana.adService.unregisterOnLoadFailed(this._adType, this._onLoadFailedListener); this._onLoadFailedListener = null; } }
|
横幅广告
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| const adUnitId = "***************";
const adSize = AdSize.fullWidth(60);
Athana.adService.createBannerAd(new CreateBannerParam(adUnitId, adSize)) .then((banner) => { this._banner = banner;
this._banner?.hide(); this._banner?.show();
}).catch((error: AthanaError) => { });
|
支付服务
查询商店服务是否可用
1 2 3 4 5 6 7 8 9 10 11 12
| Athana.isIapAvailable({ onSuccess: (data) => { if (data) { } else { } }, onError: (error) => { } });
|
查询商品
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| const keys = ["key1", "key2", ...];
Athana.queryProducts(keys, { onSuccess: (data) => { if (data.length == 0) { } else if (data.length != keys.length) { } else { data.forEach(item => { item.price; }); } }, onError: (error) => { } });
|
购买
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| const productId = "****";
const subsInex = null;
const clientOrderId = null;
const consumable = true;
Athana.purchase( new PurchaseParam( productId, subsInex, clientOrderId, consumable ), { onSuccess: (data) => { }, onError: (error) => { } });
|
查询历史订单
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| Athana.queryPurchaseHistory({ onSuccess: (data) => { data.forEach(item => { item.purchaseId;
item.isAcknowledged }); }, onError: (error) => { } });
|
验证订单
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| const purchaseId = "******";
const consumable = true;
Athana.verifyOrder( new VerifyOrderParam( productId, subsInex, clientOrderId, consumable ), { onSuccess: (data) => { }, onError: (error) => { } });
|
事件服务
内置事件
1 2 3 4 5 6 7
| const event = AthanaEventFactory.logGamesTask(...);
Athana.sendEvent(event);
|
内置事件可参阅:事件服务
发送自定义事件
1 2 3 4 5 6 7 8 9 10 11 12
|
const key = "";
const params = new Map<string, any>();
params.set("param1", "value1"); const event = AthanaEvent(key, params);
Athana.sendEvent(event);
|
应用内评分
1 2 3 4 5 6 7 8
| Athana.requestReview({ onSuccess: () => { }, onError: (error) => { } });
|