由于要做一个能够加红字体的dialog,而cocos2d中的CCMessageBox是系统内带的,我无法修改其字体颜色。事实上是可以修改的,通过观察发现CCMessageBox被调用后,在安卓平台中会调用org.cocos2dx.lib.Cocos2dxHandler类中的showDialog方法,结果发现Cocos2dx使用AlertDialog来实现的,贴上代码:

	private void showDialog(Message msg) {
Cocos2dxActivity theActivity = this.mActivity.get();
DialogMessage dialogMessage = (DialogMessage)msg.obj; new AlertDialog.Builder(theActivity)
.setTitle(dialogMessage.titile)
.setMessage(dialogMessage.message)
//.setView(view) 有一个setView成员方法允许我们定义自己的View
.setPositiveButton("ok",
new DialogInterface.OnClickListener() { @Override
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub }
}).create().show();
}

然后里面可以通过setView来实现字体加红,但是这个org.cocos2dx.lib是公共库,每个游戏都需要依赖它,修改它可能会带来不知道的隐患,因此我觉得提供一个方法给游戏调用,能降低耦合。这样就需要在Cocos2dx中调用java的AlertDialog,所以便引出了想记录的东西JNI。


利用create_project命令创建cocos2dx游戏工程,在eclipse中import进来,之后在src文件夹中创建一个.java文件,记录代码如下:

package com.My.Dialog;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.res.Resources;
import android.os.Handler;
import android.os.Message;
import android.text.Html;
import android.text.Spanned;
import android.text.method.ScrollingMovementMethod;
import android.util.Log;
import android.view.LayoutInflater;
import android.widget.LinearLayout;
import android.widget.TextView; public class ShowRedDialog {
private static Handler mHandler;
private Activity activity; public void init(Activity act){
Log.i("%s", "show dialog init");
activity = act;
mHandler = new Handler()
{
@Override
public void handleMessage(Message msg) {
Log.i("%s", "we are in handler");
Resources res = activity.getResources();
//通过在strings.xml中配置layout的位置的方法来添加View
String layoutResStr = res.getString(com.My.Dialog.R.string.view_layout);
if(layoutResStr == null){
Log.e("%s", "layoutResStr can not find !!!");
new AlertDialog.Builder(activity).setTitle("Error").setMessage("layoutResStr can not find !!!")
.setPositiveButton("ok", new DialogInterface.OnClickListener() { @Override
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub }
}).create().show(); }
int layoutId = res.getIdentifier(layoutResStr, "", "");
Log.i("%s", "the resource is found!!");
//反射出layout中的textView
LayoutInflater inflater = (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
LinearLayout view = (LinearLayout)inflater.inflate(layoutId, null);
TextView textview = (TextView) view.getChildAt(0);
//Spanned prasedText = Html.fromHtml("<font color=\"FF0000\"> MESSAGE </font> " + Integer.toString(layoutId));
//设置textView的文本显示,利用html来修改文本样式
Spanned prasedText = Html.fromHtml("<font color=\"FF0000\"> MESSAGE </font>");
textview.setText(prasedText);
textview.setMovementMethod(ScrollingMovementMethod.getInstance());
Log.i("%s", "ready to show our messagebox");
//messageBox弹出
new AlertDialog.Builder(activity)
.setTitle("Warning")
.setView(view)
.setPositiveButton("ok",
new DialogInterface.OnClickListener() { @Override
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub }
}).create().show();
}
};
} public static void showMyDialog(String data)
{
Log.i("in java show my dialog %s", data);
Message msg = mHandler.obtainMessage();
msg.sendToTarget();
} }

这里还有很多要改进的地方,可是不是现在的重点,例如我想把View分离出来,可以让别人去实现;还有方法到底该怎么设计更好,变量是静态还是非静态等等。在这里通过Handler实现C++调用静态函数,然后静态函数调用非静态函数,这只是其中一个实现C++调用非静态函数的办法,网上还有好多。我在strings.xml中加入了如下配置:

<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">JniDialog</string>
<string name="hello_world">Hello</string>
<string name="view_layout">com.My.Dialog:layout/godmsgdialog</string>
</resources>

在jni/hellocpp下新建test.h和test.cpp,代码:

#ifndef TEST_H
#define TEST_H void showMyDialog(const char *tmp); #endif

test.cpp中的代码:

#include <jni.h>
#include "test.h"
#include "platform/android/jni/JniHelper.h"
#include "cocos2d.h"
#include <android/log.h> #define TAG "myDemo-jni" // 这个是自定义的LOG的标识
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,TAG ,__VA_ARGS__) // 定义LOGD类型
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,TAG ,__VA_ARGS__) // 定义LOGI类型
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,TAG ,__VA_ARGS__) // 定义LOGW类型
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,TAG ,__VA_ARGS__) // 定义LOGE类型
#define LOGF(...) __android_log_print(ANDROID_LOG_FATAL,TAG ,__VA_ARGS__) // 定义LOGF类型 using namespace cocos2d; void showMyDialog(const char *tmp){
LOGI("########## i = %d", "call in JNI");
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
JniMethodInfo t;
if(JniHelper::getStaticMethodInfo(t, "com/My/Dialog/ShowRedDialog", "showMyDialog", "(Ljava/lang/String;)V")){
jstring jMsg = t.env->NewStringUTF("do not touch me !!");
t.env->CallStaticVoidMethod(t.classID, t.methodID, jMsg);
t.env->DeleteLocalRef(jMsg);
}
#endif
}

在这里遇到了各种问题:

1、第一个是JniHelper::getStaticMethodInfo静态方法在Eclipse中报错说找不到,解决办法是加上编译头#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)和#endif。

2、t.env->CallStaticVoidMethod(t.classID, t.methodID, "do not touch me !!");之前是这样调用这个方法的,结果出错需要将C++的字符串转为jstring,jstring jMsg = t.env->NewStringUTF("do not touch me !!");

3、如何打印日志,通过引入<android/log.h>并添加宏定义然后就可以在LOGCAT中打印日志了,并且参考:http://blog.csdn.net/zengraoli/article/details/11644815来修改Android.mk文件。

4、jni/hellocpp/main.cpp报错,找不到方法,重启eclipse即可。。。

5、第四个参数是方法签名例如:"(Ljava/lang/String;)V",可以通过在.class文件目录下打开命令行窗口,输入命令 javap -s -p ShowRedDialog (-s表示打印签名信息 -p表示打印所有函数和成员的签名信息,默认只打印public的签名信息)。


修改Android.mk文件,加入要编译的test.cpp文件:

LOCAL_SRC_FILES := hellocpp/main.cpp \
hellocpp/test.cpp \
../../Classes/AppDelegate.cpp \
../../Classes/HelloWorldScene.cpp \

在游戏中如下修改,添加头文件:

#if(CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
#include "../proj.android/jni/hellocpp/test.h"
#endif

添加菜单事件:

void HelloWorld::menuCloseCallback(CCObject* pSender)
{
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WINRT) || (CC_TARGET_PLATFORM == CC_PLATFORM_WP8)
CCMessageBox("You pressed the close button. Windows Store Apps do not implement a close button.","Alert");
#elif (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
CCLog("in cocos2d show dialog");
showMyDialog("dont touch me !!");
#else
CCDirector::sharedDirector()->end();
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
exit(0);
#endif
#endif
}

以上说的是C++调用JAVA,之后有时间再写JAVA调用C++。

JNI笔记的更多相关文章

  1. JNI笔记1

    一.什么是JNI Java Native Interface(JNI)是Java语言的本地编程接口 是 Java 与操作系统本地代码互相调用的功能的接口 二.Java 调用C/C++步骤: 1.在Ja ...

  2. JNI笔记之 初体验

    Java Native Interface提供了java与c语言写的代码之间互相调用的方式.在c语言方面jni.h中声明了许多的类型和方法,有很多java的数据类型和c语言类型的转换方法函数. jav ...

  3. Ubuntu 16.04 安装opencv3.4.5/cuda/caffe并使用jni笔记

    因操作失误,误卸开发机NVIDIA显卡驱动,先更新操作日志如下: 1>NVIDIA驱动重装 1.卸载系统里的Nvidia残余 sudo apt-get purge nvidia* 2.把显卡驱动 ...

  4. 【Android Studio安装部署系列】二十五、Android studio使用NDK生成so文件和arr文件

    版权声明:本文为HaiyuKing原创文章,转载请注明出处! 概述 Android Studio使用ndk的简单步骤. NDK环境搭建 下载NDK 下载链接:https://developer.and ...

  5. 《Android开发艺术探索》读书笔记 (13) 第13章 综合技术、第14章 JNI和NDK编程、第15章 Android性能优化

    第13章 综合技术 13.1 使用CrashHandler来获取应用的Crash信息 (1)应用发生Crash在所难免,但是如何采集crash信息以供后续开发处理这类问题呢?利用Thread类的set ...

  6. 《android开发艺术探索》读书笔记(十四)--JNI和NDK编程

    接上篇<android开发艺术探索>读书笔记(十三)--综合技术 No1: Java JNI--Java Native Interface(java本地接口),它是为了方便java调用C. ...

  7. JNI学习笔记_Java调用C —— 非Android中使用的方法

    一.学习笔记 1.java源码中的JNI函数本机方法声明必须使用native修饰. 2.相对反编译 Java 的 class 字节码文件来说,反汇编.so动态库来分析程序的逻辑要复杂得多,为了应用的安 ...

  8. JNI学习笔记_C调用Java

    一.笔记 1.C调用Java中的方法,参考jni.pdf pg97可以参考博文:http://blog.csdn.net/lhzjj/article/details/26470999步骤: a. 创建 ...

  9. JNI学习笔记_Java调用C —— Android中使用的方法

    一.笔记 1.JNI(Java Native Interface),就是如何使用java去访问C/C++编写的那些库.若想深入了解JNI可以看官方文档jni.pdf.优秀博文:Android JNI知 ...

随机推荐

  1. 曾经post为何只能通过form来提交

    当我们web程序的前台,需要有数据向后台发送时候,我们第一时间想到的就是,给我们所需要提交的用户名,密码之类的数据封装到一个<form>表单里面去,而封装完毕之后,我们需要给form的提交 ...

  2. Win7宽带一键创建

    简化创建宽带连接步骤,为简便而生. 不断分享,不断进步. 免费下载:                  http://yunpan.cn/cmZesi2jpJk9E  访问密码 9444

  3. jq不包含某属性

    jq解释属性选择器时有以下四种: 上面都是带某属性或者属性为某值的情况,还有一种情况是不带某属性怎么办? 答案是同属性不为某值. 如 <a b='c' class="d"&g ...

  4. canvas模拟重力效果

    总结 速度和加速度是动画的基础元素,其中两者都是向量,包括了一个重要因素:方向. 要学会应用 分解 和 合成 ,将速度或加速度分解到x.y轴上,然后将每条轴上的加速度或速度相加,然后再分别与物体的位置 ...

  5. asp.net mvc 多级目录结构

    ikmb@163.com ASP.NET MVC默认的文件组织和URL访问都是一级,我们通常要将一个功能模块组织到一个目录下.方法是:1.文件组织 分别在Controllers和Views文件夹下建议 ...

  6. jquery datatable

    <html><head></head> <script type="text/javascript"> $(document).re ...

  7. 简进祥--iOS开发基础知识

    1:App跳转至系统Settings 跳转在IOS8以上跟以下是有区别的,如果是IOS8以上可以如下设置: NSURL *url = [NSURL URLWithString:UIApplicatio ...

  8. Spark Shell & Spark submit

    Spark 的 shell 是一个强大的交互式数据分析工具. 1. 搭建Spark 2. 两个目录下面有可执行文件: bin  包含spark-shell 和 spark-submit sbin 包含 ...

  9. 【BNUOJ19500】 Matrix Decompressing

    https://www.bnuoj.com/v3/problem_show.php?pid=19500 (题目链接) 题意 给出一个R行C列的正整数矩阵,设前${A_i}$项为其前i行所有元素之和,$ ...

  10. NAnt打包使用MSTest进行单元测试的配置

    NAnt比较老的持续集成工具了,对于它的文章都停留在09年左右的,只有一些github上的老项目上可以很多的看见是使用这个进行集成的,估计这个当时老外用的非常多吧. 如题,NAnt如果使用单元测试,用 ...