Unity3D与Android,iOS交互

一. 写在前面

最近由于业务需求,对Unity3D与Android,iOS平台交互有所了解,特此记录和分享。

二. 准备工作

1)我使用的Unity版本是4.6.3,eclipse+ADT开发环境,以及Xcode7.2;
2)unity脚本采用C#编写。

三. 开始

2.1 Unity脚本部分

若要在C#脚本中调用OC方法,须引入系统库:
using System.Runtime.InteropServices
要在C#脚本中调用Android部分方法,先定义如下方法:

#if UNITY_ANDROID
    public AndroidJavaObject androidContext() {
        return new AndroidJavaClass("com.unity3d.player.UnityPlayer").GetStatic<AndroidJavaObject>("currentActivity");
    }
    #endif

获取android当前Activity的引用,然后使用该引用调用其他方法。
获取引用还有一种写法,但个人认为以上方法更具普遍性,故不在这里讨论。

1)调用无参方法

iOS:
对要调用的方法进行定义:
[DllImport ("__Internal")]
private static extern void _showUI();

须注意的是,Internal前面是2个下划线,DllImport后面有个空格。


Android:无须其他操作。


此时,就可以在C#代码中使用该方法:

if (GUILayout.Button ("显示一个对话框", GUILayout.Height (100), GUILayout.Width (400))) {
            #if UNITY_IOS
            _showUI();
            #elif UNITY_ANDROID
            androidContext().Call("showUI");
            #endif
        }

android部分调用,第一个参数为要调用的参数名字,类型为string。

2)调用有参方法

iOS:
对方法进行定义:

[DllImport ("__Internal")]
private static extern void _passParameter(string name,int age);

Android:无须其他操作


在C#中调用该方法:

if (GUILayout.Button ("传递参数", GUILayout.Height (100), GUILayout.Width (400))) {
            #if UNITY_IOS
            _passParameter("Jerry",24);
            #elif UNITY_ANDROID
            androidContext().Call("passParameter","Jerry",24);
            #endif
        }

android部分,方法参数紧跟在方法名称参数之后。
目前应该只支持string 和int类型参数。

3)调用有返回值的方法

iOS:
对方法进行定义:

[DllImport ("__Internal")]
    private static extern string _getReturnValue();

Android:无须其他操作


在C#中调用:

if (GUILayout.Button ("有返回值的方法", GUILayout.Height (100), GUILayout.Width (200))) {
            string value = "";
            #if UNITY_IOS
            value = _getReturnValue();
            #elif UNITY_ANDROID
            value = androidContext().Call<string>("getReturnValue");
            #endif
        }

留意android部分,有返回值的方法调用,和无返回值的方法略有不同。

4)接收回调信息

iOS:
定义该方法:

[DllImport ("__Internal")]
private static extern void _receiveCallback(string gameObject,string callbackMethod);

Android:无须其他操作


在C#中调用:

if (GUILayout.Button ("有回调的方法", GUILayout.Height (100), GUILayout.Width (200))) {
            #if UNITY_IOS
            _receiveCallback(this.gameObject.name,"callback");
            #elif UNITY_ANDROID
            androidContext().Call("receiveCallback",this.gameObject.name,"callback");
            #endif
        }

往unity部分发送回调信息,需要知道回调方法名称,以及该方法所属的GameObject的名字,因此,从方法参数中传入这2个值。

注:也可以采用其他方式,如在配置文件中配置,或约定方法名称,预制体名称。


2.2 Android部分

在eclipse中新建一个android工程,从unity的安装路径下取出classes.jar放到libs目录下。

classes.jar目录
Mac:Unity.app右键show package contents,然后Contents->PlaybackEngines->AndroidPlayer->developement->bin目录下
Windows:unity安装目录->Editor->Data->PlaybackEngines->AndroidPlayer->development->bin目录下

1)新建一个Activity:

public class MainActivity extends UnityPlayerActivity {

    @Override
    protected void onCreate(Bundle arg0) {
        super.onCreate(arg0);
    }

    public void showUI() {
        AlertDialog.Builder builder = new Builder(this);
        builder.setMessage("我是个对话框").show();
    }

    public void passParameter(String name,int age) {
        Toast.makeText(this, name + "is" + age, Toast.LENGTH_LONG).show();
    }

    public String getReturnValue() {
        return "hello";
    }

    public void receiveCallback(String gameObject,String callback) {
        UnityPlayer.UnitySendMessage(gameObject, callback, "I am a callback");
    }

}

使其继承UnityPlayerActivity,然后实现刚才在C#需要调用的方法;
以上代码简洁清楚,不再赘述。
须注意的是,向Unity部分发送回调信息,使用方法:
UnityPlayer.UnitySendMessage(String,String,String)
第一个参数为接收该信息的预制体GameObject名称,第二个参数为接收信息的方法,该方法所在脚本须与上述GameObject绑定,第三个参数为回调消息,即回调方法的参数。


2)配置AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.leaf.blogdemo"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="18"
        android:targetSdkVersion="19" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity 
            android:name="com.leaf.blogdemo.MainActivity"
            android:screenOrientation="landscape">
            <intent-filter >
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
    </application>

</manifest>

3)导出jar包
将所有源码导出成jar包。

4)Unity工程修改
将3)导出的jar包放在Assets->Plugins->Android->bin目录下(目录没有时请创建),若android工程中libs下有引用其他jar包,请放在Android->libs目录下;
将配置好的AndroidManifest.xml文件放在Android目录下;
将assets目录复制到Android目录下;
将res目录复制到Android目录下。

5)导出apk
以上步骤操作无误后,先检查导出环境:
Mac:Unity->Preferences->External Tools->Android SDK Location
Windows:Edit->Preferences->External Tools->Android SDK Location

该配置项设置Android SDK目录。(须注意的是,不同的unity版支持的android sdk不同,若版本不匹配时,可能出现导出错误。)

SDK配置无误后,开始导出:File->Build Settins…
apk导出

在Player Settings里可对导出的apk属性进行设置,不详述,点击Build,导出apk后,可安装进行测试。


2.3 iOS部分

1)导出Xcode工程
File->Build Settings…选择iOS平台,导出Xcode工程;
2)编写oc方法
在导出的Xcode工程中,新建一个.mm文件,开始coding,实现在C#中调用的方法,方法体需要采用C语言格式:
iOS与unity交互组件

主要代码如下:

extern "C" {
    void _showUI()
    {
        UIAlertView *view = [UIAlertView new];
        view.message = @"我是一个对话框";

        [view addButtonWithTitle:@"确定"];
        [view dismissWithClickedButtonIndex:0 animated:YES];
        [view show];
    }

    void _passParameter(const char* name,int age)
    {
        NSLog(@"%@ is %d",cStr2NStr(name),age);
    }

    const char* _getReturnValue()
    {
        return MakeStringCopy("hello");
    }

    void _receiveCallback(const char* gameObject,const char* callback)
    {
        UnitySendMessage(gameObject, callback, "I am a callback");
    }
}

以上代码片段还有一个写法:

@interface iBlogDemo : NSObject

@end

@implementation iBlogDemo

void _showUI()
{
    UIAlertView *view = [UIAlertView new];
    view.message = @"我是一个对话框";

    [view addButtonWithTitle:@"确定"];
    [view dismissWithClickedButtonIndex:0 animated:YES];
    [view show];
}

void _passParameter(const char* name,int age)
{
    NSLog(@"%@ is %d",cStr2NStr(name),age);
}

const char* _getReturnValue()
{
    return MakeStringCopy("hello");
}

void _receiveCallback(const char* gameObject,const char* callback)
{
    UnitySendMessage(gameObject, callback, "I am a callback");
}


@end

但此时,文件后缀只能为.m,否则会报错。


_showUI方法是利用iOS API显示了一个简单的对话框;
_passParameter须注意的是,c#当中的string对应过来是const char*类型,二者可互相转换:

//convert const char* to NSString
NSString* cStr2NStr(const char* cstr) {
    return [[NSString alloc] initWithCString:cstr encoding:NSUTF8StringEncoding];
}

_getReturnValue有返回值的方法,须注意的是,目前只能返回string值,并且,在返回时,需要进行特殊处理:

// By default mono string marshaler creates .Net string for returned UTF-8 C string
// and calls free for returned value, thus returned strings should be allocated on heap
char* MakeStringCopy (const char* string)
{
    if (string == NULL)
        return NULL;

    char* res = (char*)malloc(strlen(string) + 1);
    strcpy(res, string);
    return res;
}

否则会出现空指针异常。
_receiveCallback在oc中向Unity发送回调信息时,是用于android类似的方法:

UnitySendMessage(const char* obj, const char* method, const char* msg);

各参数意义,与android一样。

3)步骤2)可以提前在导出Xcode工程之前进行
新建一个静态库(或动态库)工程,新建.mm(或.m)文件,实现方法;

#ifdef __cplusplus
extern "C" {
#endif

    void UnitySendMessage(const char* obj, const char* method, const char* msg);

#ifdef __cplusplus
}
#endif

源码中的以上声明,其实就是为了在此种方式下,调用该方法而不报错。
在Unity导出的Xcode工程中,该项声明可以在iPhone_target_prefix.h中找到,该文件是Xcode的一个预编译文件
因此,若按照方法2),其实以上声明可以去掉;

这种方式开发时,可以将编写完成的代码,编译成.a或者.framework文件,或者也可以保留成源码文件。

coding完成后,在Unity工程的Plugins目录下,新建iOS目录,将源文件放在该目录下,然后导出Xcode工程,源文件会出现在Xcode工程的Libraries目录下。
须注意,只能放在iOS下不可嵌套目录,否则无法识别。

若已编译成库文件,则只能在导出Xcode工程后,再引入。
在Unity官方文档中,都有这些说明,扔个链接:Getting Started with iOS Development

4)运行工程,就可以出现与android类似的效果。
unity与iOS存在编码问题,因此中文会乱码,此问题没有在Demo中解决。

三. 其他

有时运行会报找不到libiPhone-lib.a库的错误,这时,修改一下Build Settings里面的Library Search paths即可。

Demo链接地址:Demo

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Unity3D是一款广泛应用于游戏开发的跨平台游戏引擎。施耐得是Unity Technologies公司的创始人之一,他在Unity3D的发展中起到了重要的作用。 施耐得(David Helgason)在2002年参加了一次由埃里克·维肯德与乔尔·比奇在哥本哈根举办的游戏开发者大会,此次会议激发了施耐得对游戏开发的兴趣。2003年,他与Nicholas Francis一起开发了一个基于游戏引擎的项目,并开始意识到游戏开发过程中的种种困难与挑战。 为了解决这些问题,施耐得与Francis以及Joachim Ante一起创立了Unity Technologies公司,并开发出了Unity3D游戏引擎。Unity3D于2005年首次发布,并且在发布后的几年间持续更新与改进。 Unity3D的特点之一是其跨平台性,它可以在多个不同的操作系统和设备上运行,包括Windows、Mac、iOSAndroid等。这使得开发者可以用统一的代码和资源开发一次,然后在不同平台上部署游戏。 Unity3D提供了丰富的功能和工具,包括可视化的场景编辑器、强大的物理引擎、音频引擎、动画系统等。此外,Unity3D还支持脚本编程,开发者可以使用C#或JavaScript等语言编写游戏逻辑和交互行为。 通过Unity3D的开发人员社区,开发者可以互相交流经验、分享资源和解决问题。这个社区的活跃度和支持使得Unity3D成为了业界最受欢迎和广泛应用的游戏引擎之一。 总之,Unity3D的成功与施耐得在其创立与发展中的贡献密不可分。施耐得的愿景和努力使得Unity3D成为了一款功能强大、易于使用的游戏引擎,为游戏开发者提供了一个快速、高效的开发平台。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值