cocos2d-x在Android双平台上嵌入WebView

来源:互联网 发布:java程序员常用的软件 编辑:程序博客网 时间:2024/05/22 13:50
这几天想要在cocos2d中嵌入web网页,找了各种方法后最正确的做法好像只有通过jnicocos2d-xc++代码调用java函数,由于对javajni都知之甚少,走了不少弯路,也犯了不少错误,现将我的过程和需要注意的地方做个记录,以方便后面使用的朋友查阅。

本文参照了Vincent Chou的个人博客文章:cocos2d-xiOS/Android双平台上嵌入WebView 和 Cocos2d-x中通过JNI进行C++调用Java代码


1.基本说明 

要通过jnicocos2d-xc++代码调用java函数,要使用到cocos2d-x中有一个JniHelper类。

头文件:#include "platform/android/jni/JniHelper.h"

       需要使用的接口如下:

const char *className, const char *methodName, const char *paramCode);static bool getMethodInfo(JniMethodInfo &methodinfo, const char *className, const char *methodName, const char *paramCode);
每个参数的意义和使用方法:
//函数信息结构体    JniMethodInfo minfo;    bool isHave = JniHelper::getStaticMethodInfo(minfo,/*JniMethodInfo的引用*/                                                 "com/omega/MyApp",/*类的路径*/                                                 "getJavaActivity",/*函数名*/                                                 "()Ljava/lang/Object;");/*函数类型简写*/    jobject activityObj;    if (isHave)    {        //CallStaticObjectMethod调用java函数,并把返回值赋值给activityObj        activityObj = minfo.env->CallStaticObjectMethod(minfo.classID, minfo.methodID);    }

这里重点要说明一下"com/omega/MyApp",/*类的路径*/),这个类的路径,我弄了很久才搞明白,它其实是你在创建android时使用的包名,比如com.xxx.xxx,如果你不知道或者忘记了是什么可以打开 proj.android目录下的AndroidManifest.xml文件查看, package="com.cocos2dx.example" 中的 "com.cocos2dx.example" 就是你的包名。下面继续


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.cocos2dx.example"
      android:versionCode="1"
      android:versionName="1.0">

  .....



源文件是放在:youProject\proj.android\src\com\cocos2dx\example下,比如我的JAVA函数是写在ForAndroid.java文件当,那么最终这里类的路径就是: "com/cocos2dx/example/ForAndroid" .


2.新建一个类CCWebView继承 CCObject

.h文件:



#include "cocos2d.h"

USING_NS_CC;

class CCWebView: public CCObject
{
public:
   CCWebView ();
 ~ CCWebView ();

    CREATE_FUNC(CCWebView);
    bool init();

    /**
     *   @brief  显示WebView
     *
     *   @param  url     地址
     *    @param  x   x位置
     *   @param  y   y位置(左上的位置,坐标系为左上0)
     *    @param  width   宽度
     *    @param  height  高度
     */
    void showWebView(const char* url, float x, float y, float width, float height);

   
    void updateURL(const char* url);
       
    void removeWebView();

};


 .cpp文件:


#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
#include <jni.h>
#include <android/log.h>
#include "platform/android/jni/JniHelper.h"

#define  JAVA_PACK_NAME "com/cocos2dx/example/DianXinForAndroid"
#endif



CCWebView:: CCWebView ()
{

}

CCWebView::~ CCWebView ()
{

}

bool CCWebView::init()
{

   return true;
}


void CCWebView::showWebView(const char* url, float x, float y, float width, float height)
{
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
 //1. 获取activity静态对象
 JniMethodInfo minfo;
     CCLog("1.Get JniMethodInfo!");
 //getStaticMethodInfo 次函数返回一个bool值表示是否找到此函数
 bool isHave = JniHelper::getStaticMethodInfo(minfo,
                                             JAVA_PACK_NAME,
                                             "getJavaActivity",
                                              "()Ljava/lang/Object;");
    CCLog("2.JniHelper::getStaticMethodInfo!");
 jobject activityObj;
    if (isHave)
 {
       activityObj = minfo.env->CallStaticObjectMethod(minfo.classID, minfo.methodID);
  }
   CCLog("3.CallStaticObjectMethod!");
 //2. 查找displayWebView接口,并用jobj调用
    isHave = JniHelper::getMethodInfo(minfo,JAVA_PACK_NAME,"displayWebView", "(IIII)V");

    if (!isHave)
    {
       CCLog("jni:displayWebView 函数不存在");
  }
   else
    {
       //调用此函数
     jint jX = (int)x;
       jint jY = (int)y;
       jint jWidth = (int)width;
       jint jHeight = (int)height;
     minfo.env->CallVoidMethod(activityObj, minfo.methodID, jX, jY, jWidth, jHeight);
 }
   CCLog("4.Find displayWebView!");
    //3. 查找updateURL接口,并用jobj调用
 isHave = JniHelper::getMethodInfo(minfo,JAVA_PACK_NAME,"updateURL", "(Ljava/lang/String;)V");

   if (!isHave)
    {
       CCLog("jni:updateURL 函数不存在");
   }
   else
    {
       //调用此函数
     jstring jmsg = minfo.env->NewStringUTF(url);
     minfo.env->CallVoidMethod(activityObj, minfo.methodID, jmsg);
    }
   CCLog("4.Find updateURL!");
#endif
}

void CCWebView::updateURL(const char* url)
{
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
   //1. 获取activity静态对象
 JniMethodInfo minfo;
    //getStaticMethodInfo 次函数返回一个bool值表示是否找到此函数
 bool isHave = JniHelper::getStaticMethodInfo(minfo,
     JAVA_PACK_NAME,
     "getJavaActivity",
      "()Ljava/lang/Object;");
    jobject activityObj;
    if (isHave)
 {
       activityObj = minfo.env->CallStaticObjectMethod(minfo.classID, minfo.methodID);
  }

   //2. 查找updateURL接口,并用jobj调用
 isHave = JniHelper::getMethodInfo(minfo,JAVA_PACK_NAME,"updateURL", "(Ljava/lang/String;)V");

   if (!isHave)
    {
       CCLog("jni:updateURL 函数不存在");
   }
   else
    {
       //调用此函数
     jstring jmsg = minfo.env->NewStringUTF(url);
     minfo.env->CallVoidMethod(activityObj, minfo.methodID, jmsg);
    }
#endif
}

void CCWebView::removeWebView()
{
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
    //1. 获取activity静态对象
 JniMethodInfo minfo;
    //getStaticMethodInfo 次函数返回一个bool值表示是否找到此函数
 bool isHave = JniHelper::getStaticMethodInfo(minfo,
     JAVA_PACK_NAME,
     "getJavaActivity",
      "()Ljava/lang/Object;");
    jobject activityObj;
    if (isHave)
 {
       activityObj = minfo.env->CallStaticObjectMethod(minfo.classID, minfo.methodID);
  }

   //2. 查找updateURL接口,并用jobj调用
 isHave = JniHelper::getMethodInfo(minfo,JAVA_PACK_NAME,"removeWebView", "()V");

    if (!isHave)
    {
       CCLog("jni:updateURL 函数不存在");
   }
   else
    {
       //调用此函数
     minfo.env->CallVoidMethod(activityObj, minfo.methodID);
  }
#endif
}


3. ForAndroid.java文件里写上接口就可以了


package com.cocos2dx.example;

import org.cocos2dx.lib.Cocos2dxActivity;

import android.os.Bundle;
import android.app.Activity;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;

public class ForAndroid extends Cocos2dxActivity{

    public static Activity actInstance;
 private LinearLayout m_webLayout;
   private WebView m_webView;
 
    protected void onCreate(Bundle savedInstanceState){
     super.onCreate(savedInstanceState);
    
        actInstance = this;
     //web layout
       m_webLayout = new LinearLayout(this);
       actInstance.addContentView(m_webLayout,
                new LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT));
   }
  
    static {
         System.loadLibrary("game");
    }
   
  
    public static Object getJavaActivity()
 {
       return actInstance;
 }
  
    //WebView
   public void displayWebView(final int x, final int y, final int width, final int height)
    {
   //  Log.e("Vincent", "showWebView");
       
        this.runOnUiThread(new Runnable()
      {
           public void run()
          {
   //          LinearLayout layout = new LinearLayout(actInstance);
    //          actInstance.addContentView(layout, new LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT));
                m_webView = new WebView(actInstance);
               m_webLayout.addView(m_webView);
            
                LinearLayout.LayoutParams linearParams = (LinearLayout.LayoutParams) m_webView.getLayoutParams();
               linearParams.leftMargin = x;
                linearParams.topMargin = y;
             linearParams.width = width;
             linearParams.height = height;
               m_webView.setLayoutParams(linearParams);
   
                m_webView.setBackgroundColor(0);
                m_webView.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);
                m_webView.getSettings().setAppCacheEnabled(false);
              //m_webView.setBackgroundResource(R.drawable.yourImage);
               
                m_webView.setWebViewClient(new WebViewClient(){
                 @Override
                   public boolean shouldOverrideUrlLoading(WebView view, String url){
                         
                            return false;
                          
                    }
               });
            
            }
       });
 }

   public void updateURL(final String url)
    {
   //  Log.e("Vincent", "updateURL"+url);
     
        this.runOnUiThread(new Runnable()
      {
           public void run() {
             m_webView.loadUrl(url);
         }
       });
 }

   public void removeWebView()
    {
   //  Log.e("Vincent", "removeWebView");
 
        this.runOnUiThread(new Runnable()
      {
           public void run()
          {
               m_webLayout.removeView(m_webView);
              m_webView.destroy();
            }
       });
 }
}


4.我遇到过的问题:在用cygwin编译cocos2d-x文件的时候在Android.mk里面添加了在目录下自动查找.cpp文件然后进行编译的方式。结果在真机上运行时就出错,错误如下。后来删除Android.mk的自动查找.cpp,然后自己手动添加cpp文件,编译运行就正常,说明在自动获取cpp文件时有问题。


system_process — InputDispatcher 
channel StatusBarView (server)’ ~ Consumer closed input channel or an error occurred. events=0×8
channel StatusBarView (server)’ ~ Channel is unrecoverably broken and will be disposed!

原创粉丝点击