Unity3d AndroidJNI两篇应用示例。羽化的文章。







http://blog.csdn.net/libeifs/article/details/7110371

Unity Android平台AdMob应用


开发环境

Window7

Unity3D  3.4.1

MB525defy Android 2.2.1


        羽化的第二十一篇博客,这次一次发布三篇确实有点漫长。。。因为最近羽化一直很忙,没多少时间重新整理Android AdMob方面的东西,正好今天有空就把准备写的补上。其实羽化这方面也不是很熟悉,但知道的解决方法有两三种,这次就说一个最简单的解决方案,并送上代码,以后任何人开发都可以改改项目名称和ID就可以直接拿来用。很多方法来自官方的大牛们热议,大家可以可以借鉴下这些脚本写法。

        最近通关了刺客信条启示录,作为Ezio和Altair时代的终结,本作应该算是前作兄弟会的延伸,创新点不多,但依然很有趣,刺客养成方面做得过于繁琐,也没有隐藏的装备了,这点实在是可惜。想当初羽化开始玩刺客信条系列的时候,大概读大一,XBOX360才刚买不久,家里还是一个纯平电视,第一次玩的时候感觉很兴奋,开阔的场景,密集的建筑,自由的攀爬,这就是游戏的乐趣,真正的次世代体验,但初代任务方面薄弱很多,幸运的是,刺客信条系列总是在不断改进和创新,可以看到开发团队在这方面的努力,这种开发游戏的态度值得游戏制作人学习,希望这个系列能做得更好,真正做到“万物皆虚,万事皆允”,应该下一作就是终结。


本次学习:

1. Eclipse报错解决方案

2. AdMob应用

 

1.Eclipse报错解决方案

      本来不用写的,但羽化在打开Eclipse的时候遇到了几个蛋疼问题,下面羽化把这几个问题做个小小总结:

(1)Error: Unableto open class file XXX/R.java错误

      有两种解决方案:首先是Project -> clean 再勾上Build Automatically,可以解决一类常出现的脑抽问题。。。其次是Window -> Preferences -> Java -> Build Path 中选择Project -> Apply,可以解决些意外问题。。。

(2)error generating final archive 错误

   这类错误一般新手是遇不到的,因为这是证书过期引起的,一般证书有效期只有1年,超过1年后,所有新建的Android工程都会无故报错,解决方法是来到Window -> Preferences -> Android -> Build中 Default debug keystore目录下,复制里面地址打开删除debug.keystore及 ddms.cfg两个文件,重启eclipse就可以解决。

 

2.AdMob应用

      首先是Eclipse上Android项目的写法,导入羽化的项目AdMob(Import –> Existing Projects into Workspace),肯定会报错。。。

Unity3d AndroidJNI两篇应用示例。羽化的文章。_第1张图片

       这时修改引用,选中项目文件单击鼠标右键-> Properties -> Java Build Path里面的Libraries,把admob-sdk-android.jar和classes.jar文件重新Edit到当前的libs里面,再到Order and Export里面勾选上。

       注意: admob-sdk-android.jar是网上一个大牛封装的AdMob SDK,有一些自己的方法,但不是最新版本,下载最新版本的同学注意Android系统版本最好超过3.2,否则广告栏会显示一段错误。classes.jar是Unity里面自带的一个jar包,通过搜寻就可以知道位置,羽化就不再介绍。

       如果不出意外,现在应该完全不会报错,报错了请看上面的注意和Eclipse报错原因。。。下面我们看代码

AdMob.java

[java]  view plain copy print ?
  1. package com.LB.AdMob;   //必须改变  
  2.   
  3. import android.os.Bundle;  
  4. import android.os.Handler;  
  5. import android.util.Log;  
  6. import android.view.View;  
  7. import android.view.ViewGroup.LayoutParams;  
  8. import android.view.animation.AccelerateInterpolator;  
  9. import android.view.animation.AlphaAnimation;  
  10. import android.widget.LinearLayout;  
  11. import android.os.Message;  
  12.   
  13. import com.unity3d.player.*;  
  14.   
  15. import com.admob.android.ads.AdView;  
  16. import com.admob.android.ads.SimpleAdListener;  
  17.   
  18. public class AdMob extends UnityPlayerActivity  
  19. {  
  20.     public AdView adView;  
  21.     private boolean adVisible = true;  
  22.     protected void onCreate(Bundle savedInstanceState)  
  23.     {  
  24.         Log.i("AdMob""onCreate");  
  25.         super.onCreate(savedInstanceState);  
  26.           
  27.         setupAds();  
  28.     }  
  29.     private Handler handler = new Handler()   
  30.     {  
  31.         public void  handleMessage(Message msg)   
  32.         {  
  33.             switch (msg.what)  
  34.             {  
  35.                 case 0:   
  36.                     if(adVisible)  
  37.                     {  
  38.                         adView.setVisibility(View.GONE);  
  39.                         adVisible = false;  
  40.                     }  
  41.                     break;  
  42.                 case 1:  
  43.                     if (!adVisible)  
  44.                     {  
  45.                         adView.setVisibility(View.VISIBLE);  
  46.                         AlphaAnimation animation = new AlphaAnimation(0.0f, 1.0f);  
  47.                         animation.setDuration(400);  
  48.                         animation.setFillAfter(true);  
  49.                         animation.setInterpolator(new AccelerateInterpolator());  
  50.                         adView.startAnimation(animation);  
  51.                         adVisible = true;  
  52.                     }  
  53.                     break;  
  54.                 default:  
  55.                     break;  
  56.             }  
  57.         }  
  58.     };  
  59.   
  60.     public void EnableAds()  
  61.     {  
  62.         handler.sendEmptyMessage(1);  
  63.     }  
  64.   
  65.     public void DisableAds()  
  66.     {  
  67.         handler.sendEmptyMessage(0);  
  68.     }     
  69.     private void setupAds()  
  70.     {  
  71.             LinearLayout layout = new LinearLayout(this);  
  72.         layout.setOrientation(LinearLayout.VERTICAL);  
  73.             addContentView(layout, new LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT));  
  74.   
  75.             adView = new AdView(this);  
  76.         layout.addView(adView, new LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.WRAP_CONTENT));  
  77.   
  78.             adView.setBackgroundColor(0xff000000);  
  79.             adView.setPrimaryTextColor(0xffffffff);   
  80.             adView.setSecondaryTextColor(0xffcccccc);  
  81.             adView.setKeywords("kickoff Goal Pinball game spiel bundesliga male Flipper Bumper Parlotones kick off 3d soccer fussball football tor vuvuzela");  
  82.         //  adView.setRequestInterval(20);       //设置自动出现频率  
  83.   
  84.         // add listener for easier debugging  
  85.             adView.setAdListener( new SimpleAdListener()  
  86.             {  
  87.                 public void onFailedToReceiveAd(com.admob.android.ads.AdView adView)  
  88.                 {  
  89.                     Log.d("AdListener""onFailedToReceiveAd: " + adView.toString());  
  90.                     super.onFailedToReceiveAd(adView);  
  91.                 }  
  92.   
  93.                 public void onFailedToReceiveRefreshedAd(com.admob.android.ads.AdView adView)  
  94.                 {  
  95.                     Log.d("AdListener""onFailedToReceiveRefreshedAd: " + adView.toString());  
  96.                     super.onFailedToReceiveRefreshedAd(adView);  
  97.                 }  
  98.   
  99.                 public void onReceiveAd(com.admob.android.ads.AdView adView)  
  100.                 {  
  101.                     Log.d("AdListener""onReceiveAd: " + adView.toString());  
  102.                     super.onReceiveAd(adView);  
  103.                 }  
  104.   
  105.                 public void onReceiveRefreshedAd(com.admob.android.ads.AdView adView)  
  106.                 {  
  107.                     Log.d("AdListener""onReceiveRefreshedAd: " + adView.toString());  
  108.                     super.onReceiveRefreshedAd(adView);  
  109.                 }  
  110.             } );  
  111.             adView.requestFreshAd();  
  112.     }  
  113. }  

和AndroidMainifest.xml

[html]  view plain copy print ?
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"  
  3.       package="com.LB.AdMob"  
  4.       android:versionCode="1"  
  5.       android:versionName="1.0">  
  6.         
  7.     <application android:icon="@drawable/icon" android:label="@string/app_name">  
  8.         <activity android:name=".AdMob"  
  9.                   android:label="@string/app_name">  
  10.             <intent-filter>  
  11.                 <action android:name="android.intent.action.MAIN" />  
  12.                 <category android:name="android.intent.category.LAUNCHER" />  
  13.             </intent-filter>  
  14.         </activity>  
  15.           
  16.         <!-- The application's publisher ID assigned by AdMob  //android:value中放入使用者ID -->  
  17.         <meta-data android:value="a14ddb78fc3babe" android:name="ADMOB_PUBLISHER_ID" />  
  18.           
  19.         <!-- AdMobActivity definition -->  
  20.         <activity android:name="com.admob.android.ads.AdMobActivity"  
  21.                   android:theme="@android:style/Theme.NoTitleBar.Fullscreen"  
  22.                   android:configChanges="orientation|keyboard|keyboardHidden" />  
  23.           
  24.         <!-- Track Market installs -->  
  25.         <receiver android:name="com.admob.android.ads.analytics.InstallReceiver" android:exported="true">  
  26.             <intent-filter> <action android:name="com.android.vending.INSTALL_REFERRER" />  
  27.             </intent-filter>  
  28.         </receiver>  
  29.     </application>  
  30.       
  31.     <!-- AdMob SDK requires Internet permission -->  
  32.     <uses-permission android:name="android.permission.INTERNET" />  
  33. </manifest>  

        这是个典型的Android项目代码,有几点注意下,1.如果想用在自己的应用上,就照着羽化的引用结构自己新建一个工程,把这两个文件中所有的羽化自定义名称换掉即可。2. android:value中填入自己申请的AdMob ID。3.羽化把代码简化到最少,所以并没用使用res中的所有内容,若想自定义图标等就需要自己去修改AndroidManifests实现。4.这个可以加上阻止休眠命令,在羽化上一篇Android博客里面有提到。5.Unity中的Bundle Identifier必须与这里定义的package一致。6.这时把Eclipse项目运行肯定报错。7.这里只写了广告淡出效果,没写淡入效果- - 大家凑合看吧。。。

Unity3d AndroidJNI两篇应用示例。羽化的文章。_第2张图片

            当上面的都没问题后就把AdMob.java打jar包,方法是选中AdMob鼠标右键 -> Export -> java -> JAR file -> Next

Unity3d AndroidJNI两篇应用示例。羽化的文章。_第3张图片


    选择你的到处路径和名称JAR file,直接Finish,这样的jar包里面只包括编译后的AdMob.class,很小很干净。。。然后打开羽化的Unity工程AdMobTest(File- > Open Project),双击UnityAdMob这个Sence,可以看到只有一个相机。。。上面只有一个脚本Ad.cs。

Ad.cs

[csharp]  view plain copy print ?
  1. using UnityEngine;  
  2.   
  3. using System.Collections;  
  4.   
  5. using System;  
  6.   
  7.   
  8.   
  9. public class Ad : MonoBehaviour   
  10.   
  11. {  
  12.   
  13.     void OnGUI()   
  14.   
  15.     {  
  16.   
  17.         if(Input.GetKey(KeyCode.Escape))  
  18.   
  19.         {  
  20.   
  21.             Application.Quit();  
  22.   
  23.         }  
  24.   
  25.           
  26.   
  27.         if(GUI.Button(new Rect(0,Screen.height-220,100,100),"EnableAds!"))  
  28.   
  29.         {  
  30.   
  31.             EnableAds();  
  32.   
  33.         }  
  34.   
  35.           
  36.   
  37.         if(GUI.Button(new Rect(0,Screen.height-110,100,100),"DisableAds!"))  
  38.   
  39.         {  
  40.   
  41.             DisableAds();  
  42.   
  43.         }  
  44.   
  45.           
  46.   
  47.         if(GUI.Button(new Rect(Screen.width-120,Screen.height-40,120,30),"Click to YUHUA!"))         
  48.   
  49.         {        
  50.   
  51.             Application.OpenURL("http://blog.csdn.net/libeifs");        
  52.   
  53.         }  
  54.   
  55.     }  
  56.   
  57.       
  58.   
  59.       
  60.   
  61.     public void EnableAds()  
  62.   
  63.     {  
  64.  
  65. #if UNITY_ANDROID  
  66.   
  67.         AndroidJNI.AttachCurrentThread();  
  68.   
  69.   
  70.   
  71.         // first we try to find our main activity..  
  72.   
  73.         IntPtr cls_Activity = AndroidJNI.FindClass("com/unity3d/player/UnityPlayer");  
  74.   
  75.         IntPtr fid_Activity = AndroidJNI.GetStaticFieldID(cls_Activity, "currentActivity""Landroid/app/Activity;");  
  76.   
  77.         IntPtr obj_Activity = AndroidJNI.GetStaticObjectField(cls_Activity, fid_Activity);  
  78.   
  79.         //Debug.Log("obj_Activity = " + obj_Activity);  
  80.   
  81.   
  82.   
  83.         IntPtr cls_OurAppNameActivityClass = AndroidJNI.FindClass("com/LB/AdMob/AdMob"); //this has to be changed  
  84.   
  85.   
  86.   
  87.         IntPtr startAdsMethod = AndroidJNI.GetMethodID(cls_OurAppNameActivityClass, "EnableAds""()V");  
  88.   
  89.         //Debug.Log("m_startAdsMethod = " + startAdsMethod);  
  90.   
  91.   
  92.   
  93.         if (AndroidJNI.IsInstanceOf(obj_Activity, cls_OurAppNameActivityClass) != false)  
  94.   
  95.         {  
  96.   
  97.             //Debug.Log("Activity IS a OurAppNameActivity");  
  98.   
  99.             jvalue[] myArray = new jvalue[1];  
  100.   
  101.             AndroidJNI.CallVoidMethod(obj_Activity, startAdsMethod,myArray);  
  102.   
  103.         }  
  104.  
  105. #else  
  106.   
  107.         m_adShowing = true;  
  108.  
  109. #endif //UNITY_ANDROID  
  110.   
  111.     }  
  112.   
  113.   
  114.   
  115.       
  116.   
  117.     public void DisableAds()  
  118.   
  119.     {  
  120.  
  121. #if UNITY_ANDROID  
  122.   
  123.         AndroidJNI.AttachCurrentThread();  
  124.   
  125.   
  126.   
  127.         // first we try to find our main activity..  
  128.   
  129.         IntPtr cls_Activity = AndroidJNI.FindClass("com/unity3d/player/UnityPlayer");  
  130.   
  131.         IntPtr fid_Activity = AndroidJNI.GetStaticFieldID(cls_Activity, "currentActivity""Landroid/app/Activity;");  
  132.   
  133.         IntPtr obj_Activity = AndroidJNI.GetStaticObjectField(cls_Activity, fid_Activity);  
  134.   
  135.   
  136.   
  137.         IntPtr cls_OurAppNameActivityClass = AndroidJNI.FindClass("com/LB/AdMob/AdMob"); //this has to be changed  
  138.   
  139.         IntPtr stopAdsMethod = AndroidJNI.GetMethodID(cls_OurAppNameActivityClass, "DisableAds""()V");  
  140.   
  141.   
  142.   
  143.         if (AndroidJNI.IsInstanceOf(obj_Activity, cls_OurAppNameActivityClass) != false)  
  144.   
  145.         {  
  146.   
  147.             jvalue[] myArray = new jvalue[1];  
  148.   
  149.             AndroidJNI.CallVoidMethod(obj_Activity, stopAdsMethod,myArray);  
  150.   
  151.         }  
  152.  
  153. #else //UNITY_ANDROID  
  154.   
  155.         m_adShowing = false;  
  156.  
  157. #endif //UNITY_ANDROID  
  158.   
  159.     }  
  160.   
  161. }  

Unity3d AndroidJNI两篇应用示例。羽化的文章。_第4张图片

       看起很简单,确实也不难,首先建立Plugins -> Android -> bin | libs这个文件集,把Eclipse项目里面的AndroidManifest.xml放在Android目录下,把打包的UnityAdMob.jar放在bin下,把这个重写的AdMob SDK放在libs下,注意:把Bundle Identifier设置成和Eclipse项目包一样的名字,就算没有Ad.cs程序运行也会执行一次广告,这个C#类只是个广告开关,还有里面的两个AndroidJNI.FindClass("XXX")自行修改。。。

 

运行效果: (有空就帮羽化点下广告吧- -)

Unity3d AndroidJNI两篇应用示例。羽化的文章。_第5张图片

 

     这个应该能满足大部分广告显示方式,置于显示位置就麻烦大家自行修改了,谢谢大家支持~ ~

 

老样子,项目送上:

http://dl.dbank.com/c0ya3iynro

 

下集预告:

Thinking inShader(5)




1
0
查看评论
15楼  bykk317227081 2012-12-27 16:11发表 [回复]
想了很多办法都不能把广告定位....求大神思路...
14楼  地狱男爵 2012-12-11 17:27发表 [回复]
很不幸你的工程和我做的一样都是不出广告
13楼  fishbiao 2012-10-16 15:21发表 [回复]
你好,为什么我做的插件加到unity项目里面后就只显示广告,项目本身的内容完全不显示了呢?
Re:  地狱男爵 2012-12-09 22:09发表 [回复]
引用“fishbiao”的评论:你好,为什么我做的插件加到unity项目里面后就只显示广告,项目本身的内容完全不显示了呢?
为啥会遇到这样的问题呢,是什么导致的呢?
12楼  lisayang 2012-06-08 14:56发表 [回复]
给您发私信了哟,请查看一下,谢谢。
11楼  笔触 2012-05-01 21:58发表 [回复]
新的GoogleAdMobAdsSdk-4.1.0,怎么弄呢,好像方法完全不一样啦,AdMob官网上说新申请的ID必须加载2011 年 3 月 15 日之后的SDK
10楼  笔触 2012-04-27 21:34发表 [回复]
请别这么称呼,屌丝一个啊,新手嘞,没学过java,麻烦大侠直接指点
9楼  star627055192 2012-04-27 16:24发表 [回复]
androidJNI 调用android里面的方法可以向方法里面传递参数吗?
jvalue[] myArray = new jvalue[1]; 
jvalue[0].i=5;
AndroidJNI.CallVoidMethod(obj_Activity, stopAdsMethod,myArray);
Re:  羽化 2012-04-27 16:26发表 [回复]
回复star627055192:可以 去看JNI的API
8楼  笔触 2012-04-27 13:01发表 [回复]
请问一下怎么使广告靠右显示呢?
Re:  羽化 2012-04-27 16:24发表 [回复]
回复xinhai657:盖茨 你该看看Activity怎么排版。。。
7楼  hole1 2012-04-15 15:51发表 [回复]
为啥用unity 编android版本时,提示需要sdk2.3呢?
Re:  羽化 2012-04-15 16:02发表 [回复]
回复hole1:unity编译肯定需要Android SDK 
3.5版需要4.0SDK
6楼  hole1 2012-04-15 02:23发表 [回复]
最近开始狠命研究unity做移动平台游戏
今天为了加广告,搞了一天eclipse,adt,各式各样版本不匹配,
郁闷的不行了,看到这篇博文,简直是雪中送火堆啊.
5楼  j349900963 2012-02-29 17:58发表 [回复]
admob-sdk-android.jar与classes.jar 都导入了你博客上的设置都做了的
4楼  j349900963 2012-02-29 17:26发表 [回复]
羽化大哥 我下载下包 JAVA源码,在Eclipse下启动VM运行报错 LogCat 如下:
02-28 09:08:17.248: E/Unity(775): Unable to locate player settings. bin/Data/settings.xml
但我用直接UnityAdActivity extends Activity的程序运行都正常,用你的ID广告这些得了出来了 求解决
Re:  羽化 2012-02-29 17:30发表 [回复]
回复j349900963:Eclipse还要导一次lib 不知道你导没。。。
Re:  j349900963 2012-02-29 18:01发表 [回复]
admob-sdk-android.jar与classes.jar 都导入了你博客上的设置都做了的 你默认我发布成APK的运行都 正确的
3楼  leileibox861210 2012-02-23 18:42发表 [回复]
恩,谢谢~~我试试看~不懂了再来求救,嘿嘿~~
2楼  leileibox861210 2012-02-23 18:28发表 [回复]
雪中跪求.....等回复3
1楼  leileibox861210 2012-02-23 18:26发表 [回复] [引用] [举报]
libeifs大神你好,我本身是三维特效师,由于工作需要所以要在游戏中加入广告,我下载了你的项目文件,用unity导出时候报错:以下错误代码,求救是什么原因
Error building Player: Win32Exception: ApplicationName='java', CommandLine='-Xmx1024M -Djava.ext.dirs="C:/Program Files/Android/android-sdk\platform-toolsb/" -jar "C:/Program Files/Android/android-sdk\platform-toolsb.jar" --dex --verbose --output=bin/classes.dex bin/classes.jar plugins', CurrentDirectory='Temp/StagingArea'
UnityEditor.HostView:OnGUI()
Re:  羽化 2012-02-23 18:30发表 [回复] [引用] [举报]
回复leileibox861210:这应该是你Android SDK的路径问题 或者是SDK本身缺少文件







http://blog.csdn.net/libeifs/article/details/6791346

Unity调用Android


开发环境

Window7

Unity3D  3.4

MB525defy   Android 2.2.1

jdk1.6.0 (7版本貌似不行)


         羽化的第十一篇博客。最近在玩《北欧女神:负罪者》,3A做的游戏都很有诚意,游戏秉承了系列优良传统,而且做成了SRPG也不觉得不适应,游戏难度中上,剧情也不错,在羽化看来《北欧女神》是个十分经典的系列,在RPG中算是个另类作品,准确来说应该是独树一帜。能力在逐渐提高,而工资却越拿越少,羽化面包和泡面的日子不知道还能坚持多久,面对这个忧郁的现实,如何改变,羽化现在就跟威尔弗雷德一个心情,一直坚持自己最初的理由还是放下包袱开始新的生活?因为。。。于是羽化做了个决定~ ~ Brand New World

         这次说一个比较有趣的内容,Android类在Unity上如何调用的方法,感谢★幻想の猫⌒的分享,话说方法来自网上,羽化只是小做修改,在此感慨国外牛人多,下面开始吧- -

 

本次学习:

1.      Android类打jar包

2.      Unity如何调用Android

3.      功能分析

 

1.   Android类打jar包

         羽化在这还是用网上的那个例子,用Android类得到Sensor的三个值,这里把过程简化,毕竟这些都是Android的基础。

         首先打开Unity,在Project下创建Plugins文件夹,然后在该文件夹下创建一个名为Android的子文件夹,再在Android文件夹下创建src文件夹,创建这三个层级的文件夹后我们开始写Android类,下面有些部分是需要自己修改的,羽化用自己的习惯修改了。

CompassActivity.java

[java]  view plain copy print ?
  1. package com.LB.UnityAndroid1;  
  2.   
  3. import com.unity3d.player.UnityPlayerActivity;  
  4.   
  5. import android.content.Context;  
  6. import android.hardware.Sensor;  
  7. import android.hardware.SensorEvent;  
  8. import android.hardware.SensorEventListener;  
  9. import android.hardware.SensorManager;  
  10. import android.os.Bundle;  
  11. import android.util.Config;  
  12. import android.util.Log;  
  13. import android.app.Activity;  
  14. import android.view.WindowManager;  
  15.   
  16. public class CompassActivity extends UnityPlayerActivity {  
  17. private static final String TAG = "Compass";  
  18.   
  19. private SensorManager mSensorManager;  
  20. private Sensor mSensor;  
  21.   
  22. static public float xmag;  
  23. static public float x;  
  24. static public float ymag;  
  25. static public float zmag;  
  26.   
  27. private final SensorEventListener mListener = new SensorEventListener() {  
  28. public void onSensorChanged(SensorEvent event) {  
  29. if (Config.DEBUG) Log.d(TAG,  
  30. "sensorChanged (" + event.values[0] + ", " + event.values[1] + ", " + event.values[2] + ")");  
  31.   
  32. xmag = event.values[0];  
  33. ymag = event.values[1];  
  34. zmag = event.values[2];  
  35. }  
  36.   
  37. public void onAccuracyChanged(Sensor sensor, int accuracy) {  
  38. }  
  39. };  
  40.   
  41. @Override  
  42. protected void onCreate(Bundle icicle) {  
  43. super.onCreate(icicle);  
  44. getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON, WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);  
  45. mSensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE);  
  46. mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);  
  47. }  
  48.   
  49. @Override  
  50. protected void onResume()  
  51. {  
  52. if (Config.DEBUG) Log.d(TAG, "onResume");  
  53. super.onResume();  
  54.   
  55. mSensorManager.registerListener(mListener, mSensor,  
  56. SensorManager.SENSOR_DELAY_GAME);  
  57. }  
  58.   
  59. @Override  
  60. protected void onStop()  
  61. {  
  62. if (Config.DEBUG) Log.d(TAG, "onStop");  
  63. mSensorManager.unregisterListener(mListener);  
  64. super.onStop();  
  65. }  
  66.   
  67. public static float getX() {  
  68. //return xmag;  
  69. x+=10.0;  
  70. return x;  
  71. }  
  72.   
  73. public static float getY() {  
  74. return ymag;  
  75. }  
  76.   
  77. public static float getZ() {  
  78. return zmag;  
  79. }  
  80. }  

       好了,这个类放在src文件夹里面,现在是四个层级关系,右击UnityAndroid选中Show in Explorer,这样就会来到这个文件夹下,下面打开cmd命令控制台,cd到我们这个文件夹下,分别输入这三条语句:

1.> javac CompassActivity.java -classpath D:\Unity\Editor\Data\PlaybackEngines\androidplayer\bin\classes.jar -bootclasspath D:\android-sdk-windows\platforms\android-8\android.jar -d .

2.> javap -s com.LB.UnityAndroid1.CompassActivity

3.> jar cvfM ../Compass.jar com/

         注意这里需要配置好java的环境变量和要有android 2.2的API。这样,在Unity里面会发现多出来一个com的文件夹和Android的jar包,我们打jar包就这样打好了。

 

2.  Unity如何调用Android

         这里我们还需要新建AndroidMainfest.xml在Android文件夹下,这里要新建个res文件夹,因为羽化这有用到里面的资源。于是放好后结构就很像Android的项目了。

AndroidMainfest.xml

[html]  view plain copy print ?
  1. <?xml version="1.0" encoding="utf-8"?>   
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"   
  3.       package="com.LB.UnityAndroid1"   
  4.       android:versionCode="1"   
  5.       android:versionName="1.0">   
  6.    
  7.     <application android:icon="@drawable/icon" android:label="@string/app_name">   
  8.         <activity android:name=".CompassActivity"   
  9.                   android:label="@string/app_name">   
  10.             <intent-filter>   
  11.                 <action android:name="android.intent.action.MAIN" />   
  12.                 <category android:name="android.intent.category.LAUNCHER" />   
  13.             </intent-filter>   
  14.         </activity>   
  15.     </application>   
  16.     <uses-permission android:name="android.permission.WAKE_LOCK"/>   
  17. </manifest>  

万事具备,现在写个C#来调用这个类了,这个就放在根目录下。

CompassJNI.cs

[csharp]  view plain copy print ?
  1. using UnityEngine;   
  2. using System.Collections;   
  3. using System;   
  4.    
  5. public class CompassJNI : MonoBehaviour    
  6. {   
  7.     static float    xValue;   
  8.     static float    yValue;   
  9.     static float    zValue;   
  10.    
  11.     // Use this for initialization   
  12.     void Start ()    
  13.     {   
  14.         AndroidJNI.AttachCurrentThread();   
  15.     }   
  16.    
  17.     void Update() {   
  18.         if(Input.GetKey(KeyCode.Escape))   
  19.         {   
  20.             Application.Quit();   
  21.         }   
  22.         using (AndroidJavaClass cls_UnityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))    
  23.         {   
  24.    
  25.             using (AndroidJavaObject obj_Activity = cls_UnityPlayer.GetStatic<AndroidJavaObject>("currentActivity")) {   
  26.    
  27.                 AndroidJavaClass cls_CompassActivity = new AndroidJavaClass("com.LB.UnityAndroid1.CompassActivity");   
  28.    
  29.                 cls_CompassActivity.CallStatic("Init", obj_Activity);   
  30.    
  31.                 xValue = cls_CompassActivity.CallStatic<float>("getX");   
  32.                 yValue = cls_CompassActivity.CallStatic<float>("getY");   
  33.                 zValue = cls_CompassActivity.CallStatic<float>("getZ");   
  34.    
  35.             }   
  36.         }   
  37.     }   
  38.    
  39.     void OnGUI()    
  40.     {   
  41.         GUI.Label(new Rect(Screen.width / 2 -200, Screen.height / 2, 400,100), "xmag = " + xValue.ToString() + " ymag = " + yValue.ToString() + " zmag = " + zValue.ToString());   
  42.         if(GUI.Button(new Rect(Screen.width-120,Screen.height-40,120,30),"Click to YUHUA!"))    
  43.         {   
  44.             Application.OpenURL("http://blog.csdn.net/libeifs");   
  45.         }   
  46.     }   
  47. }  

在运行的时候一定要记住把Player Settings里面的Identification的Bundle Identifier改成自己的项目名,羽化这里是Com.LB.UnityAndroid1 。

 

3.   功能分析

         这个例子是得到Android手机的Sensor,羽化这里让X自增长以示区别,细心的人会发现羽化这里加了些看似没用的语句,比如这里有个阻止屏幕休眠的语句,这是羽化目前发现唯一的一个Unity做不到的功能,多亏了Michael的提醒,不然会成为一个盲点。其实这个项目里面很多东西可以删掉,留下jar包和CompassJNI就够了,大家可以试试,Unity载入jar包貌似是全部载入与名字没有关系,话说这个例子可以用来添加ADMob,公司里面明哥已经实现出来了,羽化是不建议加这个,因为很烦人,原来玩《割绳子》的时候深有体会=。= 这里加了羽化博客的广告,大家不要骂。。。

        

老样子项目地址送上:

          http://download.csdn.net/detail/libeifs/3616911

 

下集预告

Unity简单Ai编写
10
0
查看评论
11楼  yanx8844 2013-06-07 13:55发表 [回复]
调用java函数,有一个参数要传递一个java的接口类。

在C#中要怎么实现jave的接口类,并传递给jave函数啊?
10楼  u010295244 2013-04-14 18:24发表 [回复]
羽化,您好,我也有个关于unity打包APK到安卓的问题想请问一下,需求是:在已经安装在安卓系统中的unity程序运行后,点击按钮,打开一个插入了swf文件的html文件,通过文档,我已知道访问android程序jar包的方法,也成功的将www对象中提取jar包中的html文件和对应的swf文件用文件流输出到我指定的路径下,然后的程序就是用Application.OpenURL()来访问那个路径下的html(路径:mnt/sdcard/car/),html也顺利打开了,直到这个步骤都是正确的,但是就是那个swf文件在网页中不会播放,但是在安卓自带的文件管理器中打开mnt/sdcard/car/这个文件夹,再点击那个刚创建出来的html文件后,swf是会正常的播放的,这就令我很困惑啊,是Application.OpenURL()这个方法出了什么问题么?我看unity 的文档里说的the page the plugin is contained in will be redirected to the url. 也不太理解这是什么意思,会不会和我的问题有关?不知道您遇到过这样的情况吗?麻烦您帮我个忙吧,谢谢啦!
9楼  skeay168 2013-03-27 17:14发表 [回复]
羽化你好,请问下unity可以直接调jar 中java方法吗,我的程序发布不是运行在android平台上,直接生成exe运行在windows平台上
8楼  daisi1020 2012-05-09 19:29发表 [回复]
求教:我什么我这边运行出现这个呢
JNI: Unable to find method id for 'getX' (static)
UnityEngine.AndroidJavaObject:CallStatic(String, Object[])
CompassJNI:Update() (at Assets/CompassJNI.cs:31)
Re:  gene_feng 2012-06-05 17:51发表 [回复]
回复daisi1020:发布到手机上就可以了
7楼  zzd406405137 2012-05-03 09:32发表 [回复]
Screen.sleepTimeout = 0;//防止休眠
6楼  scell3 2011-11-12 00:56发表 [回复]
请教下下博主 
据说在AndroidMainfest.xml的<intent-filter>里
加一句
<action android:name="android.service.wallpaper.WallpaperService" />
就可以把APK变成动态桌面??
是这样吗?
Re:  羽化 2011-11-12 08:54发表 [回复]
回复scell3:我记得做壁纸还要继承WallpaperService吧,Unity没试过,就算成功做壁纸了,效率应该也不高,费电。。。
5楼  风里疯语 2011-10-22 16:21发表 [回复]
阻止屏幕休眠的语句在哪呢?我只看到你添加了这个权限。
Re:  羽化 2011-10-22 16:31发表 [回复]
回复xiawei32:getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON,WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
权限只是安装时的提示 这句才是关键~
Re:  风里疯语 2011-10-26 13:36发表 [回复]
回复libeifs:你的jdk版本是多少的? 我用的是jdk1.6.0_21的。 用你打的包测试 运行正确。 为什么同样是你的代码,我打包后,就运行出错了呢?我只不过是重新打包了一下。
Re:  Chiuan 2012-02-29 16:30发表 [回复]
回复xiawei32:我也是。同样的代码。为何我重新build处理后安装却报错了??
Re:  羽化 2011-10-26 13:55发表 [回复]
回复xiawei32:工程文件都提供下载的 代码没有问题 配置需求已经给出 很多网友已经测试成功并且研究出新的成果-0- 仔细检查下文件位置、uunity设置和xml,写个简单的代码测试下
4楼  yuyixiaoxiang 2011-10-16 06:25发表 [回复]
请问一下,在unity中如何调用android jar包中的非静态方法??
在你的例子中,只是调用了三个静态的方法???
Re:  羽化 2011-10-16 11:34发表 [回复]
回复yuyixiaoxiang:不好意思 这方面暂时无需求 也没有做过测试 羽化个人认为应该只能调用静态方法 你也可以试试使用NDK或者别的方式
3楼  playbeyond 2011-10-08 22:35发表 [回复]
因为Unity3d,关注你的博客有一段时间了。我是极端的菜鸟中的菜鸟(垃圾学校的在校生),现遇一诡异问题百思不得其解,遂求问博主(可能问题比较模糊)。就是默认做的windows版的项目变更为Android版后(Switch Platform),原先写没问题的javascripts大量报错。(几百个错啊!偶痛苦地闭上了眼睛。)
Re:  羽化 2011-10-09 00:06发表 [回复]
回复playbeyond:额 羽化也不是什么好学校毕业-0- 你说的这个问题很正常 ,有些接口是有平台限制的,但也不会有“大改”,仔细看下吧,多半是没声明变量之内的。
2楼  fendou123456 2011-09-22 18:15发表 [回复]
请问一下! 我现在导出 apx 格式 ,就是直接 bulid and run!
怎么快速传送到 Android上! 并且 在上面运行?
谢谢!!
Re:  羽化 2011-09-23 08:47发表 [回复]
回复fendou123456:Build & Run 第一次手动生成APK后就会自动运行在Android上 后面都是Unity自动替换APK 直接运行到Android设备上 一般新建个工程后Buiding Setting里面切换到Android平台 更改Player Settings里面的Bundle Identifier有时候会更具测试机更改Device Filter
Re:  fendou123456 2011-09-23 09:27发表 [回复]
回复libeifs:好的~~ 谢谢呀! 以后多交流交流!
你有没有Email 联系方式? 我是个游戏新手,找个伙伴! 哈哈!
Re:  羽化 2011-09-23 09:41发表 [回复]
回复fendou123456:QQ 675517707 邮箱就是QQ邮箱-0- 我也是新手 共同进步~ ~
1楼  waqa1988 2011-09-21 10:12发表 [回复] [引用] [举报]
请问这build and run 后,显示的效果是什么,或者如何看到效果呢?
Re:  羽化 2011-09-21 10:21发表 [回复] [引用] [举报]
回复waqa1988:如果你Usb连接手机,驱动没有问题的话就会Build & Run直接运行这个Unity的程序了,效果应该是中间显示xyz轴的数值 右下角应该有个按钮。 话说打开这个项目以后还要双击Android12后运行才能看到效果,因为羽化把它添加到Sences In Build里面。。。









为android构建一个插件


要创建一个android插件,首先要有 Android NDK 并熟悉使用ndk构建共享库的方法。

如果用C++来实现库,必须声明成用C语言的链接方式,以避免Name Mangling问题。

[cpp]  view plain copy
  1. extern "C"   
  2. {  
  3.   float FooPluginFunction ();  
  4. }   

通过C#脚本使用插件

构建了共享库后,必须把共享库复制到unity3d工程中的Assets->Plugins->Android目录下。(没有该目录的话,自己依次创建。)

当你在unity3d中在C#脚本中定义如下的函数时,unity3d就能通过名称找到共享库

[csharp]  view plain copy
  1. [DllImport ("PluginName")]  
  2. private static extern float FooPluginFunction ();   

注意 PluginName 不要包含共享库文件名中的“lib”前缀和“.so”后缀。建议所有的native代码方法都用C#代码封装一层,并在C#代码中检查 Application.platform 变量,以保证只有app运行在正确的设备上时,才去调用native方法。当在Editor环境下运行时,可以在C#代码中返回空值。

当然也可以用平台宏定义的方法,来控制与平台相关的代码的编译。


部署

对于要部署到多个平台的项目,项目工程中必须包含各个平台所需要的插件(例如:libPlugin.so用于android平台,Plugin.bundle用于mac平台,Plugin.dll用于windows平台)。unity3d会自动为目标平台选择正确的插件。


使用java插件

android插件机制同样允许使用java来与android系统进行交互。


为android构建一个java插件

有好几种方法来构建java插件,最终结果都是生成包含.class文件的.jar包。一种方法是下载 JDK,在命令行下用javac命令编译,用jar命令打包成jar文件;另一种方法是 Eclipse+ADT。


在native代码中使用java插件

构建好了java插件后,将java插件(.jar)复制到 unity3d工程中的Assets->Plugins->Android文件夹下面,unity3d会将你的.class文件和其余的java代码打包,并通过Java Native Interface (JNI)来访问这些代码。JNI既可以用于java代码调用native代码,也可用于native代码与java(java虚拟机)的交互。


要找到你的java代码,必须要能访问到java虚拟机。幸运的是,可以通过在c/c++代码中添加如下函数来很容易的实现这种访问:

[cpp]  view plain copy
  1. jint JNI_OnLoad(JavaVM* vm, void* reserved)   
  2. {  
  3.   JNIEnv* jni_env = 0;  
  4.   vm->AttachCurrentThread(&jni_env, 0);  
  5. }   

这个是从c/c++调用java所必需的。JNI超越了本文档的范畴,不做详细解释。通常情况下,先找到类的定义,然后解析类的构造方法(<init>)并创建类的实例,如下面例子所示:

[cpp]  view plain copy
  1. jobject createJavaObject(JNIEnv* jni_env)   
  2. {  
  3.   jclass cls_JavaClass = jni_env->FindClass("com/your/java/Class");          // 找到类定义  
  4.   jmethodID mid_JavaClass = jni_env->GetMethodID (cls_JavaClass, "<init>",  "()V");        // 找到构造方法  
  5.   jobject obj_JavaClass = jni_env->NewObject(cls_JavaClass, mid_JavaClass);      // 创建对象实例  
  6.   return jni_env->NewGlobalRef(obj_JavaClass);                       // return object with a global reference  
  7. }   

通过帮助类来使用java插件

使用AndroidJNIHelper 和AndroidJNI会减轻些使用原始JNI的痛苦。


AndroidJNIHelper 和AndroidJNI自动完成了很多任务(指找到类定义,构造方法等),并且使用缓存使调用java速度更快。AndroidJavaObjectAndroidJavaClass基于AndroidJNIHelper 和AndroidJNI创建,但在处理自动完成部分也有很多自己的逻辑,这些类也有静态的版本,用来访问java类的静态成员。


你可以选择任意你喜欢的方式来替代这种原始JNI的做法,可以通过 AndroidJNI类,也可以通过AndroidJNIHelperAndroidJNI 最后也可以使用 AndroidJavaObject/AndroidJavaClass,这样会有最大程度的自动完成和最大的便利性。


UnityEngine.AndroidJNI是对那些c代码可用的JNI调用的封装,该类中的所有方法都是静态的并且一一对应到JNI。

UnityEngine.AndroidJNIHelper通过public方法提供了一些不常用的辅助功能,在某些特殊情况下会比较有用处。


在java端,UnityEngine.AndroidJavaObject和UnityEngine.AndroidJavaClass的实例分别一一对应于 java.lang.Object和java.lang.Class (或它的子类)的实例。它们提供了3种与java端交互的方法:

  • Call方法
  • Get域的值
  • Set域的值

    Call分为两类,调用void方法和调用非void返回类型的方法,会使用一个泛型类型来表示这些非void返回类型的方法的返回类型;Get和Set也经常带一个泛型类型用以表示域的类型。


    例子1:

    [cpp]  view plain copy
    1. //注释表示是使用原始JNI方法必须做的工作  
    2.  AndroidJavaObject jo = new AndroidJavaObject("java.lang.String""some_string");   
    3.  // jni.FindClass("java.lang.String");   
    4.  // jni.GetMethodID(classID, "<init>", "(Ljava/lang/String;)V");   
    5.  // jni.NewStringUTF("some_string");   
    6.  // jni.NewObject(classID, methodID, javaString);   
    7.  int hash = jo.Call<int>("hashCode");   
    8.  // jni.GetMethodID(classID, "hashCode", "()I");   
    9.  // jni.CallIntMethod(objectID, methodID);  
    这个例子中,我们创建了一个 java.lang.String的实例,并用我们自定义的一个字符串初始化它,最后我们得到该字符串的哈希值。


     AndroidJavaObject的构造方法至少需要一个参数----你想要实例化的类的名称。类名之后的参数会被对象的构造函数所使用,如上例种的字符串“
    some_string”,随后的对hashCode方法的Call会返回一个int型值,这也是为什么我们会传一个泛型参数给Call方法。


    注意:不能使用点.来初始化一个嵌套类型,内部类必须使用$分隔符,在斜线/或点.分隔的类名中都可以使用。所以当类LayoutParams嵌套在ViewGroup类中时,android.view.ViewGroup$LayoutParams或者android/view/ViewGroup$LayoutParams,这两种方式都是可行的。


    例子2:

    上面有个插件的例子是说获取当前程序的缓存目录的,下面这个例子直接用c#代码做同样的事情,而不需要任何插件:

    [csharp]  view plain copy
    1. AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer");   
    2. // jni.FindClass("com.unity3d.player.UnityPlayer");   
    3. AndroidJavaObject jo = jc.GetStatic<AndroidJavaObject>("currentActivity");   
    4. // jni.GetStaticFieldID(classID, "Ljava/lang/Object;");   
    5. // jni.GetStaticObjectField(classID, fieldID);   
    6. // jni.FindClass("java.lang.Object");   
    7.   
    8. Debug.Log(jo.Call<AndroidJavaObject>("getCacheDir").Call<string>("getCanonicalPath"));   
    9. // jni.GetMethodID(classID, "getCacheDir", "()Ljava/io/File;"); // or any baseclass thereof!   
    10. // jni.CallObjectMethod(objectID, methodID);   
    11. // jni.FindClass("java.io.File");   
    12. // jni.GetMethodID(classID, "getCanonicalPath", "()Ljava/lang/String;");   
    13. // jni.CallObjectMethod(objectID, methodID);   
    14. // jni.GetStringUTFChars(javaString);  

    这个例子中,我们没有首先使用AndroidJavaObject,而是AndroidJavaClass ,因为我们想获取类com.unity3d.player.UnityPlayer的一个静态成员,而不是去创建一个新的对象(Android UnityPlayer会自动创建一个实例)。我们访问其静态域"currentActivity" ,这个时候我们用的是AndroidJavaObject作为泛型参数,这是因为实际类型(android.app.Activity)是类java.lang.Object的子类,任意非基本类型都必须作为AndroidJavaObject来访问。有一个例外就是字符串,字符串可以直接访问,尽管它在java中并不是基本类型。


    之后就是调用的Activity的getCacheDir()得到缓存目录的文件对象,再调用getCanonicalPath()方法获取缓存目录路径的字符串表示。


    当然,现在已经不需要通过这种方式来获取缓存目录了,因为unity3d提供了接口用以访问程序的缓存目录和数据目录,也就是Application.temporaryCachePath and Application.persistentDataPath。


    例子3:

    最后,是一个通过UnitySendMessage方法从java代码向脚本代码传递数据的小窍门。

    [csharp]  view plain copy
    1. using UnityEngine;   
    2. public class NewBehaviourScript : MonoBehaviour   
    3. {   
    4.   
    5. <span style="white-space:pre">  </span>void Start ()   
    6. <span style="white-space:pre">  </span>{   
    7.     <span style="white-space:pre">  </span>JNIHelper.debug = true;   
    8.     <span style="white-space:pre">  </span>using (JavaClass jc = new JavaClass("com.unity3d.player.UnityPlayer"))   
    9. <span style="white-space:pre">      </span>{   
    10. <span style="white-space:pre">  </span>     jc.CallStatic("UnitySendMessage""Main Camera""JavaMessage""whoowhoo");   
    11.     <span style="white-space:pre">  </span>}   
    12.     }   
    13.   
    14.     void JavaMessage(string message)   
    15. <span style="white-space:pre">  </span>{   
    16.         Debug.Log("message from java: " + message);   
    17.     }  
    18. }   


    com.unity3d.player.UnityPlayer现在有一个静态方法UnitySendMessage,与iOS中native端的UnitySendMessage一样,可用来在java中向脚本传递数据。


    这里我们直接从脚本中调用的,但它确实是在java端发送的消息,它会调回到unity3d的native代码,传递消息到名为"Main Camera"的游戏对象上去,该对象上绑定的某个脚本中包含有名为"JavaMessage"的方法。


    在unity3d中使用java插件的最佳实践
    这一节主要针对那些没有足够jni,java和android经验的人。假设我们在unity3d中使用AndroidJavaObject/AndroidJavaClass来与java交互。


    首先就是要注意对AndroidJavaObject/AndroidJavaClass的任何操作都是很费时的(是通过JNI来进行的)。因此为了代码性能和代码清晰性,我们强烈建议托管代码与native/java代码间的转换次数保持在最小数量。


    你可以定义一个java方法完成所有的事情,然后我们通过AndroidJavaObject/AndroidJavaClass来与这个方法通信和获取结果,我们的JNI帮助类会尽可能多的缓存数据已提高性能。

    [csharp]  view plain copy
    1. //第一次像这样调用java函数  
    2. AndroidJavaObject jo = new AndroidJavaObject("java.lang.String""some_string");  // 有点费时  
    3. int hash = jo.Call<int>("hashCode");  //第一次 - 费时  
    4. int hash = jo.Call<int>("hashCode");  // 第二次 - 不那么费时, 因为我们已经知道了这个java方法,可以直接调用它。  

    在使用过后,Mono垃圾回收器会释放所有创建的AndroidJavaObjectAndroidJavaClass实例,但我们还是建议把它们放到using(){}块中,以保证它们能被尽快的清除掉。除此之外,你无法保证它们会被销毁掉。如果你设置了AndroidJNIHelper.debug为true,你会在log输出中看到垃圾回收器的活动记录。

    [csharp]  view plain copy
    1. //获取系统语言的安全方法  
    2. void Start ()   
    3. {   
    4.     using (AndroidJavaClass cls = new AndroidJavaClass("java.util.Locale"))   
    5. <span style="white-space:pre">  </span>{   
    6.         using(AndroidJavaObject locale = cls.CallStatic<AndroidJavaObject>("getDefault"))   
    7. <span style="white-space:pre">      </span>{   
    8.             Debug.Log("current lang = " + locale.Call<string>("getDisplayLanguage"));   
    9.   
    10.         }   
    11.     }   
    12. }  


    也可以直接调用.Dispose()方法确保没有java对象残留,c#对象会存活长一点,最终还是会被mono的垃圾回收器回收。

    继承UnityPlayerActivity java代码


    在Unity Android上,我们可以继承标准的UnityPlayerActivity类(android上Unity Player的主要java类,类似于Unity iOS上的AppController.mm)。


    应用程序可以覆写android系统与Unity Android之间的任意交互方法,只要新建一个Activity继承UnityPlayerActivity就可以实现。(在mac系统上,UnityPlayerActivity.java在/Applications/Unity/Unity.app/Contents/PlaybackEngines/AndroidPlayer/src/com/unity3d/player目录下;在windows系统中,它通常在C:\Program Files\Unity\Editor\Data\PlaybackEngines\AndroidPlayer\src\com\unity3d\player目录下)


    首先定位Unity Android的classes.jar文件,可以在Unity3d的安装目录(windows下通常是C:\Program Files\Unity\Editor\Data,mac下是/Applications/Unity)下的子文件夹PlaybackEngines/AndroidPlayer/bin中找到,将它添加到你编译activity的classpath中。最终编译出来的.class文件,需要打包成.jar文件,放到工程中的Assets->Plugins->Android目录下。因为android中manifest文件指明了启动哪个Activity,因此我们也需要重新写一个AndroidManifest.xml文件,也需要将它放到Assets->Plugins->Android目录下。


    继承UnityPlayerActivity的一个例子,OverrideExample.java:

    [java]  view plain copy
    1. package com.company.product;  
    2.   
    3. import com.unity3d.player.UnityPlayerActivity;  
    4.   
    5. import android.os.Bundle;  
    6. import android.util.Log;  
    7.   
    8. public class OverrideExample extends UnityPlayerActivity {  
    9.   
    10.   protected void onCreate(Bundle savedInstanceState) {  
    11.   
    12.     // call UnityPlayerActivity.onCreate()  
    13.     super.onCreate(savedInstanceState);  
    14.   
    15.     // print debug message to logcat  
    16.     Log.d("OverrideActivity""onCreate called!");  
    17.   }  
    18.   
    19.   public void onBackPressed()  
    20.   {  
    21.     // instead of calling UnityPlayerActivity.onBackPressed() we just ignore the back button event  
    22.     // super.onBackPressed();  
    23.   }  
    24. }   

    相关的AndroidManifest.xml文件如下:

    [html]  view plain copy
    1. <?xml version="1.0" encoding="utf-8"?>  
    2. <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.company.product">  
    3.   <application android:icon="@drawable/app_icon" android:label="@string/app_name">  
    4.     <activity android:name=".OverrideExample"  
    5.               android:label="@string/app_name"  
    6.               android:configChanges="fontScale|keyboard|keyboardHidden|locale|mnc|mcc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|uiMode|touchscreen">  
    7.         <intent-filter>  
    8.             <action android:name="android.intent.action.MAIN" />  
    9.             <category android:name="android.intent.category.LAUNCHER" />  
    10.         </intent-filter>  
    11.     </activity>  
    12.   </application>  
    13. </manifest>   


    UnityPlayerNativeActivity

    同样我们可以创建UnityPlayerNativeActivity的子类,这与创建UnityPlayerActivity的子类具有相同的效果,但是会有较小的输入延迟。但是,需要明白的是,NativeActivity是在Gingerbread中引入的(即android 2.3),老的android版本没有这个特性,因为在NativeActivity中,触摸事件都是在native代码中处理的,java视图正常情况下是无法获取这些事件的,不过在unity3d中,有允许将事件传到DalvikVM的转发机制,要应用这个转发机制,必须修改manifest文件如下:

    [html]  view plain copy
    1. <?xml version="1.0" encoding="utf-8"?>  
    2. <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.company.product">  
    3.   <application android:icon="@drawable/app_icon" android:label="@string/app_name">  
    4.     <activity android:name=".OverrideExampleNative"  
    5.               android:label="@string/app_name"  
    6.               android:configChanges="fontScale|keyboard|keyboardHidden|locale|mnc|mcc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|uiMode|touchscreen">  
    7.   <meta-data android:name="android.app.lib_name" android:value="unity" />  
    8.   <meta-data android:name="unityplayer.ForwardNativeEventsToDalvik" android:value="true" />  
    9.         <intent-filter>  
    10.             <action android:name="android.intent.action.MAIN" />  
    11.             <category android:name="android.intent.category.LAUNCHER" />  
    12.         </intent-filter>  
    13.     </activity>  
    14.   </application>  
    15. </manifest>   

    要注意activity元素中的.OverrideExampleNative属性,还有两条meta-data元素,第一条meta-data元素指明使用unity3d库libunity.so,第二条meta-data元素使事件能传递到你创建的UnityPlayerNativeActivity子类中。


    例子


    native插件例子

    这里有一个简单的使用native插件的例子。

    这个例子演示了如果从unity3d android程序中来调用c代码,包中包含了一个通过native插件计算出来的两个数之和的场景,要注意,你必须用Android NDK来编译这个插件。


    java插件例子

    这里有一个简单的使用java代码的例子。


    这个例子演示了怎么用java代码与android系统进行交互,以及如何用c++来将c#和java沟通起来,包中的场景显示了一个按钮,点击该按钮,会显示出程序在android系统中的缓存目录路径。需要JDK和 Android NDK来编译这个插件。


    这里有一个相似的例子,但是是基于预先编译好的JNI库,来封装native代码,供c#调用。


    最后更新于:2012-09-25












  • 你可能感兴趣的:(Unity3d AndroidJNI两篇应用示例。羽化的文章。)