返回博客首页
← 所有文章

使用 AdMob 货币化您的 NativeScript 应用(第 1 部分 - iOS)

2015 年 11 月 27 日 — 作者:Nikolay Diyanov

整个世界都在转向移动化,软件趋势也是如此。但是,到底是什么原因促使人们创建移动应用呢?好吧,当然,当事情变得严肃起来,在“仅仅是为了测试和娱乐”的阶段之后,一切都是为了赚钱。您可以为公司员工或其他人的员工创建应用(B2E、B2B)。在这种情况下,您的公司可以直接从为其员工提供的服务中获益,或者从您创建的应用中获得佣金。但是,如果您的客户是最终用户(B2C),或者您为一家企业客户创建应用,而该企业客户会将其出售给大众,那么您肯定应该了解不同的应用货币化方法,其中两种主要方法是应用内购买和移动广告。

今天,我们将讨论移动广告以及如何使用 Google AdMob 服务和 SDK 在您的 NativeScript 应用程序中启用它们。本文将重点介绍 iOS,在下一部分中,我们将介绍 Android 平台。

googleads-bannerview googleads-interstitial


对于许多场景,NativeScript 已经被现有的 NPM 插件所覆盖,这些插件甚至在 NativeScript 项目开始之前就已经创建了。并且,还有一些 专门为 NativeScript 编写的插件来解决特定的原生场景,其中一些插件已获得我们的正式批准,并在 已验证的插件市场 中列出。

插件的数量很多,但场景的数量总是更多,因此不可避免地会有一些功能没有被插件覆盖。对于这些情况,NativeScript 的一个非常酷的功能发挥了作用——它能够直接使用 iOS(或 Android)库的原生 API 及其 JavaScript 形式,无需任何预构建的包装器或其他内容。您只需查阅该所需功能的文档,遵循一些规则将原生代码转换为 JavaScript,瞧,您就进入了游戏。

因此,遵循现有的技术 AdMob 文档,今天我们将把广告插入我们的 NativeScript 应用中。

当然,为此您需要一个 AdMob 帐户。我们的布道师 Jen Looper 在其博客的前半部分有一篇关于使用 AdMob 帐户的不错的演练:Make it Rain!使用 Cordova 插件货币化您的移动应用

从技术上讲,我们将重点关注以下两种类型的广告
  • 横幅广告 - 这是通常在整个应用生命周期内显示在应用底部的视图。
  • 插页式广告 - 这些广告出现在应用生命周期的特定时刻,占据整个设备屏幕。最终用户可以通过点击关闭按钮将其关闭。

CocoaPods 集成

适用于 iOS 的 Google 移动广告 SDK 以简单框架库文件或通过 CocoaPods 的方式分发。CocoaPods 绝对是获取 iOS 库的现代且首选的方式,因此我们将使用此方法。为了让您更容易操作,我创建了 一个非常简单的 NPM 插件,它只是通过 CocoaPods 加载 Google 移动广告 SDK

使用 CLI

为了演示目的,我们将从默认的 CLI 应用项目模板开始。要从该模板创建应用,只需在终端中执行以下命令

tns create googleadmobproject

然后,让我们导航到该项目的根目录

cd googleadmobproject

并运行以下命令安装插件

tns plugin add nativescript-google-mobile-ads

这会将原生库安装到适当的位置,以便您可以立即开始使用 JavaScript 在其之上进行编码。

使用 AppBuilder IDE

除了命令行界面工具之外,您还可以使用 Telerik 提供的用于构建 NativeScript 应用的 AppBuilder IDE。AppBuilder IDE 在 Telerik 云中构建应用,因此实际上不需要 Mac 即可构建 iOS 应用。由于构建发生在云中,因此无需设置其他 SDK 和工具。关于在插件中使用 AppBuilder 的专用博客文章将在稍后发布。现在,您可以 从此处获取免费的 Telerik Platform 试用版,并探索如何按照“入门”>“交互式教程”链接(位于 Telerik Platform 顶部菜单栏)创建 NativeScript 应用。


使用横幅广告

框架已设置,使用 CLI 或 AppBuilder,现在是编码时间,我们将从编码横幅广告开始。

首先,让我们定义我们的布局。由于我们的原生移动广告功能周围没有任何通用的 JS 包装器代码,因此我们可以使用 占位符 组件直接使用应该显示广告的原生视图。此占位符应停靠在屏幕底部,其余内容填充剩余区域,因此,让我们将其全部放入 DockLayout 中。从默认 CLI 应用模板开始的结果将是

<Page xmlns="http://schemas.nativescript.org/tns.xsd" loaded="pageLoaded">
    <DockLayout>
        <Placeholder dock="bottom" creatingView="creatingView" id="bannerView"/>
        <StackLayout dock="top">
            <Label text="点击按钮" class="title"/>
            <Button text="点击" tap="{{ tapAction }}" />
            <Label text="{{ message }}" class="message" textWrap="true"/>
        </StackLayout>
    </DockLayout>
</Page>

我们可以在 XML 中这样定义占位符(因此是横幅视图)的高度

<Placeholder dock="bottom" height=”50” creatingView="creatingView" id="bannerView"/>

但是,让我们在 main-page.js 文件中使用 Google 推荐的横幅视图高度常量来定义高度。我们应该在使用其 initWithAdSize 初始化器创建原生 BannerView 对象时这样做。并且,所有这些都应该发生在 creatingView 方法中,该方法在占位符应该确定它应该表示哪个对象时被调用

function creatingView(args) {
    if(platformModule.device.os == platformModule.platformNames.ios) {
        bannerView = GADBannerView.alloc().initWithAdSize(kGADAdSizeSmartBannerPortrait);
        args.view = bannerView;
    }
    else {}
}
 
exports.creatingView = creatingView;

此外,正如您从上面的 XML 中注意到的那样,我们使用 pageLoaded 方法处理 Page 的加载事件,以设置一些对已创建的 BannerView 属性至关重要的属性

function pageLoaded(args) {
    var page = args.object;
    page.bindingContext = vmModule.mainViewModel;
 
    var placeholder = page.getViewById("bannerView");
    var bannerView;
 
    if(platformModule.device.os == platformModule.platformNames.ios) {
        bannerView = placeholder.ios;
        bannerView.adUnitID = "ca-app-pub-3940256099942544/2934735716";
        bannerView.strongDelegateRef = bannerView.delegate = GADBannerViewDelegateImpl.new();
        bannerView.rootViewController = page.ios;
        var request = GADRequest.request();
        request.testDevices = [kGADSimulatorID];
        bannerView.loadRequest(request);
    }
    else {}
}

这些内容包括分配给您帐户的广告单元 ID(此处我们使用测试 ID)、rootViewController(将其视为应用程序的最主页面框架)、被视为测试设备的设备(否则,Google 可能会施加处罚,包括暂停帐户),以及实际请求广告以在横幅视图中投放和显示的请求。

您还可以注意到,我们正在设置一个委托,它将启用一些在广告生命周期中调用的回调方法。但是我们还没有创建启用这些回调的委托类型。现在让我们来创建它。

if(platformModule.device.os == platformModule.platformNames.ios) {
    var GADBannerViewDelegateImpl = (function (_super) {
        __extends(GADBannerViewDelegateImpl, _super);
        function GADBannerViewDelegateImpl() {
            _super.apply(this, arguments);
        }
        GADBannerViewDelegateImpl.prototype.adViewWillLeaveApplication = function (bannerView) {
            // 当用户由于点击广告而离开应用程序时执行某些操作
            console.log("Leaving the app, bye bye!");
        };
        GADBannerViewDelegateImpl.ObjCProtocols = [GADBannerViewDelegate];
        return GADBannerViewDelegateImpl;
    })(NSObject);
}

正如AdMob 文档中所述,委托支持的方法很少。

如您所见,出于测试目的,我们利用了 *adViewWillLeaveApplication* 方法,该方法在用户由于点击广告而离开应用程序时被调用。

好吧,实际上就是这样,如此简单,如此容易。以下是应用程序的外观和行为。




您可以在 GitHub 上找到使用横幅广告的完整 NativeScript 项目。

使用插页式广告

插页式广告……啊,这些广告会意外地从底部到顶部出现,就像它们正在炸毁您的应用程序一样,破坏了最终用户对您应用程序的良好感觉和好感。无论您是否喜欢,这种广告类型也很受欢迎,并且如果在适当的时机使用,例如在两个游戏关卡之间,可以为您带来收益。

现在让我们看看如何实现插页式广告。它与横幅广告并没有太大区别,但我们不会在任何 XML 布局中包含插页式视图,因为插页式广告将使用原生方法调用显示。

在本演示中,我们将使用 CLI 应用程序模板提供的按钮,在简单的按钮点击上调用插页式广告。

让我们创建一个创建插页式广告的方法,因为我们可能希望在应用程序生命周期中显示几次插页式广告。

function createAndLoadiOSInterstitial() {
    var interstitial = GADInterstitial.alloc().initWithAdUnitID("ca-app-pub-3940256099942544/4411468910");
    var request = GADRequest.request();
    interstitial.strongDelegateRef = interstitial.delegate = frameModule.topmost().currentPage.delegate;
    request.testDevices = [kGADSimulatorID];
    interstitial.loadRequest(request);
 
    return interstitial;
}
 
exports.createAndLoadiOSInterstitial = createAndLoadiOSInterstitial;

与横幅视图一样,我们正在设置 *AdUnitID*、用于测试的设备,以及请求显示广告的请求。您还可以看到,我们正在设置一个委托(在 pageLoaded 方法中实例化),以启用在广告生命周期中调用的几个回调方法的使用。以下是应如何定义委托类型。

if(platformModule.device.os == platformModule.platformNames.ios) {
    var GADInterstitialDelegateImpl = (function (_super) {
        __extends(GADInterstitialDelegateImpl, _super);
        function GADInterstitialDelegateImpl() {
            _super.apply(this, arguments);
        }
        GADInterstitialDelegateImpl.prototype.interstitialDidDismissScreen = function (gadinterstitial) {
            frameModule.topmost().currentPage.interstitial = createAndLoadiOSInterstitial();
        };
        GADInterstitialDelegateImpl.ObjCProtocols = [GADInterstitialDelegate];
        return GADInterstitialDelegateImpl;
    })(NSObject);
}

这里需要注意的一个重要的回调方法是 *interstitialDidDismissScreen*,当用户点击已显示的插页式广告的关闭按钮时会调用此方法。根据 AdMob 文档,请求插页式广告的推荐方法是在关闭先前显示的插页式广告时进行,从而确保您的插页式广告始终准备显示。

说到准备就绪,让我们在页面的加载事件上加载一个插页式广告,以便在第一次点击按钮时它已准备就绪。

var frameModule = require("ui/frame");
 
function pageLoaded(args) {
    var page = args.object;
    page.bindingContext = vmModule.mainViewModel;
     
    if(platformModule.device.os == platformModule.platformNames.ios) {
        frameModule.topmost().currentPage.delegate = GADInterstitialDelegateImpl.new();
        frameModule.topmost().currentPage.interstitial = createAndLoadiOSInterstitial();
    }
    else {}
}
 
exports.pageLoaded = pageLoaded;

请注意,我们正在将从 *createAndLoadiOSInterstitial* 返回的插页式对象设置为当前页面的属性。我们为什么要这样做?首先,我们需要在 main-page 中全局访问插页式对象。因此,我们可以将其全局定义。是的,但根据场景,这可能会导致潜在的内存泄漏。因此,当您需要全局访问时,最佳方法是将其附加到该页面的控件或页面本身。

最后但并非最不重要的一点是,以下是按钮的点击事件实现,我们将在其中显示插页式广告(希望它已准备好显示)。

function buttonTapped(args) {
    var interstitial = frameModule.topmost().currentPage.interstitial;
 
    if(platformModule.device.os == platformModule.platformNames.ios) {
        if(interstitial.isReady) {
            interstitial.presentFromRootViewController(args.object.page.frame.ios.controller);
        }
    }
    else {}
}
 
exports.buttonTapped = buttonTapped;

结果如下



您可以在 GitHub 上找到使用插页式广告的完整 NativeScript 项目。

希望本文能帮助您了解在 NativeScript 应用程序中直接使用现有原生库并与之交互的便捷性,无需任何常见的 JS 包装器代码。尽管如此,鉴于 AdMob 服务的普及,我们可能会很快推出经过验证的 AdMob 插件。敬请期待!

有关 NativeScript 的更多信息和更新,请关注 @nativescript 推特 或关注 GitHub 上的 NativeScript 项目