海外SDK集成文档(IOS版本)
1.内购
1.1 添加SDK依赖
在Podfile文件中添加以下代码:
pod 'YF_IAP'
执行以下命令
pod install --repo-update
1.2 导入头文件
支付SDK的接口都封装在IAPHelper类中,在你需要调用IAPHelper接口的类中导入IAPHelper头文件即可:
#import <IAPKit/IAPHelper.h>
1.3 初始化SDK
在需要初始化的时候调用以下函数:
[[IAPHelper defaultHelper] startWithPurchasedTransaction:^(NSError * _Nullable error, NSString * _Nullable productId, NSString * _Nullable transactionId) { if (productId != nil && transactionId != nil) { //处理回调逻辑,例如发货 ... //发货后必须调用此方法 [[IAPHelper defaultHelper] finishTransactionWithId: transactionId]; } }];
注意,没有完成的交易或者自动订阅新的续费都会触发这个回调。
1.4 请求商品信息列表
在发起支付前需要向服务器请求一次商品信息列表,一般可用在展示商店的时候调用,示例代码如下:
NSArray *products = @[ @"g7_tfaa021909002.coins.0099", @"g7_tfaa021909002.coins.0499", @"g7_tfaa021909002.coins.0999", ]; [[IAPHelper defaultHelper] validateProductIds:products completion:^(NSError * _Nullable error, NSArray<SKProduct *> * _Nullable products) { self.products = products; //此处可以遍历返回的商品数组,从SKProduct中拿到商品信息:价格等 }];
1.5 发起内购
[[IAPHelper defaultHelper] buyProduct: sku completion:^(NSError * _Nullable error, NSString * _Nullable productId, NSString * _Nullable transactionId) { if (productId != nil && transactionId != nil && error == nil) { //处理回调逻辑,例如发货 ... //发货后必须调用此方法 [[IAPHelper defaultHelper] finishTransactionWithId: transactionId]; //Firebase埋点统计,必须添加 [FIRAnalytics logEventWithName:@"iap_pay_success" parameters:@{@"product_name":@"500coins",@"location":"main_page"}]; } }];
注意,支付成功与失败是根据回调中error是否为空。
1.5 发货后必须调用接口
[[IAPHelper defaultHelper] finishTransactionWithId: transactionId];
这个接口在支付成功回调中发货后调用一下即可。注意,初始化和发起内购两个地方都有支付回调。
1.6 恢复购买
恢复内购,严禁在启动时候调用,需由玩家手动触发。
[[IAPHelper defaultHelper] restoreCompletion:^(NSError * _Nullable error, NSArray<NSString *> * _Nullable productIds) { //处理回调 }];
1.7 查询订阅有效性
// 检查订阅的有效性 - (void)validateSubscripedProducts:(NSArray<NSString *> *)productIds completion:(void(^)(NSError * _Nullable error, NSArray<Product *> * _Nullable subscriptions))completion;
1.8 测试与验证
1)确保计费点ID和bundleID无误并入库ars后台; 2)发起支付并支付成功; 3)成功发货并在ars后台看到测试数据。
2.广告接入
广告采用AdMob聚合广告平台,Facebook、Unity等第三方广告SDK逻辑已经集成在MoPub中。
AdMob广告接入步骤大致如下:
1)集成admob sdk; 2)集成admob第三方广告平台网络适配器,是admob为了适配第三方广告的插件sdk; 3)集成第三方广告网络sdk,admob可以聚合多个第三方广告网络; 4)初始化并集成广告格式代码; 5)测试验证。
2.1添加SDK依赖
2.1.1 添加AdMob SDK
以下两种方式选择其中一种添加即可。
通过CocoaPods下载
在项目中的podfile文件种添加以下代码:
pod 'Google-Mobile-Ads-SDK'
然后在终端运行:
pod install --repo-update
通过本地添加AdMob依赖
SDK下载地址:
下载成功后直接解压,将以下framwork导入到Xcode工程中:
GoogleAppMeasurement.framework
GoogleMobileAds.framework
GoogleUtilities.xcframework
nanopb.xcframework
PromisesObjC.xcframework
UserMessagingPlatform.framework
导入到工程后,将 -ObjC
链接器标记添加到项目的 Build Settings 下的 Other Linker Flags 中。
2.1.2 添加AdMob第三方广告网络SDK适配器
第三方广告网络只需添加以下五个平台,后续添加AdMob适配器和广告网络SDK选择以下四个平台即可:
- Facebook Audience Network
- UnityAds
- IronSource
- AppLovin
以下两种方式选择其中一种添加即可。
通过CocoaPods下载
在项目中的podfile文件种添加以下代码:
# Facebook Audience Network pod 'GoogleMobileAdsMediationFacebook' # Unity Ads pod 'GoogleMobileAdsMediationUnity' # ironSource pod 'GoogleMobileAdsMediationIronSource' # AppLovin pod 'GoogleMobileAdsMediationAppLovin'
然后在终端运行:
pod install --repo-update
通过将Framwork下载到本地添加依赖
2.1.3 添加第三方广告网络SDK(注意,2.1.2中采用cocoapods方式集成可以忽略此步骤)
第三方广告适配器中采用cocoapods方式集成的话可以跳过此步骤,直接进入2.2章节,因为2.1.4章节中已经把广告网络SDK和适配器一起下载到了本地。
通过本地添加framwork依赖
SDK下载地址:
下载好SDK将FBAudienceNetwork.framework导入到Xcode中。
2)UnityAds
下载好SDK后将UnityAds.framwork导入到Xcode中。
下载好SDK后将IronSource.framwork导入到Xcode中。
4)AppLovin
2.2 Info.plist文件及其他配置
Admob AppID配置
将Admob AppId配置到info.plist文件中,AppId请联系我方运营获取,将运营提供的AppId替换下面的string值:
<key>GADApplicationIdentifier</key> <string>ca-app-pub-3940256099942544~1458002511</string>
添加连接器标记
1)点击项目target,点击Build Settings;
2)搜索Other Linker Flags;
3)在Other Linker Flags的值中添加'-ObjC'
2.3 初始化
导入头文件
在AppDelegate.m文件中导入以下头文件:
@import GoogleMobileAds;
添加初始化代码
在AppDelegate.m文件中的didFinishLaunchingWithOptions函数中添加以下代码:
GADMobileAds *ads = [GADMobileAds sharedInstance]; [ads startWithCompletionHandler:^(GADInitializationStatus *status) { /*NSDictionary *adapterStatuses = [status adapterStatusesByClassName]; for (NSString *adapter in adapterStatuses) { GADAdapterStatus *adapterStatus = adapterStatuses[adapter]; NSLog(@"Adapter Name: %@, Description: %@, Latency: %f", adapter, adapterStatus.description, adapterStatus.latency); } */ // 初始化完成才能请求广告 }];
2.4 横幅广告
导入头文件
在你的视图控制器ViewController.h文件中导入以下头文件并添加MPAdViewDelegate委托代理协议、声明属性:
@import GoogleMobileAds; @interface ViewController () <GADBannerViewDelegate> @property(nonatomic, strong) GADBannerView *bannerView; @end
创建并加载横幅广告
在视图控制器的viewDidLoad函数中添加以下代码:
self.bannerView = [[GADBannerView alloc] initWithAdSize:kGADAdSizeBanner]; bannerView.translatesAutoresizingMaskIntoConstraints = NO; [self.view addSubview:bannerView]; [self.view addConstraints:@[ [NSLayoutConstraint constraintWithItem:bannerView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.bottomLayoutGuide attribute:NSLayoutAttributeTop multiplier:1 constant:0], [NSLayoutConstraint constraintWithItem:bannerView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1 constant:0] ]]; self.bannerView.adUnitID = @"ca-app-pub-3940256099942544/2934735716";//注意这里要替换成运营提供的广告单元id self.bannerView.rootViewController = self; [self.bannerView loadRequest:[GADRequest request]];
自定义banner尺寸
如果kGADAdSizeBanner(320*50)不适用,可以进行自定义尺寸:
GADAdSize size = GADAdSizeFromCGSize(CGSizeMake(300, 50));
处理隐藏
如果在某些场景下需要把banner隐藏,可以调用以下代码:
[self.bannerView setHidden:YES];//需要在主线程中调用,设置为NO为显示状态
广告价值回传
self.bannerView.paidEventHandler = ^void(GADAdValue *_Nonnull value){ [FIRAnalytics logEventWithName:@"ads_revenue" parameters:@{ @"valuemicros": [[value.value decimalNumberByMultiplyingByPowerOf10:6] longValue], @"currency": value.currencyCode, @"precision": value.precision, @"adunitid": strongSelf.bannerView.adUnitID, @"network": strongSelf.bannerView.responseInfo.adNetworkClassName }]; };
添加回调
将以下代码根据你的需要添加到你的视图控制器中:
//广告加载成功回调 - (void)adViewDidReceiveAd:(GADBannerView *)adView { NSLog(@"adViewDidReceiveAd"); } //广告加载失败回调 - (void)adView:(GADBannerView *)adView didFailToReceiveAdWithError:(GADRequestError *)error { NSLog(@"adView:didFailToReceiveAdWithError: %@", [error localizedDescription]); } //广告展示时触发 - (void)adViewWillPresentScreen:(GADBannerView *)adView { NSLog(@"adViewWillPresentScreen"); } //广告即将视图消失时触发 - (void)adViewWillDismissScreen:(GADBannerView *)adView { NSLog(@"adViewWillDismissScreen"); } //广告视图消失时触发 - (void)adViewDidDismissScreen:(GADBannerView *)adView { NSLog(@"adViewWillDismissScreen"); } //离开APP时触发 - (void)adViewWillLeaveApplication:(GADBannerView *)adView { NSLog(@"adViewWillLeaveApplication"); }
2.5 插屏广告
导入头文件
在你的视图控制器ViewController.h文件中导入以下头文件并添加MPInterstitialAdControllerDelegate委托代理协议、声明属性:
@import GoogleMobileAds; @import UIKit; @interface ViewController ()<GADFullScreenContentDelegate> @property(nonatomic, strong) GADInterstitialAd *interstitial; @end
创建并加载插屏广告
在视图控制器的viewDidLoad函数中调用以下函数:
- (void)loadInterstitial { GADRequest *request = [GADRequest request]; [GADInterstitialAd loadWithAdUnitID:@"ca-app-pub-3940256099942544/4411468910" //注意这里要替换成运营提供的广告单元id request:request completionHandler:^(GADInterstitialAd *ad, NSError *error) { if (error) { //请求插屏失败 NSLog(@"Failed to load interstitial ad with error: %@", [error localizedDescription]); return; } //请求成功 self.interstitial = ad; self.interstitial.fullScreenContentDelegate = self; }]; }
展示插屏广告
在视图控制器中添加以下代码,并在你需要展示广告的时候调用:
- (void)showInterstitial { if (self.interstitial) [self.interstitial presentFromRootViewController:self]; else // 插屏还没有加载好 }
广告价值回传
self.interstitial.paidEventHandler = ^void(GADAdValue *_Nonnull value){ [FIRAnalytics logEventWithName:@"ads_revenue" parameters:@{ @"valuemicros": [[value.value decimalNumberByMultiplyingByPowerOf10:6] longValue], @"currency": value.currencyCode, @"precision": value.precision, @"adunitid": strongSelf.interstitial.adUnitID, @"network": strongSelf.interstitial.responseInfo.adNetworkClassName }]; };
添加回调
将以下代码根据你的需要添加到你的视图控制器中:
//插屏展示成功 - (void)adDidPresentFullScreenContent:(nonnull id<GADFullScreenPresentingAd>)ad { NSLog(@"Ad did present full screen content."); } //插屏展示失败 - (void)adDidPresentFullScreenContent:(nonnull id<GADFullScreenPresentingAd>)ad { NSLog(@"Ad did present full screen content."); } //插屏关闭 - (void)adDidDismissFullScreenContent:(nonnull id<GADFullScreenPresentingAd>)ad { NSLog(@"interstitial close"); //这里可以做下一条广告缓存 loadInterstitialAd(); }
2.6 激励视频
导入头文件
在你的视图控制器ViewController.h文件中导入以下头文件并添加MPRewardedVideoDelegate委托代理协议:
@import GoogleMobileAds; @import UIKit; @interface ViewController ()<GADFullScreenContentDelegate> @property(nonatomic, strong) GADRewardedAd *rewardedAd; @end
创建并加载激励视频
在视图控制器的viewDidLoad函数中调用以下函数:
GADRequest *request = [GADRequest request]; [GADRewardedAd loadWithAdUnitID:@"ca-app-pub-3940256099942544/4806952744"//注意这里要替换成运营提供的广告单元id request:request completionHandler:^(GADRewardedAd *ad, NSError *error) { if (error) { //请求激励视频失败 NSLog(@"Rewarded ad failed to load with error: %@", [error localizedDescription]); return; } //请求激励视频成功 self.rewardedAd = ad; self.rewardedAd.fullScreenContentDelegate = self; NSLog(@"Rewarded ad loaded."); }];
展示激励视频并处理广告奖励
在视图控制器中添加以下代码,并在你需要展示广告的时候调用:
- (void)show { ... if (self.rewardedAd) { [self.rewardedAd presentFromRootViewController:self userDidEarnRewardHandler:^{ GADAdReward *reward = self.rewardedAd.adReward; // 发放激励视频奖励 }]; } else { NSLog(@"Ad wasn't ready"); } }
广告价值回传
self.rewardedAd.paidEventHandler = ^void(GADAdValue *_Nonnull value){ [FIRAnalytics logEventWithName:@"ads_revenue" parameters:@{ @"valuemicros": [[value.value decimalNumberByMultiplyingByPowerOf10:6] longValue], @"currency": value.currencyCode, @"precision": value.precision, @"adunitid": strongSelf.rewardedAd.adUnitID, @"network": strongSelf.rewardedAd.responseInfo.adNetworkClassName }]; };
添加回调
将以下回调代码根据你的需要添加到你的视图控制器中:
//广告展示失败 - (void)ad:(nonnull id<GADFullScreenPresentingAd>)ad didFailToPresentFullScreenContentWithError:(nonnull NSError *)error { NSLog(@"Ad did fail to present full screen content."); } //广告展示成功 - (void)adDidPresentFullScreenContent:(nonnull id<GADFullScreenPresentingAd>)ad { NSLog(@"RV show"); //Firebase埋点,必须添加 [FIRAnalytics logEventWithName:@"ads_RV_show" parameters:{@"location":@"level_fail"}]; } //广告结束,可以在这里进行请求下一个广告 - (void)adDidDismissFullScreenContent:(nonnull id<GADFullScreenPresentingAd>)ad { NSLog(@"RV Disappear"); //这里可以缓存下一条广告 loadRV(); }
2.7 接入GDPR欧盟隐私条款
GDPR简单据介绍
产品上线欧盟地区必须要在游戏首次启动时弹出GDPR欧盟隐私条款,让玩家选择是否同意遵循条款。如果玩家选择不同意,则游戏就不能获取玩家的个人信息数据。
是否需要接入以我方运营需求为准。
2.7.1 定制用户协议界面
在AdMob后台左侧 “隐私权和消息” 栏目中进行定制用户协议界面。
此步骤研发无需关心,由我方运营进行
2.7.2 导入SDK
以下两种方式选择其中一种添加即可。
通过CocoaPods下载
在项目中的podfile文件种添加以下代码:
pod 'Google-Mobile-Ads-SDK'
然后在终端运行:
pod install --repo-update
通过本地添加AdMob依赖
SDK下载地址:
2.7.3 接口调用
导入头文件
#include <UserMessagingPlatform/UserMessagingPlatform.h>
请求协议同意状态
在游戏启动时调用以下接口:
UMPRequestParameters *parameters = [[UMPRequestParameters alloc] init]; //测试设备配置 UMPDebugSettings *debugSettings = [[UMPDebugSettings alloc] init]; debugSettings.testDeviceIdentifiers = @[ @"TEST-DEVICE-HASHED-ID" ];//测试设备Id请参考2.8.2中获取 debugSettings.geography = UMPDebugGeographyEEA; parameters.debugSettings = debugSettings; // 请求更新协议同意信息 [UMPConsentInformation.sharedInstance requestConsentInfoUpdateWithParameters:parameters completionHandler:^(NSError *_Nullable error) { if (error) { // 处理异常 } else { // 更新成功,可以开始加载协议弹窗 } }];
加载协议弹窗
[UMPConsentInformation.sharedInstance requestConsentInfoUpdateWithParameters:parameters completionHandler:^(NSError* _Nullable error) { if (error) { } else { UMPFormStatus formStatus = UMPConsentInformation.sharedInstance .formStatus; if (formStatus == UMPFormStatusAvailable) { [self loadForm]; } } }]; ... - (void) loadForm { [UMPConsentForm loadWithCompletionHandler:^(UMPConsentForm *form, NSError *loadError) { if (loadError) { // 处理异常 } else { // 展示弹窗 } }]; }
展示弹窗
- (void)loadForm { [UMPConsentForm loadWithCompletionHandler:^(UMPConsentForm *form, NSError *loadError) { if (loadError) { } else { if (UMPConsentInformation.sharedInstance.consentStatus == UMPConsentStatusRequired) { /** UMPConsentStatusUnknown: 未知状态 UMPConsentStatusRequired: 用户需要授权但是还没同意授权 UMPConsentStatusNotRequired: 用户不需要授权,比如用户并非欧洲用户 UMPConsentStatusObtained: 用户已经授权 **/ //展示弹窗 [form presentFromViewController:self completionHandler:^(NSError *_Nullable dismissError) { if (UMPConsentInformation.sharedInstance.consentStatus == UMPConsentStatusObtained) { // App can start requesting ads. } }]; } else { // 无需展示弹窗 } } }]; }
重置同意状态
测试时如果需要重置同意状态可以调用以下代码:
[UMPConsentInformation.sharedInstance reset];
2.8 测试与验证
测试前设备需要开启VPN(建议美国地区),否则可能会有加载不到广告的现象。
注意!对于激励视频和插屏广告强烈不建议在广告加载失败回调中进行加载广告,如果一定要这么做,务必限制重新加载次数,避免造成死循环。
激励视频和插屏广告建议在以下时机进行请求广告:
-
首次请求在游戏启动广告SDK初始化成功时;
-
缓存下一个广告在广告关闭的回调里进行加载;
-
在展示广告前的某个时机应该提前判断是否有广告,没有广告就去进行加载广告。
对于第三点,比如关卡结束时有广告埋点,游戏应该在关卡开始时先判断有没有广告已经填充,如果没有就要去进行加载广告。
2.8.1 使用测试广告单元Id测试,确保AdMob集成无误
iOS
横幅广告 ca-app-pub-3940256099942544/2934735716 插页式广告 ca-app-pub-3940256099942544/4411468910 激励视频广告 ca-app-pub-3940256099942544/1712485313
2.8.2 测试中介联盟广告,确保第三方广告集成无误
添加测试设备
以下添加方式选择一种即可
- AdMob后台添加,联系我方运营进行添加;
- 代码中添加,如下步骤所示:
1)运行游戏,发起一个广告请求; 2)检查控制台或者logcat的日志,查找以下内容: <Google> To get test ads on this device, set: GADMobileAds.sharedInstance.requestConfiguration.testDeviceIdentifiers = @[ @"2077ef9a63d2b398840261c8221a0c9b" ]; 3)复制日志中的设备id; 4)代码中设置测试设备: //可以在初始化前添加 GADMobileAds.sharedInstance.requestConfiguration.testDeviceIdentifiers = @[ @"2077ef9a63d2b398840261c8221a0c9b" ];
安装测试套件
1)安装 Material Components依赖项;
2)请将以下这行代码添加到您的 Podfile:
pod 'GoogleMobileAdsMediationTestSuite'
展示测试套件
在admob初始化完成时调用一下代码开启测试套件:
@import GoogleMobileAdsMediationTestSuite; [GoogleMobileAdsMediationTestSuite presentOnViewController:self delegate:nil];
注意!正式发布时,需要把测试套件代码注释!
在设备上运行游戏
运行游戏,启动时会弹出测试套件界面,逐一对每个平台进行加载、展示广告即可。
3.统计接入
统计需要接入以下两个平台。
Adjust用于归因事件统计与转发,不同用户来源追踪、质量追踪等;
Firebase以事件和用户为中心,展开对用户属性和行为进行分析。
3.1 Adjust
3.1.1 添加SDK依赖
添加Adjust SDK
以下两种方式任选其中一种即可。
通过CocoaPods下载
在项目中的podfile文件种添加以下代码:
pod 'Adjust', '~> 4.28.0'
然后在终端运行:
pod install
通过本地添加framwork依赖
SDK下载地址:
下载好后将整个AdjustSdk文件夹拖到项目根目录,并勾选Copy items if needed。
添加Adjust必须依赖框架
点击项目的Build Phases并展开Link Binary With Libraries,将以下系统的framwork添加进去,若项目已经存在以下framwork则无需添加:
- AdSupport.framework
- iAd.framework
- CoreTelephony.framework
3.1.2 初始化
导入头文件
在AppDelegate.h文件中添加AdjustDelegate
声明:
@interface AppDelegate : UIResponder <UIApplicationDelegate, AdjustDelegate>
在AppDelegate.m文件中导入以下头文件:
#import <AdjustSdk/Adjust.h>//framwork #import <Adjust/Adjust.h>//pod
添加初始化代码
在AppDelegate.m文件中的didFinishLaunching或者didFinishLaunchingWithOptions函数中添加以下代码:
NSString *yourAppToken = @"{YourAppToken}";//注意替换成项目的apptoken NSString *environment = ADJEnvironmentSandbox;//ADJEnvironmentSandbox是测试环境,正式发布前请设置为正式环境ADJEnvironmentProduction NSString *environment = ADJEnvironmentProduction; ADJConfig *adjustConfig = [ADJConfig configWithAppToken:yourAppToken environment:environment]; [adjustConfig setDelegate:self]; [Adjust appDidLaunch:adjustConfig];
在AppDelegate.m文件中添加以下委托回调:
- (void)adjustAttributionChanged:(ADJAttribution *)attribution { //获取归因数据用于Firebase adjust_conversion事件统计 NSString *network = attibution.network; NSString *campaign = attibution.campaign; NSString *adgroup = attibution.adgroup; NSString *creative = attibution.creative; if(network != nil){ //设置来源属性,必须添加 [FIRAnalytics setUserPropertyString:network forName:@"network"]; [FIRAnalytics setUserPropertyString:campaign forName:@"campaign"]; //Firebase埋点,必须添加 [FIRAnalytics logEventWithName:@"adjust_conversion" parameters:{@"network":network,@"campaign":campaign,@"adgroup":adgroup,@"creative":creative}]; } }
3.1.3 事件跟踪
在应用中需要跟踪的地方添加如下代码:
ADJEvent *event = [ADJEvent eventWithEventToken:@"abc123"]; [Adjust trackEvent:event];
3.1.4 其他接口
Adjust日志
可以通过设置日志等级来控制日志显示的数量:
[adjustConfig setLogLevel:ADJLogLevelVerbose]; // enable all logging [adjustConfig setLogLevel:ADJLogLevelDebug]; // enable more logging [adjustConfig setLogLevel:ADJLogLevelInfo]; // the default [adjustConfig setLogLevel:ADJLogLevelWarn]; // disable info logging [adjustConfig setLogLevel:ADJLogLevelError]; // disable warnings as well [adjustConfig setLogLevel:ADJLogLevelAssert]; // disable errors as well [adjustConfig setLogLevel:ADJLogLevelSuppress]; // disable all loggingogs
禁用日志:
NSString *yourAppToken = @"{YourAppToken}"; NSString *environment = ADJEnvironmentSandbox; ADJConfig *adjustConfig = [ADJConfig configWithAppToken:yourAppToken environment:environment allowSuppressLogLevel:YES]; [Adjust appDidLaunch:adjustConfig];
延迟启动SDK
如果需要延迟启动SDK,你可以在初始化得时候添加下面代码,Adjust最多延迟10秒:
[adjustConfig setDelayStart:5.5];
3.2 Firebase
目前只需添加Firebase统计SDK(Firebase Analytics)和崩溃SDK(Crashlytics)即可。
3.2.1 添加配置文件
运营会提供一个GoogleService-Info.plist配置文件,将此文件添加到项目的根目录即可。
3.2.2 添加SDK依赖
以下两种方式任选其中一种即可。
通过CocoaPods下载
在项目中的podfile文件种添加以下代码:
pod 'Firebase/Analytics' pod 'Firebase/Crashlytics'
然后在终端运行:
pod install
通过本地添加framwork依赖
SDK下载地址:
这个文件约有1GB大小,下载需要些时间,下载好后将Analytics和Crashlytics目录下的所有framwork添加到Xcode。
3.2.3 初始化SDK
初始化配置
1)在Navigator中选中项目,选择Build Phases;
2)点击+ Add a new build phase,然后选择 New Run Script Phase;
3)根据你添加SDK的方式将下面对应的代码添加到 Type a script 文本框中:
CocoaPods添加SDK:
${PODS_ROOT}/FirebaseCrashlytics/run /path/to/pods/directory/FirebaseCrashlytics/upload-symbols
手动添加SDK:
"${PROJECT_DIR}/FirebaseCrashlytics/run"
4)仅限 Xcode 10:将应用的已构建 Info.plist
位置添加到“Build Phase”的 Input Files 字段中:
$(SRCROOT)/$(BUILT_PRODUCTS_DIR)/$(INFOPLIST_PATH)
导入头文件
在AppDelegate.m文件中添加以下头文件:
@import Firebase;
添加初始化代码
在AppDelegate.m文件的application:didFinishLaunchingWithOptions函数中添加以下代码:
[FIRApp configure];
3.2.4 事件统计
Firebase可以自定义500个不同的事件,每个事件可以传最多25个参数,自定义事件需要传两个参数,一个是字符串类型事件名,一个是字典类型参数集,参数集可以为空,示例代码如下:
[FIRAnalytics logEventWithName:@"level_up" parameters:@{@"level":@"20"}];
注意!具体要统计的事件和规范请联系我方运营。
3.2.5 设置用户属性
用户属性可以将用户进行动态分群,后台可以直接将这个属性作为过滤条件,代码示例如下:
[FIRAnalytics setUserPropertyString:food forName:@"favorite_food"];
3.2.6 测试验证
由于Firebase后台数据有很长时间的延迟(24小时左右),测试数据没办法在后台马上能看到,要看实时测试数据需要用到Firebase后台的DebugView。请按以下步骤进行测试:
1)将设备打开USB调试连接电脑,注意设备和电脑都要翻墙; 2)打开Firebase后台DebugView; 3)在Xcode Product> Scheme> Edit scheme>Arguments> Launch > Add items,输入以下命令: -FIRDebugEnabled 4)在Xcode上运行游戏,运行成功后稍等十几秒DebugView左上角会出现你的设备名称,主面板会依次出现你打的事件名称。
3.2.7 Firebase远程配置接入(可选)
远程配置用于动态参数调整,可以根据后台配置的参数,来在客户端做出不同的行为调整。
添加SDK依赖
pod 'Firebase/RemoteConfig'
手动添加的话可以从3.2.2中下载好的SDK里获取remote config的framwork文件进行导入。
接口调用
初始化实例
self.remoteConfig = [FIRRemoteConfig remoteConfig]; FIRRemoteConfigSettings *remoteConfigSettings = [[FIRRemoteConfigSettings alloc] init]; remoteConfigSettings.minimumFetchInterval = 0; self.remoteConfig.configSettings = remoteConfigSettings;
设置默认值
如果出现获取不到后台设置的参数值,可以获取本地存储的默认值:
[self.remoteConfig setDefaultsFromPlistFileName:@"RemoteConfigDefaults"];
RemoteConfigDefaults.plist配置文件可放在项目根目录下,默认值配置实例如下:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>loading_phrase</key> <string>Fetching config...</string> <key>welcome_message_caps</key> <false/> <key>welcome_message</key> <string>Welcome to my awesome app!</string> </dict> </plist>
获取后台参数配置
通过调用fetchWithCompletionHandler方法可以向服务器请求参数配置,请求成功后所有参数配置会缓存到本地,此方法建议在初始化时调用:
[self.remoteConfig fetchWithCompletionHandler:^(FIRRemoteConfigFetchStatus status, NSError *error) { if (status == FIRRemoteConfigFetchStatusSuccess) { NSLog(@"Config fetched!"); [self.remoteConfig activateWithCompletionHandler:^(NSError * _Nullable error) { // ... }]; } else { NSLog(@"Config not fetched"); NSLog(@"Error %@", error.localizedDescription); } [self displayWelcome]; }];
获取参数中的值
根据游戏业务场景来获取相应的值,从而做出不同的策略,获取示例如下:
self.remoteConfig[@"welcome_message"].stringValue; self.remoteConfig[@"welcome_message_caps"].boolValue;
4.推送接入
暂时无需接入推送。
5.Facebook接入
Facebook接入包含Facebook统计、Facebook登录和Facebook分享,Facebook统计为必接模块,所以Facebook登录与分享中有和Facebook统计相同的配置不再重复说明。
5.1 Facebook统计
Facebook统计只需集成SDK并初始化即可,无需事件打点。
5.1.1 添加SDK依赖
以下两种方式任选其中一种即可。
通过CocoaPods下载
在项目中的podfile文件种添加以下代码:
pod 'FBSDKCoreKit'
然后在终端运行:
pod install
通过本地添加framwork依赖
SDK下载地址:
下载好后将FBSDKCoreKit.framework和Bolts.framework文件添加到Xcode并勾选Copy items if needed。
5.1.2 Info.plist文件配置
在Info.plist文件中添加以下配置:
<key>CFBundleURLTypes</key> <array> <dict> <key>CFBundleURLSchemes</key> <array> <string>fb{your-app-id}</string> </array> </dict> </array> <key>FacebookAppID</key> <string>{your-app-id}</string> <key>FacebookDisplayName</key> <string>{your-app-name}</string> <key>LSApplicationQueriesSchemes</key> <array> <string>fbapi</string> <string>fb-messenger-share-api</string> <string>fbauth2</string> <string>fbshareextension</string> </array>
注意替换{your-app-id}和{your-app-name},不要大括号。
5.1.3 初始化SDK
导入头文件
在AppDelegate.m文件中导入以下头文件:
#import <FBSDKCoreKit/FBSDKCoreKit.h>
添加初始化代码
在AppDelegate.m文件中添加以下初始化代码:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // You can skip this line if you have the latest version of the SDK installed [[FBSDKApplicationDelegate sharedInstance] application:application didFinishLaunchingWithOptions:launchOptions]; // Add any custom logic here. return YES; } - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options { BOOL handled = [[FBSDKApplicationDelegate sharedInstance] application:application openURL:url sourceApplication:options[UIApplicationOpenURLOptionsSourceApplicationKey] annotation:options[UIApplicationOpenURLOptionsAnnotationKey] ]; // Add any custom logic here. return handled; } - (void)applicationDidBecomeActive:(UIApplication *)application { [FBSDKAppEvents activateApp]; }
5.2 Facebook登录(可选)
5.2.1 添加SDK依赖
以下两种方式任选其中一种即可。
通过CocoaPods下载
在项目中的podfile文件种添加以下代码:
pod 'FBSDKLoginKit'
然后在终端运行:
pod install
通过本地添加framwork依赖
参考Facebook统计模块,然后将FBSDKLoginKit.framework添加到Xcode。
5.2.2 Info.plist文件及其他配置
配置Info.plist文件
参考Facebook统计模块
配置连接标记
在Build Setting中Other Linker Flags添加-ObjC标记。
5.2.3 初始化
参考Facebook统计模块。
5.2.4 添加登录按钮
导入头文件
在ViewController.m文件中导入以下头文件:
#import <FBSDKCoreKit/FBSDKCoreKit.h> #import <FBSDKLoginKit/FBSDKLoginKit.h>
添加登录按钮代码
在ViewController.m文件中添加以下代码:
@implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; FBSDKLoginButton *loginButton = [[FBSDKLoginButton alloc] init]; // Optional: Place the button in the center of your view. loginButton.center = self.view.center; [self.view addSubview:loginButton]; } @end
5.2.5 检查登录状态
- (void)viewDidLoad { [super viewDidLoad]; if ([FBSDKAccessToken currentAccessToken]) { // User is logged in, do work such as go to next view controller. } }
5.3 Facebook分享(可选)
5.2.1 添加SDK依赖
以下两种方式任选其中一种即可。
通过CocoaPods下载
在项目中的podfile文件种添加以下代码:
pod 'FBSDKShareKit'
然后在终端运行:
pod install
通过本地添加framwork依赖
参考Facebook统计模块,然后将FBSDKShareKit.framework添加到Xcode。
5.2.2 内容建模
分享链接
FBSDKShareLinkContent *content = [[FBSDKShareLinkContent alloc] init]; content.contentURL = [NSURL URLWithString:@"https://developers.facebook.com"];//替换成你要分享的链接
分享照片
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info { UIImage *image = info[UIImagePickerControllerOriginalImage]; FBSDKSharePhoto *photo = [[FBSDKSharePhoto alloc] init]; photo.image = image; photo.userGenerated = YES; FBSDKSharePhotoContent *content = [[FBSDKSharePhotoContent alloc] init]; content.photos = @[photo]; ... }
分享视频
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info { FBSDKShareVideo *video = [[FBSDKShareVideo alloc] init]; if (@available(iOS 11, *)) { video.videoAsset = [info objectForKey:UIImagePickerControllerPHAsset]; } else { video.videoURL = [info objectForKey:UIImagePickerControllerReferenceURL]; } FBSDKShareVideoContent *content = [[FBSDKShareVideoContent alloc] init]; content.video = video; ... }
分享多媒体
FBSDKSharePhoto *photo = [FBSDKSharePhoto photoWith... FBSDKShareVideo *video = [FBSDKShareVideo videoWith... FBSDKShareMediaContent *content = [FBSDKShareMediaContent new]; content.media = @[photo, video];
5.2.3 分享方法
构建好内容后,就要添加方法来触发分享,Facebook提供按钮和对话框的形式来触发分享。
分享按钮
分享按钮可以将内容分享到Facebook时间线、好友的时间线或小组中。
FBSDKShareButton *button = [[FBSDKShareButton alloc] init]; button.shareContent = content; [self.view addSubview:button];
发送按钮
发送按钮可以将内容分享给好友和使用Facebook Messenger的联系人。
FBSDKSendButton *button = [[FBSDKSendButton alloc] init]; button.shareContent = content; [self.view addSubview:button];
分享对话框
FBSDKShareLinkContent *content = [[FBSDKShareLinkContent alloc] init]; content.contentURL = [NSURL URLWithString:@"https://developers.facebook.com"]; FBSDKShareDialog *dialog = [[FBSDKShareDialog alloc] init]; dialog.fromViewController = self; dialog.content = content; dialog.mode = FBSDKShareDialogModeShareSheet; [dialog show];
5.2.4 其他分享
话题标签
可以指定一个话题标签,随着图片、链接视频等内容一同显示。
FBSDKShareLinkContent *content = [[FBSDKShareLinkContent alloc] init]; content.contentURL = [NSURL URLWithString:@"https://developers.facebook.com"]; content.hashtag = [FBSDKHashtag hashtagWithString:@"#MadeWithHackbook"];
引文分享
可以指定一段文本,随着图片、链接视频等内容一同分享。
FBSDKShareLinkContent *content = [[FBSDKShareLinkContent alloc] init]; content.contentURL = [@"https://developers.facebook.com/products/sharing"]; content.quote = @"Learn quick and simple ways for people to share content from your app or website to Facebook.";
6.其他
6.1 各平台官网文档链接
如遇到sdk版本与官网不同,以官网版本为准
6.2 iOS 14 适配
iOS 14开始,Apple获取IDFA广告设备标识符需要进行用户授权,如果不进行授权申请,在iOS 14上将影响广告变现收入、投放归因。
6.2.1 更新各平台SDK
将以下平台SDK更新到支持iOS14相应版本,具体详细版本请参考各平台接入“添加SDK依赖”部分
- Mopub
- Admob
- Ironsource
- Unity Ads
- Applovin
- Firebase
- Adjust
采用cocoa pods方式集成,重新拉一遍SDK即可,手动集成可以到官网下载最新版本SDK。
Facebook SDK更新注意事项
支持iOS14必须使用Facebook Audience Network SDK 6.0.0版本,这个版本必须和Facebook SDK 7.0.1及以上版本使用,否则请求Facebook广告时会发生崩溃。
1)如果使用cocoa pods方式集成,拉取Facebook Audience Network时会自动拉取Fcebook SDK;
2)如果不适用cocoa pods,则需要手动下载Facebook Audience Network和Fcebook SDK,下载链接如下:
下载好后将FBAudienceNetwork.framework 和FBSDKCoreKit.framework同时引入到项目中即可。
Facebook初始化适配
在初始化聚合广告平台(MoPub、AdMob)前,Facebook需要设置以下配置:
//YES表示允许Facebook使用数据去投放个性化广告,此设置仅在iOS14上生效 [FBAdSettings setAdvertiserTrackingEnabled:YES];
6.2.2 添加系统支持框架
- StoreKit.framework
- AppTrackingTransparency.framework (Xcode需要升级到12,暂时无需添加)
6.2.3 info.plist文件配置
在info.plist文件中添加广告平台
添加已经有授权的平台Id,即使用户拒绝授权,这些广告平台也可以在iOS14上归因到应用安装。
目前已知被授权的平台有:
- AdMob
- Ironsource
- Unity Ads
- AppLovin
- MoPub
使用非Mopub聚合广告需要添加的配置:
<key>SKAdNetworkItems</key> <array> <dict> <key>SKAdNetworkIdentifier</key> <string>cstr6suwn9.skadnetwork</string> </dict> <dict> <key>SKAdNetworkIdentifier</key> <string>SU67R6K2V3.skadnetwork</string> </dict> <dict> <key>SKAdNetworkIdentifier</key> <string>4DZT52R2T5.skadnetwork</string> </dict> <dict> <key>SKAdNetworkIdentifier</key> <string>ludvb6z3bs.skadnetwork</string> </dict> <dict> <key>SKAdNetworkIdentifier</key> <string>v9wttpbfk9.skadnetwork</string> </dict> <dict> <key>SKAdNetworkIdentifier</key> <string>n38lu8286q.skadnetwork</string> </dict> </array>
使用MoPub聚合广告需要添加的配置:
<key>SKAdNetworkItems</key> <array> <dict> <key>SKAdNetworkIdentifier</key> <string>cstr6suwn9.skadnetwork</string> </dict> <dict> <key>SKAdNetworkIdentifier</key> <string>SU67R6K2V3.skadnetwork</string> </dict> <dict> <key>SKAdNetworkIdentifier</key> <string>4DZT52R2T5.skadnetwork</string> </dict> <dict> <key>SKAdNetworkIdentifier</key> <string>ludvb6z3bs.skadnetwork</string> </dict> <dict> <key>SKAdNetworkIdentifier</key> <string>22mmun2rn5.skadnetwork</string> </dict> <dict> <key>SKAdNetworkIdentifier</key> <string>2U9PT9HC89.skadnetwork</string> </dict> <dict> <key>SKAdNetworkIdentifier</key> <string>3qy4746246.skadnetwork</string> </dict> <dict> <key>SKAdNetworkIdentifier</key> <string>3RD42EKR43.skadnetwork</string> </dict> <dict> <key>SKAdNetworkIdentifier</key> <string>3sh42y64q3.skadnetwork</string> </dict> <dict> <key>SKAdNetworkIdentifier</key> <string>4468km3ulz.skadnetwork</string> </dict> <dict> <key>SKAdNetworkIdentifier</key> <string>44jx6755aq.skadnetwork</string> </dict> <dict> <key>SKAdNetworkIdentifier</key> <string>4FZDC2EVR5.skadnetwork</string> </dict> <dict> <key>SKAdNetworkIdentifier</key> <string>523jb4fst2.skadnetwork</string> </dict> <dict> <key>SKAdNetworkIdentifier</key> <string>5a6flpkh64.skadnetwork</string> </dict> <dict> <key>SKAdNetworkIdentifier</key> <string>5l3tpt7t6e.skadnetwork</string> </dict> <dict> <key>SKAdNetworkIdentifier</key> <string>5lm9lj6jb7.skadnetwork</string> </dict> <dict> <key>SKAdNetworkIdentifier</key> <string>737z793b9f.skadnetwork</string> </dict> <dict> <key>SKAdNetworkIdentifier</key> <string>7953JERFZD.skadnetwork</string> </dict> <dict> <key>SKAdNetworkIdentifier</key> <string>7rz58n8ntl.skadnetwork</string> </dict> <dict> <key>SKAdNetworkIdentifier</key> <string>7UG5ZH24HU.skadnetwork</string> </dict> <dict> <key>SKAdNetworkIdentifier</key> <string>8s468mfl3y.skadnetwork</string> </dict> <dict> <key>SKAdNetworkIdentifier</key> <string>97r2b46745.skadnetwork</string> </dict> <dict> <key>SKAdNetworkIdentifier</key> <string>9RD848Q2BZ.skadnetwork</string> </dict> <dict> <key>SKAdNetworkIdentifier</key> <string>9T245VHMPL.skadnetwork</string> </dict> <dict> <key>SKAdNetworkIdentifier</key> <string>9yg77x724h.skadnetwork</string> </dict> <dict> <key>SKAdNetworkIdentifier</key> <string>av6w8kgt66.skadnetwork</string> </dict> <dict> <key>SKAdNetworkIdentifier</key> <string>bvpn9ufa9b.skadnetwork</string> </dict> <dict> <key>SKAdNetworkIdentifier</key> <string>c6k4g5qg8m.skadnetwork</string> </dict> <dict> <key>SKAdNetworkIdentifier</key> <string>cg4yq2srnc.skadnetwork</string> </dict> <dict> <key>SKAdNetworkIdentifier</key> <string>CJ5566H2GA.skadnetwork</string> </dict> <dict> <key>SKAdNetworkIdentifier</key> <string>F38H382JLK.skadnetwork</string> </dict> <dict> <key>SKAdNetworkIdentifier</key> <string>f73kdq92p3.skadnetwork</string> </dict> <dict> <key>SKAdNetworkIdentifier</key> <string>ggvn48r87g.skadnetwork</string> </dict> <dict> <key>SKAdNetworkIdentifier</key> <string>gvmwg8q7h5.skadnetwork</string> </dict> <dict> <key>SKAdNetworkIdentifier</key> <string>hs6bdukanm.skadnetwork</string> </dict> <dict> <key>SKAdNetworkIdentifier</key> <string>kbd757ywx3.skadnetwork</string> </dict> <dict> <key>SKAdNetworkIdentifier</key> <string>KLF5C3L5U5.skadnetwork</string> </dict> <dict> <key>SKAdNetworkIdentifier</key> <string>M8DBW4SV7C.skadnetwork</string> </dict> <dict> <key>SKAdNetworkIdentifier</key> <string>mlmmfzh3r3.skadnetwork</string> </dict> <dict> <key>SKAdNetworkIdentifier</key> <string>mls7yz5dvl.skadnetwork</string> </dict> <dict> <key>SKAdNetworkIdentifier</key> <string>mtkv5xtk9e.skadnetwork</string> </dict> <dict> <key>SKAdNetworkIdentifier</key> <string>n66cz3y3bx.skadnetwork</string> </dict> <dict> <key>SKAdNetworkIdentifier</key> <string>n9x2a789qt.skadnetwork</string> </dict> <dict> <key>SKAdNetworkIdentifier</key> <string>nzq8sh4pbs.skadnetwork</string> </dict> <dict> <key>SKAdNetworkIdentifier</key> <string>p78axxw29g.skadnetwork</string> </dict> <dict> <key>SKAdNetworkIdentifier</key> <string>ppxm28t8ap.skadnetwork</string> </dict> <dict> <key>SKAdNetworkIdentifier</key> <string>prcb7njmu6.skadnetwork</string> </dict> <dict> <key>SKAdNetworkIdentifier</key> <string>pu4na253f3.skadnetwork</string> </dict> <dict> <key>SKAdNetworkIdentifier</key> <string>t38b2kh725.skadnetwork</string> </dict> <dict> <key>SKAdNetworkIdentifier</key> <string>u679fj5vs4.skadnetwork</string> </dict> <dict> <key>SKAdNetworkIdentifier</key> <string>uw77j35x4d.skadnetwork</string> </dict> <dict> <key>SKAdNetworkIdentifier</key> <string>v72qych5uu.skadnetwork</string> </dict> <dict> <key>SKAdNetworkIdentifier</key> <string>W9Q455WK68.skadnetwork</string> </dict> <dict> <key>SKAdNetworkIdentifier</key> <string>WZMMZ9FP6W.skadnetwork</string> </dict> <dict> <key>SKAdNetworkIdentifier</key> <string>XY9T38CT57.skadnetwork</string> </dict> <dict> <key>SKAdNetworkIdentifier</key> <string>YCLNXRL5PM.skadnetwork</string> </dict> <dict> <key>SKAdNetworkIdentifier</key> <string>z4gj7hsk7h.skadnetwork</string> </dict> <dict> <key>SKAdNetworkIdentifier</key> <string>v9wttpbfk9.skadnetwork</string> </dict> <dict> <key>SKAdNetworkIdentifier</key> <string>n38lu8286q.skadnetwork</string> </dict> </array>
在info.plist文件中添加授权弹窗提示信息(暂时无需配置)
开发者可以自定义弹窗文本来提高用户授权,下面是一个示例文本,将其添加到info.plist文件中:
<key>NSUserTrackingUsageDescription</key> <string>This identifier will be used to deliver personalized ads to you.</string>
6.2.4 用户授权申请(暂时无需配置)
请在应用初始化时,调用以下接口,根据回调信息可以上传埋点等信息了解用户的授权情况:
[Adjust requestTrackingAuthorizationWithCompletionHandler:^(NSUInteger status) { switch (status) { case 0: NSLog(@"等待授权"); break; case 1: NSLog(@"授权状态受限"); break; case 2: NSLog(@"拒绝授权"); break; case 3: NSLog(@"用户已授权"); break; } }];
6.3 兑换码功能(可选)
游戏如果想要接入兑换码功能,请自行提供输入兑换码的UI,然后访问我们提供的API接口,根据接口的返回计费点Id进行发货。
6.3 FAQ
待补充,欢迎提出问题与建议!