具体如何发布IOS可看前面文章(一)(二)
cocos creator引擎版本: 2.4.3
macOS Big Sur:11.5
Xcode:12.0
Googel Admob Sdk :8.9.0
demo:https://download.csdn.net/download/weixin_41843959/21063187
参考链接:
https://www.jianshu.com/p/7bb64c1ac182
0、先看官网介绍
1、新建空项目,构建-》编译,得到Xcode项目 打开
打开遇到这个问题把其他Xode项目关闭就行?
?
?2、下载sdk
由于不会用CocoaPods ,所以还是手动下载sdk
https://developers.google.com/admob/ios/download
?下载好后将7个都放入到 根目录下
切记勾选 :Copy...? 不然后面引用不上google sdk
?检查这里的状态是否包含进去
?将?-ObjC ?链接器标记添加到项目的 Build Settings 下的?Other Linker Flags?中,默认cocos导出的项目应该已经是有的,如果没有就自己增加-ObjC?$(inherited) ,如果什么都没有点不出来写的话,可以先在子节点里面点加号,随便写东西就有了
?
更新应用的?Info.plist ?文件
?添加:
获取广告权限 (可看(二),有详解)
<key>NSUserTrackingUsageDescription</key> <string>Your?data?will?be?used?to?provide?you?better?personalized?ads</string>
然后添加相对应的lib
设置广告的appid
<key>GADApplicationIdentifier</key> <string>ca-app-pub-3940256099942544~1458002511</string>
据说不加会有bug,详解:https://blog.csdn.net/lvmaker/article/details/100061183
<key>GADIsAdManagerApp</key> <true/>
后面的欧盟地区,?延迟应用测量(可选)
<key>GADDelayAppMeasurementInit</key> <true/>
3 、SDK,调用
新建文件夹,commend+N 新建以下文档,由于ObjectToJs.mm需要回掉cocos接口,需要用到c++代码,所以建成.mm文件,由于没找到怎么建,我是直接将.m的后缀改成.mm,
?不能直接将整个文件夹复制,好像找不到引用,如果直接复制的话需要手动添加
?AdmobManger.h
#import <Foundation/Foundation.h>
#import "RootViewController.h"
NS_ASSUME_NONNULL_BEGIN
@interface AdmobManger : NSObject
+ (instancetype)sharedSingleton;
- (void)SetView :(RootViewController *)parm;
+ (void) ShowInterstitialAd;
+ (void) ShowRewardedAd;
+ (void) ShowBannerAd;
- (void) UMPStart;
@end
NS_ASSUME_NONNULL_END
?AdmobManger.m
#import "AdmobManger.h"
#import "AppController.h"
#import "AdsInterstitial.h"
#import "AdsRewarded.h"
#import "AdsBanner.h"
#include <UserMessagingPlatform/UserMessagingPlatform.h>
//@import GoogleMobileAds;
@interface AdmobManger()
@property RootViewController *view;
@property AdsInterstitial *adsInterstitial;
@property AdsRewarded *adsRewarded;
@property AdsBanner *adsBanner;
@end
@implementation AdmobManger
+ (instancetype)sharedSingleton {
static AdmobManger *_sharedSingleton = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
//不能再使用alloc方法
//因为已经重写了allocWithZone方法,所以这里要调用父类的分配空间的方法
if (_sharedSingleton==nil) {
_sharedSingleton = [[super allocWithZone:NULL] init];
}
//[_sharedSingleton initDelegate];
//[_sharedSingleton checkTransaction];
});
return _sharedSingleton;
}
- (void)SetView :(RootViewController *)parm{
self.view=parm;
[self InitAds];
}
/**
初始化广告
*/
- (void) InitAds{
self.adsInterstitial=[[AdsInterstitial alloc] init];
[self.adsInterstitial loadInterstitial];
self.adsRewarded=[[AdsRewarded alloc] init];
[self.adsRewarded loadRewardedAd];
self.adsBanner=[[AdsBanner alloc] init];
//[[AdsInterstitial sharedSingleton] loadInterstitial];
}
/**
展示插屏,cocos调用xcode,只能调用静态接口
*/
+ (void) ShowInterstitialAd{
[[AdmobManger sharedSingleton] showInterstitialAdUser];
}
- (void) showInterstitialAdUser{
[self.adsInterstitial showInterstitial:self.view];
}
/**
展示视频
*/
+ (void) ShowRewardedAd{
[[AdmobManger sharedSingleton] showRewardedAdUser];
}
- (void) showRewardedAdUser{
[self.adsRewarded showRewardedAd:self.view];
}
/**
展示banner
*/
+ (void) ShowBannerAd{
[[AdmobManger sharedSingleton] showBannerUser];
}
- (void) showBannerUser{
[self.adsBanner loadBannerAd:self.view];
}
/*
欧盟sdk的初始化
*/
- (void) UMPStart{
NSLog(@"------ UMpStart----------");
// Create a UMPRequestParameters object.
UMPRequestParameters *parameters = [[UMPRequestParameters alloc] init];
// Set tag for under age of consent. Here NO means users are not under age.
parameters.tagForUnderAgeOfConsent = NO;
// 强制测试
// UMPRequestParameters *parameters = [[UMPRequestParameters alloc] init];
// UMPDebugSettings *debugSettings = [[UMPDebugSettings alloc] init];
// debugSettings.testDeviceIdentifiers = @[ @"TEST-DEVICE-HASHED-ID" ];
// debugSettings.geography = UMPDebugGeographyEEA;
// parameters.debugSettings = debugSettings;
// Request an update to the consent information.
[UMPConsentInformation.sharedInstance
requestConsentInfoUpdateWithParameters:parameters
completionHandler:^(NSError* _Nullable error) {
// The consent information has updated.
if (error) {
// Handle the error.
} else {
// The consent information state was updated.
// You are now ready to see if a form is available.
UMPFormStatus formStatus =
UMPConsentInformation.sharedInstance
.formStatus;
if (formStatus == UMPFormStatusAvailable) {
[self loadForm];
}
}
}];
}
- (void)loadForm {
NSLog(@"-----UMP- loadForm----------");
[UMPConsentForm loadWithCompletionHandler:^(UMPConsentForm *form,
NSError *loadError) {
if (loadError) {
// Handle the error.
} else {
// Present the form. You can also hold on to the reference to present
// later.
if (UMPConsentInformation.sharedInstance.consentStatus ==
UMPConsentStatusRequired) {
[form
presentFromViewController:self.view
completionHandler:^(NSError *_Nullable dismissError) {
if (UMPConsentInformation.sharedInstance.consentStatus ==
UMPConsentStatusObtained) {
// App can start requesting ads.
}
}];
} else {
// Keep the form available for changes to user consent.
}
}
}];
}
@end
?AdsBanner.h
#import <Foundation/Foundation.h>
#import "RootViewController.h"
NS_ASSUME_NONNULL_BEGIN
@interface AdsBanner : NSObject
- (void)loadBannerAd:(RootViewController *)parm1;
@end
NS_ASSUME_NONNULL_END
AdsBanner.m
#import "AdsBanner.h"
#import?<GoogleMobileAds/GoogleMobileAds.h>
@interface AdsBanner ()<GADBannerViewDelegate>
@property(nonatomic, strong) GADBannerView *bannerView;
/*
广告加载状态 0 未加载 1加载中 2加载完成
*/
@property int loadingStatus;
@property RootViewController *views;
@end
@implementation AdsBanner
- (void)loadBannerAd:(RootViewController *)parm1{
NSLog(@"------loadBannerAd-------");
GADAdSize size = GADAdSizeFromCGSize(CGSizeMake(300, 50));
self.views=parm1;
self.bannerView = [[GADBannerView alloc]
initWithAdSize:kGADAdSizeBanner];
self.bannerView.adUnitID = @"ca-app-pub-3940256099942544/2934735716";
self.bannerView.rootViewController = parm1;
self.bannerView.delegate = self;
//自适应
// CGRect frame = parm1.view.frame;
//
// if (@available(iOS 11.0, *)) {
// frame = UIEdgeInsetsInsetRect(parm1.view.frame, parm1.view.safeAreaInsets);
// }
// CGFloat viewWidth = frame.size.width;
//
// self.bannerView.adSize = GADLandscapeAnchoredAdaptiveBannerAdSizeWithWidth(viewWidth);
[self.bannerView loadRequest:[GADRequest request]];
}
- (void)addBannerViewToView:(UIView *)bannerView {
bannerView.translatesAutoresizingMaskIntoConstraints = NO;
[self.views.view addSubview:bannerView];
[self.views.view addConstraints:@[
[NSLayoutConstraint constraintWithItem:bannerView
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:self.views.bottomLayoutGuide
attribute:NSLayoutAttributeLeading
multiplier:1
constant:0],
[NSLayoutConstraint constraintWithItem:bannerView
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self.views.view
attribute:NSLayoutAttributeCenterX
multiplier:1
constant:0]
]];
}
- (void)bannerViewDidReceiveAd:(GADBannerView *)bannerView {
NSLog(@"bannerViewDidReceiveAd");
[self addBannerViewToView:self.bannerView];
bannerView.alpha = 0;
[UIView animateWithDuration:1.0 animations:^{
bannerView.alpha = 1;
}];
}
- (void)bannerView:(GADBannerView *)bannerView didFailToReceiveAdWithError:(NSError *)error {
NSLog(@"bannerView:didFailToReceiveAdWithError: %@", [error localizedDescription]);
}
- (void)bannerViewDidRecordImpression:(GADBannerView *)bannerView {
NSLog(@"bannerViewDidRecordImpression");
}
- (void)bannerViewWillPresentScreen:(GADBannerView *)bannerView {
NSLog(@"bannerViewWillPresentScreen");
}
- (void)bannerViewWillDismissScreen:(GADBannerView *)bannerView {
NSLog(@"bannerViewWillDismissScreen");
}
- (void)bannerViewDidDismissScreen:(GADBannerView *)bannerView {
NSLog(@"bannerViewDidDismissScreen");
}
@end
?AdsInterstitial.h
//插屏
#import <Foundation/Foundation.h>
#import "RootViewController.h"
NS_ASSUME_NONNULL_BEGIN
@interface AdsInterstitial : NSObject
//+ (instancetype)sharedSingleton;
- (void)loadInterstitial;
- (void)showInterstitial:(RootViewController *)parm1;
@end
NS_ASSUME_NONNULL_END
?AdsInterstitial.m
#import "AdsInterstitial.h"
#import "AppController.h"
#import?<GoogleMobileAds/GoogleMobileAds.h>
@interface AdsInterstitial() <GADFullScreenContentDelegate>
/// 插屏对象
@property(nonatomic, strong) GADInterstitialAd *interstitial;
/*
广告加载状态 0 未加载 1加载中 2加载完成
*/
@property int loadingStatus;
@property RootViewController *views;
@end
@implementation AdsInterstitial
//+ (instancetype)sharedSingleton {
// static AdsInterstitial *_sharedSingleton = nil;
// static dispatch_once_t onceToken;
// dispatch_once(&onceToken, ^{
// //不能再使用alloc方法
// //因为已经重写了allocWithZone方法,所以这里要调用父类的分配空间的方法
// _sharedSingleton = [[super allocWithZone:NULL] init];
// //[_sharedSingleton initDelegate];
// //[_sharedSingleton checkTransaction];
// });
// return _sharedSingleton;
//}
- (void)loadInterstitial {
NSLog(@"------loadInterstitial-------");
GADRequest *request = [GADRequest request];
[GADInterstitialAd
loadWithAdUnitID:@"ca-app-pub-3940256099942544/4411468910"
request:request
completionHandler:^(GADInterstitialAd *ad, NSError *error) {
if (error) {
NSLog(@"Failed to load interstitial ad with error: %@", [error localizedDescription]);
self.loadingStatus=0;
return;
}
self.interstitial = ad;
self.interstitial.fullScreenContentDelegate = self;
self.loadingStatus=2;
}];
self.loadingStatus=1;
}
- (void)showInterstitial:(RootViewController *)parm1{
NSLog(@"------showInterstitial-------");
self.views=parm1;
if (self.loadingStatus==2)
{
if (self.interstitial)
{
[self.interstitial presentFromRootViewController: parm1];
} else {
NSLog(@"Ad wasn't ready");
}
}else if (self.loadingStatus==0)
{
[self loadInterstitial];
}else
{
NSLog(@"AdInterstitial 加载中。。。");
}
}
#pragma GADFullScreeContentDelegate implementation
- (void)adDidPresentFullScreenContent:(id)ad {
NSLog(@"AdInterstitial did present full screen content.");
}
- (void)ad:(id)ad didFailToPresentFullScreenContentWithError:(NSError *)error {
NSLog(@"AdInterstitial failed to present full screen content with error %@.", [error localizedDescription]);
self.loadingStatus=0;
}
- (void)adDidDismissFullScreenContent:(id)ad {
NSLog(@"AdInterstitial did dismiss full screen content.");
//重新load
[self loadInterstitial];
}
#pragma Interstitial button actions
@end
AdsRewarded.h
//激励视频
#import <Foundation/Foundation.h>
#import "RootViewController.h"
NS_ASSUME_NONNULL_BEGIN
@interface AdsRewarded : NSObject
//+ (instancetype)sharedSingleton;
- (void)loadRewardedAd;
- (void)showRewardedAd:(RootViewController *)parm1;
@end
NS_ASSUME_NONNULL_END
AdsRewarded.m
#import "AdsRewarded.h"
#import "AppController.h"
#import "ObjectToJs.h"
#import?<GoogleMobileAds/GoogleMobileAds.h>
@interface AdsRewarded() <GADFullScreenContentDelegate>
@property(nonatomic, strong) GADRewardedAd *rewardedAd;
/*
广告加载状态 0 未加载 1加载中 2加载完成
*/
@property int loadingStatus;
@property RootViewController *views;
/*
是否拿到奖励
*/
@property bool isReward;
@end
@implementation AdsRewarded
//+ (instancetype)sharedSingleton {
// static AdsInterstitial *_sharedSingleton = nil;
// static dispatch_once_t onceToken;
// dispatch_once(&onceToken, ^{
// //不能再使用alloc方法
// //因为已经重写了allocWithZone方法,所以这里要调用父类的分配空间的方法
// _sharedSingleton = [[super allocWithZone:NULL] init];
// //[_sharedSingleton initDelegate];
// //[_sharedSingleton checkTransaction];
// });
// return _sharedSingleton;
//}
- (void)loadRewardedAd {
NSLog(@"------loadRewardedAd-------");
GADRequest *request = [GADRequest request];
[GADRewardedAd
loadWithAdUnitID:@"ca-app-pub-3940256099942544/1712485313"
request:request
completionHandler:^(GADRewardedAd *ad, NSError *error) {
if (error) {
NSLog(@"Rewarded ad failed to load with error: %@", [error localizedDescription]);
self.loadingStatus=0;
return;
}
NSLog(@"Rewarded ad loaded.");
self.rewardedAd = ad;
self.rewardedAd.fullScreenContentDelegate = self;
self.loadingStatus=2;
}];
self.loadingStatus=1;
}
- (void)showRewardedAd:(RootViewController *)parm1{
NSLog(@"------showRewardedAd-------");
self.views=parm1;
self.isReward=false;
if (self.loadingStatus==2)
{
if (self.rewardedAd) {
[self.rewardedAd presentFromRootViewController:parm1
userDidEarnRewardHandler:^{
GADAdReward *reward =self.rewardedAd.adReward;
// TODO: Reward the user!
self.isReward=true;
}];
} else {
NSLog(@"Ad wasn't ready");
}
}else if (self.loadingStatus==0)
{
[self loadRewardedAd];
}else
{
NSLog(@"loadRewardedAd 加载中。。。");
}
}
#pragma GADFullScreeContentDelegate implementation
/// Tells the delegate that the ad failed to present full screen content.
- (void)ad:(nonnull id<GADFullScreenPresentingAd>)ad
didFailToPresentFullScreenContentWithError:(nonnull NSError *)error {
NSLog(@"RewardedAd did fail to present full screen content.");
}
/// Tells the delegate that the ad presented full screen content.
- (void)adDidPresentFullScreenContent:(nonnull id<GADFullScreenPresentingAd>)ad {
NSLog(@"RewardedAd did present full screen content.");
self.loadingStatus=0;
}
/// Tells the delegate that the ad dismissed full screen content.
- (void)adDidDismissFullScreenContent:(nonnull id<GADFullScreenPresentingAd>)ad {
NSLog(@"RewardedAd did dismiss full screen content.");
if (self.isReward) {
[[ObjectToJs sharedSingleton] RewardUser];
}
//重新load
[self loadRewardedAd];
}
#pragma Interstitial button actions
@end
GDATTrackingIdfa.h
//获取广告标识符权限,窗口
#import <Foundation/Foundation.h>
#import "RootViewController.h"
NS_ASSUME_NONNULL_BEGIN
@interface GDATTrackingIdfa : NSObject
+ (instancetype)sharedSingleton;
+ (void)requestIDFA;
+ (void)test2WithParm1:(NSString *)parm1 andParm2:(NSString *)parm2;
- (void) callCocos;
@end
NS_ASSUME_NONNULL_END
GDATTrackingIdfa.m?
#import "GDATTrackingIdfa.h"
#import <AdSupport/AdSupport.h>
#import <AppTrackingTransparency/AppTrackingTransparency.h>
#import "AdmobManger.h"
#import "RootViewController.h"
#import?<GoogleMobileAds/GoogleMobileAds.h>
@interface GDATTrackingIdfa()
@end
@implementation GDATTrackingIdfa
+ (instancetype)sharedSingleton {
static GDATTrackingIdfa *_sharedSingleton = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
//不能再使用alloc方法
//因为已经重写了allocWithZone方法,所以这里要调用父类的分配空间的方法
if (_sharedSingleton==nil) {
_sharedSingleton = [[super allocWithZone:NULL] init];
}
//[_sharedSingleton initDelegate];
//[_sharedSingleton checkTransaction];
});
return _sharedSingleton;
}
+ (void)requestIDFA {
if (@available(iOS 14.0, *)) {
[ATTrackingManager requestTrackingAuthorizationWithCompletionHandler:^(ATTrackingManagerAuthorizationStatus status) {
}];
NSLog(@"------ requestIDFA---14.0-------");
}else
{
NSLog(@"------调用 requestIDFA----14.0yixia----------");
}
[[AdmobManger sharedSingleton] UMPStart];
}
+ (void)test2WithParm1:(NSString *)parm1 andParm2:(NSString *)parm2 {
NSLog(@"------调用 test2WithParm1----------");
//以下是您想要开发的功能
//[[AdmobManger sharedSingleton] ShowBannerAd];
}
- (void) callCocos {
// std::string jsCallStr;
// std::string testString1 =[@"testString1" UTF8String];
// std::string testString2 = [@"testString2" UTF8String];
// jsCallStr = cocos2d::StringUtils::format("receiveNative(\"%s\",\"%s\");", testString1.c_str(), testString2.c_str());
// se::Value *ret = new se::Value();
// se::ScriptEngine::getInstance()->evalString(jsCallStr.c_str() , -1 , ret);
}
@end
ObjectToJs.h
//回掉cocos接口
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface ObjectToJs : NSObject
+ (instancetype)sharedSingleton;
- (void)RewardUser;
@end
NS_ASSUME_NONNULL_END
ObjectToJs.mm
//object-x 调用cocos 注意得为.mm 且添加两个.h头文件 不然std 和se会报错
#import "ObjectToJs.h"
#import "cocos2d.h"
#import "cocos/scripting/js-bindings/jswrapper/SeApi.h"
@interface ObjectToJs()
@end
@implementation ObjectToJs
+ (instancetype)sharedSingleton {
static ObjectToJs *_sharedSingleton = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
//不能再使用alloc方法
//因为已经重写了allocWithZone方法,所以这里要调用父类的分配空间的方法
if (_sharedSingleton==nil) {
_sharedSingleton = [[super allocWithZone:NULL] init];
}
//[_sharedSingleton initDelegate];
//[_sharedSingleton checkTransaction];
});
return _sharedSingleton;
}
- (void) RewardUser
{
NSLog(@"-----ObjectToJs----RewardUser-------");
//可以理解为:调用 cc.find() 函数在场景中查找 Canvas 节点,在利用 getComponent() 函数获取该节点下 名为 game.ts 的脚本。最后调用 脚本中的成员函数 GetAward(),此函数有一个参数。
std::string jsCallStr = cocos2d::StringUtils::format("cc.find('ADS').getComponent('AdmobeToXode').RewardUser();");
//通过evalString执行上面的代码
se::ScriptEngine::getInstance()->evalString(jsCallStr.c_str());
}
@end
最后在AppController.m 中的application中添加初始化代码:?
//----------------Admob-----------start---------------------------------
NSLog(@"------初始化 Admob----------");
[[GADMobileAds sharedInstance] startWithCompletionHandler:nil];
//GDATTrackingIdfa *idfa=[GDATTrackingIdfa sharedSingleton];
//获取ui窗口
[[AdmobManger sharedSingleton] SetView:_viewController];
//---------------Admob-------end-------------------------------------
如果代码中出现??Use?of?'@import'?when?modules?are?disabled?
就改成#import?<GoogleMobileAds/GoogleMobileAds.h>
?4 .Cocos 调用Xcode (js调用Object-c)
建立AdmobeToXode ,注意名字得一样,因为在ObjectToJs.mm中已经写好了回掉
?AdmobeToXode
const {ccclass, property} = cc._decorator;
export let mgr: AdmobeToXode = null;
@ccclass
export default class AdmobeToXode extends cc.Component {
public static inst: AdmobeToXode = null;
onLoad() {
cc.game.addPersistRootNode(this.node);
AdmobeToXode.inst=this;
mgr = this;
console.log("------------------AdmobeToXode-------onLoad----------");
}
start()
{
console.log("------------------AdmobeToXode--------start---------");
console.log("AdmobeToXode "+cc.sys.localStorage.getItem("ShowATTracking"));
if (cc.sys.os === cc.sys.OS_IOS&&cc.sys.localStorage.getItem("ShowATTracking")==null) {
console.log("cocos---requestIDFA---");
cc.sys.localStorage.setItem("ShowATTracking",1);
//@ts-ignore
jsb.reflection.callStaticMethod("GDATTrackingIdfa","requestIDFA");
}
//this.schedule(this.ShowBannerad,0.5);
}
ShowBannerad()
{
if (cc.sys.os === cc.sys.OS_IOS)
{
console.log("cocos---ShowBannerad---");
//@ts-ignore
jsb.reflection.callStaticMethod("AdmobManger","ShowBannerAd");
}
}
ShowInterstitialAd()
{
this.node.on
if (cc.sys.os === cc.sys.OS_IOS)
{
console.log("cocos---ShowInterstitialAd---");
//@ts-ignore
jsb.reflection.callStaticMethod("AdmobManger","ShowInterstitialAd");
}
}
rewardAds=null;
targetAds=null;
ShowRewardedAd(reward:any,target: any)
{
this.rewardAds=reward;
this.targetAds=target;
if (cc.sys.os === cc.sys.OS_IOS)
{
console.log("cocos---ShowRewardedAd---");
//@ts-ignore
jsb.reflection.callStaticMethod("AdmobManger","ShowRewardedAd");
}
}
//奖励回掉提供给Xcode调用
RewardUser()
{
if (AdmobeToXode.inst.rewardAds!=null&&AdmobeToXode.inst.targetAds) {
AdmobeToXode.inst.rewardAds(AdmobeToXode.inst.targetAds);
}
}
}
调用展示
5.对应效果
不知道为啥,写的其他工程没问题,写的demo工程在xcode自带的模拟设备上会出现,
Admob-mobile[67079:2284898]?Failed?to?load?interstitial?ad?with?error:?Cannot?find?an?ad?network?adapter?with?the?name(s):?com.google.DummyAdapter.?Remember?to?link?all?required?ad?network?adapters?and?SDKs,?and?set?-ObjC?in?the?'Other?Linker?Flags'?setting?of?your?build?target.
然后就有的不能二次调用广告,正式设备上完全正常,目前未发现原因,后续发现再补充.
广告标识权限
UMP SDK,欧盟地区授权
插屏
?
视频?
??
?banner
|