八、添加本机 Java 代码
到目前为止,我们一直只使用编写 Cocos2d-x 游戏框架的编程语言(C++)来创建我们的游戏;尽管如此,Google 编写的 Android API 仅在应用程序的 Java 层可用。在本章中,您将学习如何使用 Java 本机接口 ( JNI )功能将我们的本机 C++ 代码与更高端的 Java 内核进行通信。
本章将涵盖以下主题:
- 了解安卓平台的 Cocos2d-x 结构
- 了解 JNI 的能力
- 将 Java 代码添加到 Cocos2d-x 游戏中
- 通过插入 Java 代码向游戏中添加广告
了解安卓平台的 Cocos2d-x 结构
在第 1 章、设置您的开发环境中,当我们正在安装构建 Cocos2d-x 框架所需的所有组件时,我们告诉您下载并安装 Android 原生开发工具包 ( NDK ),它允许我们使用 C++ 语言构建 Android 应用程序,而不是使用已经为其编写了 Android API 的主流 Java 技术核心。
当一个安卓应用程序启动时,它会在其AndroidManisfest.xml
文件中寻找一个具有意图过滤器android.intent.action.MAIN
的活动定义,然后它会运行 Java 类。下面的列表显示了由 Cocos 新脚本生成的AndroidManifest.xml
文件的片段,其中指定了 Android 应用程序启动时要启动的活动:
<activity
android:name="org.cocos2dx.cpp.AppActivity"
android:configChanges="orientation"
android:label="@string/app_name"
android:screenOrientation="portrait"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
Cocos2d-x 项目创建脚本创建了一个名为AppActivity
的 Java 类,它位于proj.android
目录下org.cocos2dx.cpp
Java 包名下的src
文件夹中。这个类没有主体,是从Cocos2dxActivity
类扩展而来的,我们可以在下面的代码清单中看到:
package org.cocos2dx.cpp;
import org.cocos2dx.lib.Cocos2dxActivity;
public class AppActivity extends Cocos2dxActivity {
}
Cocos2dxActivity
类在其onCreate
方法中加载本机 C++ 框架核心。
了解 JNI 的能力
JNI 在 C++ 代码和 Java 代码之间架起了一座桥梁。Cocos2d-x 框架为我们提供了一个 JNI 助手,这使得集成 C++ 代码和 Java 代码变得更加容易。
JniHelper
C++ 类有一个叫getStaticMethodInfo
的方法。它接收一个JniMethodInfo
对象作为参数,该对象存储调用相应的 Java 代码所需的所有数据、静态方法所在的类名、方法名及其签名。
为了找到 JNI 的方法签名,您可以使用javap
命令:例如,如果我们想知道AppActivity
类中包含的方法签名是什么,那么我们只需要打开一个控制台窗口,转到您的proj.android\bin\classes
目录,并键入以下命令:
SET CLASSPATH=.
javap -s org.cocos2dx.cpp.AppActivity
在这种特殊情况下,您将收到一个响应,为类自动创建的null
构造函数的签名如下:
Compiled from "AppActivity.java"
public class org.cocos2dx.cpp.AppActivity extends org.cocos2dx.lib.Cocos2dxActivity {
public org.cocos2dx.cpp.AppActivity();
Signature: ()V
}
然后,通过附加到JniMethodInfo
实例的属性env
,我们可以用该对象包含的一组方法调用 Java 方法,所有这些都从Call…
开始。在我们下一节要写的代码中,我们将使用CallStaticVoid
方法来调用一个不返回值的静态方法,顾名思义。请注意,如果您想要传递一个 Java 字符串作为参数,那么您将需要调用env
属性的NewStringUTF
方法,传递const char*
,它将返回一个jstring
实例,您可以使用该实例传递给一个接收字符串的 Java 方法,如下面的代码清单所示:
JniMethodInfo method;
JniHelper::getStaticMethodInfo(method, CLASS_NAME,"showToast","(Ljava/lang/String;)V");
jstring stringMessage = method.env->NewStringUTF(message);
method.env->CallStaticVoidMethod(method.classID, method.methodID, stringMessage);
最后,如果您已经在 C++ 代码中创建了jstring
或任何其他 Java 抽象类的实例,那么请确保在将值传递给 Java 核心后删除这些实例,这样我们就不会在内存中有不必要的引用。这可以通过调用位于JniMethodInfo
实例的env
属性中的DeleteLocalRef
方法并传递您想要移除的 Java 抽象引用来实现:
method.env->DeleteLocalRef(stringMessage);
本节中公开的概念将应用于下一节中的代码清单。
在 Cocos2d-x 游戏中添加 Java 代码
现在我们将在这两种技术之间创建一个简单的集成,这将允许我们的 Cocos2d-x C++ 游戏使用 Android Java API 显示祝酒信息。
注
安卓系统中的祝酒词是一个弹出消息,显示指定的时间,没有在预定义时间之前隐藏的选项。本节末尾的截图显示了敬酒信息的样子。
Cocos2d-x 在一个 Java 活动中运行,因此为了显示原生的 Android toast 消息,我们将创建一个 Java 类,该类将有一个名为showToast
的静态方法。这会收到一个字符串,然后它会在祝酒词中显示出来。为了访问 Cocos2d-x 游戏活动,我们将向该类添加一个类型为Activity
的静态属性,并在被覆盖的onCreate
方法中初始化它。然后,我们将创建一个公共静态方法,允许我们从 Java 代码中的任何地方访问这个实例。经过这些修改后,我们的AppActivity
Java 类代码将如下所示:
package org.cocos2dx.cpp;
import org.cocos2dx.lib.Cocos2dxActivity;
import android.app.Activity;
import android.os.Bundle;
public class AppActivity extends Cocos2dxActivity {
private static Activity instance;
@Override
protected void onCreate(final Bundle savedInstanceState) {
instance = this;
super.onCreate(savedInstanceState);
}
public static Activity getInstance(){
return instance;
}
}
现在,让我们在我们的com.packtpub.jni
包中创建引用的JniFacade
Java 类,它的主体中只有一个接收字符串作为参数的静态 void 方法,然后用接收到的消息在 UI 线程上显示一个 toast,如下所示:
package com.packtpub.jni;
import org.cocos2dx.cpp.AppActivity;
import android.app.Activity;
import android.widget.Toast;
public class JniFacade {
private static Activity activity = AppActivity.getInstance();
public static void showToast(final String message) {
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(activity.getBaseContext(), message, Toast. LENGTH_SHORT).show();
}
});
}
}
现在我们的代码在 Java 端,让我们把JniBridge
C++ 类添加到我们的classes
文件夹中。
在JniBridge.h
头文件中,我们将写下以下内容:
#ifndef __JNI_BRIDGE_H__
#define __JNI_BRIDGE_H__
#include "cocos2d.h"
class JniBridge
{
public:
static void showToast(const char* message);
};
#endif
现在让我们创建实现文件JniBridge.cpp
,在这里我们将调用我们的静态 Java 方法showToast
,它接收一个字符串作为参数:
#include "JniBridge.h"
#define CLASS_NAME "com/packtpub/jni/JniFacade"
#define METHOD_NAME "showToast"
#define PARAM_CODE "(Ljava/lang/String;)V"
USING_NS_CC;
void JniBridge::showToast(const char* message)
{
JniMethodInfo method;
JniHelper::getStaticMethodInfo(method, CLASS_NAME, METHOD_NAME, PARAM_CODE);
jstring stringMessage = method.env->NewStringUTF(message);
method.env->CallStaticVoidMethod(method.classID, method.methodID, stringMessage);
method.env->DeleteLocalRef(stringMessage);
}
正如我们所看到的,这里我们使用了中与 Cocos2d-x 框架捆绑在一起的JniMethodInfo
结构和JniHelper
类,以便调用showToast
方法,并将我们的 C++ 代码中的 C 字符串发送给它,该字符串被转换为 Java 字符串。
现在让我们将我们的JniBridge.h
头文件包含在我们的HelloWorldScene.cpp
实现文件中,这样我们就可以从我们的主场景类中访问到 Java 代码的桥:
#include "JniBridge.h"
现在在位于HelloWorld.cpp
实现文件中的init
方法的末尾,我们将调用showToast
静态方法,以便使用 Android Java API 来显示本机吐司消息,显示从我们的 C++ 代码发送的文本如下:
JniBridge::showToast("Hello Java");
这将产生以下结果:
正如我们从前面的截图中可以欣赏到的,我们已经实现了从我们的 C++ 游戏逻辑代码中显示原生 Java toast 消息的目标。
通过插入 Java 代码为游戏添加广告
在前面的部分,我们已经使用 JNI 在我们的 C++ 游戏逻辑代码和我们的安卓应用的 Java 层之间创建了一个交互。在这一部分,我们将修改我们的安卓专用代码,以便在我们的安卓游戏中显示谷歌 AdMob 横幅。
注
AdMob 是一个谷歌平台,允许你通过显示广告将你的应用货币化,它也有分析工具,以及应用内购买的工具。
配置环境
为了显示谷歌 AdMob 横幅,我们需要将Google Play Services
库添加到我们的项目中。为了做到这一点,我们首先需要使用安卓软件开发工具包管理器下载它及其依赖项——安卓支持库:
成功下载谷歌游戏服务及其依赖项后,您需要将 Android.support.v4 添加到您的项目中,因为谷歌游戏服务库需要它。为此,我们将把位于以下路径上的android-support-v4.jar
文件复制到我们的安卓项目中包含的libs
文件夹中,然后我们将通过在 Eclipse 的包浏览器中右键单击我们的项目将其添加到我们的构建路径中,然后单击构建路径,然后单击配置构建路径。将显示 Java 构建路径配置窗口,点击添加 JARS… 按钮,在libs
文件夹中添加android-support-v4.jar
文件。
现在,我们将复制我们刚刚下载的谷歌游戏服务代码。这现在位于我们工作空间路径的<ADT PATH>\sdk\extras\google\google_play_services
上。通过右键单击您的 Eclipse Java 项目,然后单击属性,最后选择左侧的资源选项,您可以找到工作空间的路径;在那里你会看到位置信息,如下图截图所示:
我们已经建立了依赖关系,所以现在让我们添加谷歌游戏服务库,通过导航到文件 | 导入 | 安卓 | 现有安卓代码到工作区 | 浏览… 。然后,浏览到您从上一步复制谷歌游戏服务的位置。取消选择除google-play-services_lib
以外的所有项目,点击完成:
现在我们的工作区中有了google-play-services_lib
项目,让我们将其配置为我们的 Cocos2d-x 游戏项目的库。为此,我们将再次在包资源管理器上右键单击我们的项目,单击属性,单击左窗格中的安卓部分,然后在屏幕的底部下方,我们将单击添加… 按钮,以便将google-play-services_lib
库添加到我们的 Eclipse 项目中,如下图所示:
现在我们都准备好了,准备进入下一个部分,我们将使用刚刚添加的库来显示谷歌广告。
现在,我们的 AdMob 横幅将显示在屏幕顶部,我们现在将我们的静音按钮移动到底部,这样它就不会被横幅覆盖。我们将通过改变静音和非静音按钮的位置来实现这一点。我们现在将它的 y 组件设置为屏幕高度减去静音按钮高度的两倍,而不是将屏幕高度减去静音子画面高度的一半作为它的垂直位置,正如我们在initMuteButton
方法中的下面一行代码所示:
_muteItem->setPosition(Vec2(_visibleSize.width - _muteItem->getContentSize().width/2 ,_visibleSize.height - _muteItem->getContentSize().height * 2));
修改安卓清单
在这个部分,我们将修改我们的安卓清单,以便将其插入使用谷歌游戏服务库所需的配置中。
我们只需要添加两个片段,其中一个就在打开的应用程序标签旁边,该标签将指示正在使用的谷歌游戏服务的版本,我们可以从下面的代码清单中了解到:
<meta-data
android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version" />
我们要添加的第二个片段是AdActivity
声明,它将被添加到我们的游戏活动声明的旁边,这样我们的游戏就知道这个位于 Google Play Services 库中的内置活动:
<activity
android:name="com.google.android.gms.ads.AdActivity"
android:configChanges="keyboard|keyboardHidden|orientation| screenLayout|uiMode|screenSize|smallestScreenSize" />
添加 Java 代码
现在我们已经配置了库,并且修改了安卓清单,广告库已经可以使用了。我们要给我们的AppActivity
类添加一个 ad 初始化方法,在调用它的超类的实现之后再调用它。
为了下面的例子,我们将使用一个示例 AdMob 标识,您可以用自己的标识替换它。您可以在http://www.google.com/admob找到更多关于如何创建自己的 AdMob ID 的信息。
private void initAdMob() {
final String ADMOB_ID = "ca-app-pub-7870675803288590/4907722461";
final AdView adView;
final FrameLayout adViewLayout;
FrameLayout.LayoutParams adParams = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT);
adParams.gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL;
AdRequest adRequest = new AdRequest.Builder().
addTestDevice(AdRequest.DEVICE_ID_EMULATOR).
addTestDevice("E8B4B73DC4CAD78DFCB44AF69E7B9EC4").build();
adView = new AdView(this);
adView.setAdSize(AdSize.SMART_BANNER);
adView.setAdUnitId(ADMOB_ID);
adView.setLayoutParams(adParams);
adView.loadAd(adRequest);
adViewLayout = new FrameLayout(this);
adViewLayout.setLayoutParams(adParams);
adView.setAdListener(new AdListener() {
@Override
public void onAdLoaded() {
adViewLayout.addView(adView);
}
});
this.addContentView(adViewLayout, adParams);
}
与上一节相比,我们没有使用 JNI,因为我们根本没有与 C++ 代码交互;相反,我们正在修改由cocos
命令创建的安卓活动,以便添加更多的图形元素来查看模板中定义的 OpenGL E 视图的一面。
我们只是以编程方式创建了一个框架布局,并向其中添加了一个adView
实例;最后,我们将这个框架布局作为内容视图添加到游戏活动中,然后我们使用重力布局参数指定了它的期望位置,这就是我们最终能够在屏幕顶部显示谷歌广告的方式。请注意,您可以通过简单地修改布局参数来修改广告的位置,即您希望它显示的位置。
请注意在广告成功加载后,我们已经将adView
添加到框架布局中。通过使用AdListener
,如果在广告完成投放前添加了adView
实例,则不会显示。
这就是我们的谷歌 AdMob 在将一切联系在一起后的样子:
把所有东西放在一起
我们已经完成了在我们的 Cocos2d-x 游戏中嵌入核心 Java 代码的目标。现在我们将一起展示本章中修改过的游戏的所有部分。
这里,我们展示了我们从头开始创建的 C++ JNI 桥(JniBridge.h
)的头文件:
#ifndef __JNI_BRIDGE_H__
#define __JNI_BRIDGE_H__
#include "cocos2d.h"
class JniBridge
{
public:
static void showToast(const char* message);
};
#endif
既然我们已经定义了JniBridge
的头,那么让我们编写实现文件(JniBridge.cpp
):
#include "JniBridge.h"
#include "platform/android/jni/JniHelper.h"
#define CLASS_NAME "com/packtpub/jni/JniFacade"
#define METHOD_NAME "showToast"
#define PARAM_CODE "(Ljava/lang/String;)V"
USING_NS_CC;
void JniBridge::showToast(const char* message)
{
JniMethodInfo method;
JniHelper::getStaticMethodInfo(method, CLASS_NAME, METHOD_ NAME,PARAM_CODE);
jstring stringMessage = method.env->NewStringUTF(message);
method.env->CallStaticVoidMethod(method.classID, method.methodID, stringMessage);
method.env->DeleteLocalRef(stringMessage);
}
现在让我们看看我们的游戏类标题(HelloWorldScene.h
)在包含我们的JniBridge
之后是什么样子的:
#ifndef __HELLOWORLD_SCENE_H__
#define __HELLOWORLD_SCENE_H__
#include "cocos2d.h"
#include "PauseScene.h"
#include "GameOverScene.h"
#include "JniBridge.h"
class HelloWorld : public cocos2d::Layer
{
public:
static cocos2d::Scene* createScene();
virtual bool init();
void pauseCallback(cocos2d::Ref* pSender);
CREATE_FUNC(HelloWorld);
private:
cocos2d::Director *_director;
cocos2d::Size visibleSize;
cocos2d::Sprite* _sprBomb;
cocos2d::Sprite* _sprPlayer;
cocos2d::Vector<cocos2d::Sprite*> _bombs;
cocos2d::MenuItemImage* _muteItem;
cocos2d::MenuItemImage* _unmuteItem;
int _score;
int _musicId;
void initPhysics();
bool onCollision(cocos2d::PhysicsContact& contact);
void setPhysicsBody(cocos2d::Sprite* sprite);
void initTouch();
void movePlayerByTouch(cocos2d::Touch* touch, cocos2d::Event* event);
bool explodeBombs(cocos2d::Touch* touch, cocos2d::Event* event);
void movePlayerIfPossible(float newX);
void movePlayerByAccelerometer(cocos2d::Acceleration* acceleration, cocos2d::Event* event);
void initAccelerometer();
void initBackButtonListener();
void onKeyPressed(cocos2d::EventKeyboard::KeyCode keyCode, cocos2d::Event* event);
void updateScore(float dt);
void addBombs(float dt);
void initAudio();
void initAudioNewEngine();
void initMuteButton();
};
#endif // __HELLOWORLD_SCENE_H__
现在我们将向您展示HelloWorldScene.cpp
方法在本书最后一章的结尾是什么样子的:
#include "HelloWorldScene.h"
USING_NS_CC;
using namespace CocosDenshion;
using namespace cocos2d::experimental;
// User input handling code …
void HelloWorld::initMuteButton()
{
_muteItem = MenuItemImage::create("mute.png", "mute.png", CC_CALLBACK_1(HelloWorld::muteCallback, this));
_muteItem->setPosition(Vec2(_visibleSize.width - _muteItem->getContentSize().width/2 ,
_visibleSize.height - _muteItem->getContentSize().height * 2));
我们更改了静音按钮在代码中的位置,使其不被广告覆盖:
_unmuteItem = MenuItemImage::create("unmute.png", "unmute.png", CC_CALLBACK_1(HelloWorld::muteCallback, this));
_unmuteItem->setPosition(Vec2(_visibleSize.width - _unmuteItem->getContentSize().width/2 ,
_visibleSize.height - _unmuteItem->getContentSize().height *2));
_unmuteItem -> setVisible(false);
auto menu = Menu::create(_muteItem, _unmuteItem , nullptr);
menu->setPosition(Vec2::ZERO);
this->addChild(menu, 2);
}
// on "init" you need to initialize your instance
bool HelloWorld::init()
{
if ( !Layer::init() )
{
return false;
}
_score = 0;
_director = Director::getInstance();
visibleSize = _director->getVisibleSize();
auto origin = _director->getVisibleOrigin();
auto closeItem = MenuItemImage::create("CloseNormal.png", "CloseSelected.png", CC_CALLBACK_1(HelloWorld::pauseCallback, this));
closeItem->setPosition(Vec2(visibleSize.width - closeItem->getContentSize().width/2 , closeItem->getContentSize().height/2));
auto menu = Menu::create(closeItem, nullptr);
menu->setPosition(Vec2::ZERO);
this->addChild(menu, 1);
_sprBomb = Sprite::create("bomb.png");
_sprBomb->setPosition(visibleSize.width / 2, visibleSize.height + _sprBomb->getContentSize().height/2);
this->addChild(_sprBomb,1);
auto bg = Sprite::create("background.png");
bg->setAnchorPoint(Vec2());
bg->setPosition(0,0);
this->addChild(bg, -1);
_sprPlayer = Sprite::create("player.png");
_sprPlayer->setPosition(visibleSize.width / 2, visibleSize.height * 0.23);
setPhysicsBody(_sprPlayer);
this->addChild(_sprPlayer, 0);
//Animations
Vector<SpriteFrame*> frames;
Size playerSize = _sprPlayer->getContentSize();
frames.pushBack(SpriteFrame::create("player.png", Rect(0, 0, playerSize.width, playerSize.height)));
frames.pushBack(SpriteFrame::create("player2.png", Rect(0, 0, playerSize.width, playerSize.height)));
auto animation = Animation::createWithSpriteFrames(frames,0.2f);
auto animate = Animate::create(animation);
_sprPlayer->runAction(RepeatForever::create(animate));
setPhysicsBody(_sprBomb);
initPhysics();
_sprBomb->getPhysicsBody()->setVelocity(Vect(0,-100));
initTouch();
initAccelerometer();
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
setKeepScreenOnJni(true);
#endif
initBackButtonListener();
schedule(schedule_selector(HelloWorld::updateScore), 3.0f);
schedule(schedule_selector(HelloWorld::addBombs), 8.0f);
initAudioNewEngine();
initMuteButton();
_bombs.pushBack(_sprBomb);
JniBridge::showToast("Hello Java");
return true;
}
这就是我们的AppActivity.java
类经过所有修改后的样子:
package org.cocos2dx.cpp;
import org.cocos2dx.lib.Cocos2dxActivity;
import android.app.Activity;
import android.os.Bundle;
import android.view.Gravity;
import android.widget.FrameLayout;
import com.google.android.gms.ads.AdListener;
import com.google.android.gms.ads.AdRequest;
import com.google.android.gms.ads.AdSize;
import com.google.android.gms.ads.AdView;
public class AppActivity extends Cocos2dxActivity {
private static Activity instance;
private void initAdMob() {
final String ADMOB_ID = "ca-app-pub-7870675803288590/4907722461";
final AdView adView;
final FrameLayout adViewLayout;
FrameLayout.LayoutParams adParams = new FrameLayout. LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,FrameLayout.LayoutParams.WRAP_CONTENT);
adParams.gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL;
AdRequest adRequest = new AdRequest.Builder().
addTestDevice(AdRequest.DEVICE_ID_EMULATOR).
addTestDevice("E8B4B73DC4CAD78DFCB44AF69E7B9EC4").build();
adView = new AdView(this);
adView.setAdSize(AdSize.SMART_BANNER);
adView.setAdUnitId(ADMOB_ID);
adView.setLayoutParams(adParams);
adView.loadAd(adRequest);
adViewLayout = new FrameLayout(this);
adViewLayout.setLayoutParams(adParams);
adView.setAdListener(new AdListener() {
@Override
public void onAdLoaded() {
adViewLayout.addView(adView);
}
});
this.addContentView(adViewLayout, adParams);
}
@Override
protected void onCreate(final Bundle savedInstanceState) {
instance = this;
super.onCreate(savedInstanceState);
initAdMob();
}
public static Activity getInstance() {
return instance;
}
}
这就是我们的JniFacade.java
类文件在本章末尾的样子:包com.packtpub.jni
;
import org.cocos2dx.cpp.AppActivity;
import android.app.Activity;
import android.widget.Toast;
public class JniFacade {
private static Activity activity = AppActivity.getInstance();
public static void showToast(final String message) {
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(activity.getBaseContext(), message, Toast. LENGTH_SHORT).show();
}
}
}
}
这是我们在本章中添加JniBridge.cpp
文件后位于proj.android\jni
的Android.mk
文件的样子:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
$(call import-add-path,$(LOCAL_PATH)/../../cocos2d)
$(call import-add-path,$(LOCAL_PATH)/../../cocos2d/external)
$(call import-add-path,$(LOCAL_PATH)/../../cocos2d/cocos)
LOCAL_MODULE := cocos2dcpp_shared
LOCAL_MODULE_FILENAME := libcocos2dcpp
LOCAL_SRC_FILES := hellocpp/main.cpp \
../../Classes/JniBridge.cpp \
../../Classes/AppDelegate.cpp \
../../Classes/PauseScene.cpp \
../../Classes/GameOverScene.cpp \
../../Classes/HelloWorldScene.cpp
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../Classes
LOCAL_STATIC_LIBRARIES := cocos2dx_static
include $(BUILD_SHARED_LIBRARY)
$(call import-module,.)
最后,这就是我们的AndroidManifest.xml
文件在本书末尾的样子:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.packt.happybunny"
android:installLocation="auto"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="9" />
<uses-feature android:glEsVersion="0x00020000" />
<application
android:icon="@drawable/icon"
android:label="@string/app_name" >
<meta-data
android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version" />
<!-- Tell Cocos2dxActivity the name of our .so -->
<meta-data
android:name="android.app.lib_name"
android:value="cocos2dcpp" />
<activity
android:name="org.cocos2dx.cpp.AppActivity"
android:configChanges="orientation"
android:label="@string/app_name"
android:screenOrientation="portrait"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="com.google.android.gms.ads.AdActivity"
android:configChanges="keyboard|keyboardHidden|orientation| screenLayout|uiMode|screenSize|smallestScreenSize" />
</application>
<supports-screens
android:anyDensity="true"
android:largeScreens="true"
android:normalScreens="true"
android:smallScreens="true"
android:xlargeScreens="true" />
<uses-permission android:name="android.permission.INTERNET" />
</manifest>
总结
在本章中,我们已经看到了如何使用 JNI 添加我们的 C++ 游戏逻辑代码和安卓核心 Java 层之间的交互,我们还通过直接修改在调用cocos
命令期间创建的 Java Activity
类代码,在我们的游戏中显示了谷歌 AdMob 横幅。
版权属于:月萌API www.moonapi.com,转载请注明出处