使用c++开发Admob可以构建跨平台的广告集成体验,不用为不同平台编写原生语言的广告集成代码,也更加方便纯native开发的软件进行广告植入。通过官方教程和demo的研究, 踩了若干坑之后,终于在native code构建的游戏里顺利集成了c++接口的Admob。文本将会详细介绍,集成过程和遇到的问题及解决方法。
首先,查看官方教程。注意点,不要看中文的页面介绍,因为版本配置包括sdk下载链接都落后于英文版本,可能会导致配置不成功。
Android studio 的配置说明 https://firebase.google.com/docs/android/setup,主要有三个地方需要我们设置。
1. 到 Firebase console控制台创建应用,然后下载google-services.json文件,放到Android stuido app根目录下面。
2. 配置Project级别的Gradle的路径依赖。
3. 配置app级别的Gradle的编译依赖。
这里只使用了admob,所以只依赖一个firebase-asd,其它的功能参看文档给的Available libraries依赖表。需要注意的是,apply plugin 需要在最后一行。
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Firebase C++ SDK 的配置,https://firebase.google.com/docs/cpp/setup,主要有四点需要我们配置。
1. 下载 Firebase C++ SDK , 官方文档给了最新的版本。查看各个功能对库的依赖Dependencies,比如Admob依赖libapp.a和libadmob.a。后面说明如何配置这两个库文件。
2. 配置Firebase SDK的目录在Android stuido里的定位。文档仅仅给出了一句话,systemProp.firebase_cpp_sdk.dir=~/your_local_firebase_sdk_dir 配置在 gradle.properties 文件里。然后我发现并不起作用,查看了官方的demofirebase/quickstart-cpp 是NDK-build的模式。经过我的摸索找到了cmake的配置方法如下。我们需要手动添加project.ext属性。
3. 配置 ProGuard 混淆代码的配置,我们需要针对需要的库文件配置,否则无法正确运行。经过上一步的配置,就可以正确找到firebase sdk的文件位置了。需要注意的是release, debug都需要加入ProGuard配置。
4. 最后需要在cmake配置中,加入我们依赖的库文件。libapp.a 和 libadmob.a。
##################################################################### add_library( firebase_app STATIC IMPORTED ) set_target_properties( firebase_app PROPERTIES IMPORTED_LOCATION ${FIREBASE_CPP_SDK_DIR}/libs/android/${ANDROID_ABI}/c++/libapp.a ) ##################################################################### add_library( firebase_admob STATIC IMPORTED ) set_target_properties( firebase_admob PROPERTIES IMPORTED_LOCATION ${FIREBASE_CPP_SDK_DIR}/libs/android/${ANDROID_ABI}/c++/libadmob.a ) ##################################################################### include_directories( ../../../ ${FIREBASE_CPP_SDK_DIR}/include/ ../ ) ##################################################################### add_library( FireBaseTool STATIC ../FireBaseTool.cpp ) target_link_libraries( FireBaseTool firebase_admob firebase_app ) 我们可以看到FIREBASE_CPP_SDK_DIR目录,有多个STL版本的库文件。这里我写死了c++文件夹目录。也可以执行配置,后面说明。这里,我建立了一个工具类FireBaseTool,专门用来控制广告展示的,编译成一个库文件,在链接进入项目的库中。
//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
另外,在cmake配置中,使用了FIREBASE_CPP_SDK_DIR的目录设置,需要在Gradle文件里面进行配置的。
-DANDROID_STL=c++_static 就是配置STL类型使用的配置,只是我在cmake里写死了c++。
通过以上配置,就可以在Android studio里面使用c++来展示Admob广告了。
我们看代码如何使用。首先,我们可以参看官方demo给出的代码示例,https://github.com/firebase/quickstart-cpp/blob/master/admob/testapp/src/common_main.cc。
其次,给出我的一个封装,仅仅是插页广告的展示。
// // Created by scott.cgi // #include <android/native_activity.h> #include "FireBaseTool.h" #include "firebase/admob.h" extern ANativeActivity* nativeActivity; static const char* kAdMobAppID = "Admob应用的Id"; static const char* kInterstitialAdUnit = "广告单元的Id"; static const char* kTestDeviceIds[] = {"测试手机的Id, 在logcat中可以找到链接手机的Id"}; static firebase::admob::InterstitialAd* interstitialAd; static firebase::admob::AdRequest adRequest; static void OnLoadCompletion(const firebase::Future<void>& future, void* user_data) { if (future.Error() == firebase::admob::kAdMobErrorNone) { interstitialAd->Show(); } } static void OnInitCompletion(const firebase::Future<void>& future, void* user_data) { if (future.Error() == firebase::admob::kAdMobErrorNone) { interstitialAd->LoadAd(adRequest); // interstitialAd->LoadAdLastResult().OnCompletion(OnLoadCompletion, NULL); } } static void Init() { JNIEnv* env; nativeActivity->vm->AttachCurrentThread(&env, nullptr); // create the firebase app firebase::App* app = firebase::App::Create ( firebase::AppOptions(), env, nativeActivity->clazz ); // init the AdMob library. firebase::admob::Initialize(*app, kAdMobAppID); //-------------------------------------------------------------------------------------------------- interstitialAd = new firebase::admob::InterstitialAd(); interstitialAd->Initialize(static_cast<firebase::admob::AdParent>(nativeActivity->clazz), kInterstitialAdUnit); interstitialAd->InitializeLastResult().OnCompletion(OnInitCompletion, NULL); //-------------------------------------------------------------------------------------------------- adRequest.gender = firebase::admob::kGenderUnknown; adRequest.tagged_for_child_directed_treatment = firebase::admob::kChildDirectedTreatmentStateUnknown; // adRequest.test_device_id_count = sizeof(kTestDeviceIds) / sizeof(kTestDeviceIds[0]); // adRequest.test_device_ids = kTestDeviceIds; //-------------------------------------------------------------------------------------------------- } static bool isShown = false; static void Show() { if ( interstitialAd->LoadAdLastResult().Status() == firebase::kFutureStatusComplete && interstitialAd->LoadAdLastResult().Error() == firebase::admob::kAdMobErrorNone ) { isShown = true; interstitialAd->Show(); } } static void Refresh() { if (isShown) { isShown = false; interstitialAd->LoadAd(adRequest); } } struct AFireBaseTool AFireBaseTool[1] = { Init, Show, Refresh, };关于API的使用和功能参看官方文档,https://firebase.google.com/docs/admob/cpp/quick-start。
需要注意的是,firebase创建app的时候,参数 JNIEnv* env 需要的是从当前线程新获得的,而不是 nativeActivity 自己的那个成员变量 env.
JNIEnv* env; nativeActivity->vm->AttachCurrentThread(&env, nullptr); // create the firebase app firebase::App* app = firebase::App::Create ( firebase::AppOptions(), env, nativeActivity->clazz );
