5评论

Unity项目接入IOS的Admob Native(原生视频广告) IOS SDK

萧然 2018-11-24 2k浏览

想免费获取内部独家PPT资料库?观看行业大牛直播?点击加入腾讯游戏学院游戏开发行业精英群711501594

实现的功能与Unity项目接入Android的Admob Native(原生视频广告) SDK(二、AS导出aar)相同,但IOS的操作与Android完全不同,接入IOS的SDK大概实现流程是:

1.新建一个Unity项目,写好调用IOS的方法

2.导出Xcode工程,在Xcode中接入IOS的SDK

3.完成第2步操作后,会得到几个独立的Xcode文件,类似于Unity的package,其他项目需要时只要把这几个文件添加到项目就可以了

接下来将用大量的截图来说明整个流程,IOS将采用OC语言:

1. 先贴出Google链接,提前下载SDK和Demo

Google官方IOS Native广告说明:https://developers.google.com/admob/ios/rewarded-video

Google Native广告 IOS SDK下载:https://developers.google.com/admob/ios/download

Google Admob IOS Demo下载:  https://github.com/googleads/googleads-mobile-ios-examples

2. 新建一个Unity项目,创建一个Panel、一个C#脚本,脚本详细内容将附在文末

Unity调用IOS:
    //定义OC方法(与IOS的方法对应)
    [DllImport("__Internal")]
    private static extern void initNativeAd(string appId, string nativeAd, bool isVideoStartMute);
    //C#调用IOS
    void InitNativeIOS(string appId, string nativeAd, bool isVideoStartMute)
    {
        initNativeAd(appId, nativeAd, isVideoStartMute);
    }

3. 设置好PlayerSettings后导出到Xcode工程

4. 打开刚刚导出的Xcode工程

4.1 添加Admob IOS SDK,这里用的是GoogleMobileAdsSdkiOS-7.35.2

选择"Frameworks"文件夹右键"Add Files"

选择"GoogleMobileAds.framework",勾选"Copy items if needed",将SDK的库文件添加到工程

添加完成后

4.2 复制官方IOS Native Demo中的UI布局文件到项目

具体路径在Google下载的Demo文件夹下:

跟4.1操作一样,选择"Classes"文件夹右键"Add Files",添加"UnifiedNativeAdView.xib"文件到项目

将适配方式改为"Freeform" ,xib文件的UI布局及其他设置,可以根据实际需求再做一些修改

4.3 新建 .h 和 .m 文件

选择 .m 文件

命名为"NativeAdController"(类名)

保存到"Classes"下

.h 文件与 .m 文件创建方式一样,且需要与 .m 文件同名

两个文件创建完成后:

5. 仿照官方Demo中的"ViewController"类,修改"NativeAdController"类(即刚刚创建的.h和.m文件)

代码说明都加到注释了,附在文末 ~

6. 运行到手机看一下效果,视频广告正常显示,完美~

到这里大部分工作已经完成了,可以在Xcode工程中获取以下三个文件,对于正式项目,只需在Unity中写好调用方法,导出Xcode工程,将SDK和这三个文件添加到Xcode工程里,就可以正常加载显示Native广告了。

也可以在Unity中导入Unity的SDK,然后将这三个文件放到Unity项目中,导出Xcode时会自动加入这三个文件,这样在Xcode就不需要额外的操作了,直接出包即可。

-----------------------------

附一:

Unity中C#调用IOS的OC方法:

NativeAdController C#

using UnityEngine;
using System.Runtime.InteropServices;
using UnityEngine.UI;
public class NativeAdController : MonoBehaviour
{
    [SerializeField] Button showBtn;
    [SerializeField] Button hideBtn;
    string appIdIOS = "ca-app-pub-3940256099942544~1458002511";
    string nativeAdIdIOS = "ca-app-pub-3940256099942544/2521693316";
    bool nativeVideoAdStartMute = false;
    bool isInited = false;
    void Start()
    {
        showBtn.onClick.AddListener(() => { if (IsNativeReady()) ShowNative(0); });
        hideBtn.onClick.AddListener(HideNative);
        InitNative();
    }
    //----- public -----
    public void InitNative()
    {
        if (isInited)
            return;
        isInited = true;
        if (!string.IsNullOrEmpty(appIdIOS) && !string.IsNullOrEmpty(nativeAdIdIOS))
        InitNativeIOS(appIdIOS, nativeAdIdIOS, nativeVideoAdStartMute);
    }
    public bool IsNativeReady()
    {
        return IsNativeReadyIOS();
    }
    public void ShowNative(float positionParame)
    {
        if (positionParame < 0)
            positionParame = 0;
        else if (positionParame > 1)
            positionParame = 1;
        ShowNativeIOS(positionParame);
    }
    public void HideNative()
    {
        HideNativeIOS();
    }
    //----- IOS -----
    //定义OC方法
    [DllImport("__Internal")]
    private static extern void initNativeAd(string appId, string nativeAd, bool isVideoStartMute);
    [DllImport("__Internal")]
    private static extern bool isNativeAdReady();
    [DllImport("__Internal")]
    private static extern void showNativeAd(float positionParame);
    [DllImport("__Internal")]
    private static extern void hideNativeAd();
    //C#调用
    void InitNativeIOS(string appId, string nativeAd, bool isVideoStartMute)
    {
        initNativeAd(appId, nativeAd, isVideoStartMute);
    }
    bool IsNativeReadyIOS()
    {
        return isNativeAdReady();
    }
    void ShowNativeIOS(float positionParame)
    {
        showNativeAd(positionParame);
    }
    void HideNativeIOS()
    {
        hideNativeAd();
    }
}

IOS类:

NativeAdController.h

#import <UIKit/UIKit.h>
//声明,外部接口
@interface NativeAdController : UIViewController
@end
NativeAdController.m
//添加库引用
#import "NativeAdController.h"
#import <GoogleMobileAds/GoogleMobileAds.h>
//标记广告是否加载完成
static bool isNativeReady;
//Native广告类
static GADUnifiedNativeAd *curNativeAd;
//Native广告Id
static NSString *nativeAdUnit;
//广告视频是否静音播放
static bool videoStartMute;
//声明,类似于定义内部接口
@interface NativeAdController () <GADUnifiedNativeAdLoaderDelegate,
GADVideoControllerDelegate,
GADUnifiedNativeAdDelegate>
@property(nonatomic, strong) GADAdLoader *adLoader;
//广告界面
//@property(nonatomic, strong) GADUnifiedNativeAdView *nativeAdView;
@property (nonatomic,strong) GADUnifiedNativeAdView *myView;
@property(nonatomic, strong) NSLayoutConstraint *heightConstraint;
@end
//实现,与声明对应
@implementation NativeAdController
static NativeAdController *myAdController;
//----- C方法,供Unity调用 -----
//初始化广告,Unity传参
void initNativeAd(char *appId, char *nativeAd, bool isVideoStartMute)
{
    if(!myAdController)
        myAdController = [NativeAdController new];
    //C#的string不能直接转为OC的NSString,利用char转换
    NSString *ocAppId = [NSString stringWithUTF8String:appId];
    NSString *ocnativeAd = [NSString stringWithUTF8String:nativeAd];
    [myAdController initNative:ocAppId nativeAd:ocnativeAd isVideoStartMute:isVideoStartMute];
}
//广告是否已加载
bool isNativeAdReady()
{
    return [myAdController isNativeReady];
}
//展示广告界面
void showNativeAd(float positionParame)
{
    [myAdController showNative:positionParame];
}
//隐藏广告界面
void hideNativeAd()
{
    [myAdController hideNative];
}
//----- OC方法 -----
-(void)initNative:(NSString *)appId nativeAd:(NSString *)nativeAd isVideoStartMute:(bool)isVideoStartMute
{
    //初始化注册Native
    [GADMobileAds configureWithApplicationID:appId];
    nativeAdUnit = nativeAd;
    videoStartMute = isVideoStartMute;
    //获取"UnifiedNativeAdView.xib",即广告界面布局文件
    NSArray *nibObjects = [[NSBundle mainBundle] loadNibNamed:@"UnifiedNativeAdView" owner:nil options:nil];
    self.myView = (GADUnifiedNativeAdView *)nibObjects.firstObject;
    //初始化设置广告界面在屏幕的位置
    CGFloat kscreenW = [UIScreen mainScreen].bounds.size.width;
    CGFloat kscreenH = [UIScreen mainScreen].bounds.size.height;
    self.myView.frame = CGRectMake(0, kscreenH - 275, kscreenW, 275);
    //    [self.view addSubview:self.myView];
    [UnityGetGLView() addSubview:self.myView];
    //隐藏广告界面
    [self.myView setHidden:YES];
    //请求广告
    [self refreshAd];
}
-(Boolean) isNativeReady
{
    //外部获取广告状态时,如果未加载,请求广告
    if(!isNativeReady)
    {
        [self refreshAd];
    }
    return isNativeReady;
}
-(void) showNative:(float) positionParame
{
    if(isNativeReady)
    {
        //刷新广告界面
        [self showNativeAdView:positionParame];
        //显示广告界面
        [self.myView setHidden:NO];
    }
}
-(void) hideNative
{
    //隐藏广告界面
    [self.myView setHidden:YES];
    //请求广告
    [self refreshAd];
}
//----------
- (void)refreshAd {
    isNativeReady = false;
    //请求广告
    GADVideoOptions *videoOptions = [[GADVideoOptions alloc] init];
    videoOptions.startMuted = videoStartMute;
    self.adLoader = [[GADAdLoader alloc] initWithAdUnitID:nativeAdUnit
                                       rootViewController:self
                                                  adTypes:@[ kGADAdLoaderAdTypeUnifiedNative ]
                                                  options:@[ videoOptions ]];
    self.adLoader.delegate = self;
    //发送请求
//    //测试使用
//    GADRequest *request = [GADRequest request];
//    request.testDevices = @[@"9c8cbe613c43e2997f2dd0620fb6deb7"];
//    [self.adLoader loadRequest:request];
    //正式使用
    [self.adLoader loadRequest: [GADRequest request]];
}
//设置星级
- (UIImage *)imageForStars:(NSDecimalNumber *)numberOfStars {
    double starRating = numberOfStars.doubleValue;
    if (starRating >= 5) {
        return [UIImage imageNamed:@"stars_5"];
    } else if (starRating >= 4.5) {
        return [UIImage imageNamed:@"stars_4_5"];
    } else if (starRating >= 4) {
        return [UIImage imageNamed:@"stars_4"];
    } else if (starRating >= 3.5) {
        return [UIImage imageNamed:@"stars_3_5"];
    } else {
        return nil;
    }
}
//加载失败回调
#pragma mark GADAdLoaderDelegate implementation
- (void)adLoader:(GADAdLoader *)adLoader didFailToReceiveAdWithError:(GADRequestError *)error {
    NSLog(@"%@ failed with error: %@", adLoader, error);
}
//加载成功回调
#pragma mark GADUnifiedNativeAdLoaderDelegate implementation
- (void)adLoader:(GADAdLoader *)adLoader didReceiveUnifiedNativeAd:(GADUnifiedNativeAd *)nativeAd {
    curNativeAd = nativeAd;
    isNativeReady = true;
}
//刷新广告界面
-(void)showNativeAdView:(float)positionParame
{
    if(curNativeAd!= nil)
    {
        GADUnifiedNativeAdView *nativeAdView = self.myView;
        //设置广告界面在屏幕的位置
        CGFloat kscreenW = [UIScreen mainScreen].bounds.size.width;
        CGFloat kscreenH = [UIScreen mainScreen].bounds.size.height;
        nativeAdView.frame = CGRectMake(0, (kscreenH - 265) * (1-positionParame), kscreenW, 265);
        // Deactivate the height constraint that was set when the previous video ad loaded.
        self.heightConstraint.active = NO;
        nativeAdView.nativeAd = curNativeAd;
        // Set ourselves as the ad delegate to be notified of native ad events.
        curNativeAd.delegate = self;
        //根据广告返回值刷新UI界面
        // Populate the native ad view with the native ad assets.
        // Some assets are guaranteed to be present in every native ad.
        ((UILabel *)nativeAdView.headlineView).text = curNativeAd.headline;
        ((UILabel *)nativeAdView.bodyView).text = curNativeAd.body;
        [((UIButton *)nativeAdView.callToActionView)setTitle:curNativeAd.callToAction
                                                    forState:UIControlStateNormal];
        // Some native ads will include a video asset, while others do not. Apps can
        // use the GADVideoController's hasVideoContent property to determine if one
        // is present, and adjust their UI accordingly.
        if (curNativeAd.videoController.hasVideoContent) {
            // This app uses a fixed width for the GADMediaView and changes its height
            // to match the aspect ratio of the video it displays.
            if (curNativeAd.videoController.aspectRatio > 0) {
                self.heightConstraint =
                [NSLayoutConstraint constraintWithItem:nativeAdView.mediaView
                                             attribute:NSLayoutAttributeHeight
                                             relatedBy:NSLayoutRelationEqual
                                                toItem:nativeAdView.mediaView
                                             attribute:NSLayoutAttributeWidth
                                            multiplier:(1 / curNativeAd.videoController.aspectRatio)
                                              constant:-10];
                self.heightConstraint.active = YES;
            }
            // By acting as the delegate to the GADVideoController, this ViewController
            // receives messages about events in the video lifecycle.
            curNativeAd.videoController.delegate = self;
            //    self.videoStatusLabel.text = @"Ad contains a video asset.";
        } else {
            //    self.videoStatusLabel.text = @"Ad does not contain a video.";
        }
        // These assets are not guaranteed to be present, and should be checked first.
        ((UIImageView *)nativeAdView.iconView).image = curNativeAd.icon.image;
        if (curNativeAd.icon != nil) {
            nativeAdView.iconView.hidden = NO;
        } else {
            nativeAdView.iconView.hidden = YES;
        }
        ((UIImageView *)nativeAdView.starRatingView).image = [self imageForStars:curNativeAd.starRating];
        if (curNativeAd.starRating) {
            nativeAdView.starRatingView.hidden = NO;
        } else {
            nativeAdView.starRatingView.hidden = YES;
        }
        ((UILabel *)nativeAdView.storeView).text = curNativeAd.store;
        if (curNativeAd.store) {
            nativeAdView.storeView.hidden = NO;
        } else {
            nativeAdView.storeView.hidden = YES;
        }
        ((UILabel *)nativeAdView.priceView).text = curNativeAd.price;
        if (curNativeAd.price) {
            nativeAdView.priceView.hidden = NO;
        } else {
            nativeAdView.priceView.hidden = YES;
        }
        ((UILabel *)nativeAdView.advertiserView).text = curNativeAd.advertiser;
        if (curNativeAd.advertiser) {
            nativeAdView.advertiserView.hidden = NO;
        } else {
            nativeAdView.advertiserView.hidden = YES;
        }
        // In order for the SDK to process touch events properly, user interaction should be disabled.
        nativeAdView.callToActionView.userInteractionEnabled = NO;
    }
}
//广告视频播放完成回调
#pragma mark GADVideoControllerDelegate implementation
- (void)videoControllerDidEndVideoPlayback:(GADVideoController *)videoController {
    NSLog(@"Video playback has ended.");
}
//其他回调
#pragma mark GADUnifiedNativeAdDelegate
- (void)nativeAdDidRecordClick:(GADUnifiedNativeAd *)nativeAd {
    NSLog(@"%s", __PRETTY_FUNCTION__);
}
- (void)nativeAdDidRecordImpression:(GADUnifiedNativeAd *)nativeAd {
    NSLog(@"%s", __PRETTY_FUNCTION__);
}
- (void)nativeAdWillPresentScreen:(GADUnifiedNativeAd *)nativeAd {
    NSLog(@"%s", __PRETTY_FUNCTION__);
}
- (void)nativeAdWillDismissScreen:(GADUnifiedNativeAd *)nativeAd {
    NSLog(@"%s", __PRETTY_FUNCTION__);
}
- (void)nativeAdDidDismissScreen:(GADUnifiedNativeAd *)nativeAd {
    NSLog(@"%s", __PRETTY_FUNCTION__);
}
- (void)nativeAdWillLeaveApplication:(GADUnifiedNativeAd *)nativeAd {
    NSLog(@"%s", __PRETTY_FUNCTION__);
}
@end 
附二:

1. 关于OC语言
OC与C的交互,OC中方法/函数的声明、实现、传参、调用,如果像我一样对OC不熟悉,可能会遇到一些意想不到的问题

2. 关于storyboard、xib UI布局文件
对于"UnifiedNativeAdView.xib"布局文件,IOS的UI布局与Android有些相似,不过与Unity相差较大 ,如果需要可以对xib文件进行一些修改,甚至自己创建一个xib文件

在此要感谢一位做IOS的朋友,提供了特别大的帮助。发现问题所在并找到有效的解决途径可以节省很多不必要的时间浪费,如果大家对于Unity和IOS的交互有任何见解或建议,欢迎一起交流~~~