iOS与Unity3D交互

3,824 阅读5分钟

最近游戏组让配合开发一个 “在Unity中点击按钮弹出原生二维码扫码页面 -> 再把获取到的二维码信息传回给Unity” 的功能,于是我就开始了学习iOS与Unity3d交互的不归路~。

由于对Unity不熟,导出的Xcode工程跟平时用的Xcode也有些差异,遇到了很多没遇到过的问题,只能慢慢摸索,慢慢解决。

刚开始在网上下载下来的Xcode Demo无法在真机上运行(在模拟器上正常)、添加不了Pod,只好自己新建一个干净的Unity工程,仿照Unity Demo编写交互代码再重新导出Xcode工程,没有问题了再对接二维码扫码的功能。

在Unity中点击按钮“跳转iOS” -> 在App中扫描二维码并把结果返回给Unity -> 在Unity中显示“二维码内容XXX”:

.

一、代码实现:

1、Unity代码:

添加一个C#文件,添加实现代码。

// Unity代码
using UnityEngine;
using System.Collections;
using System.Runtime.InteropServices;

public class Test : MonoBehaviour {
    public GameObject cube;

    // DllImport这个方法相当于是告诉Unity,有一个unityToIOS函数在外部会实现。
    // 使用这个方法必须要导入System.Runtime.InteropServices;
    [DllImport("__Internal")]
    private static extern void unityToIOS ( string str );

    public string scanStatus;//二维码扫描结果

    void OnGUI(){
	// 当点击按钮后,调用外部方法
	if (GUI.Button (new Rect (100, 100, 200, 60), "跳转IOS")) {
	    // Unity调用ios函数,同时传递数据
	    unityToIOS ("Hello IOS");
	}

        //控件要写在GUI里面 可以设置一个全局str,赋值,OnGUI是每秒都会自动刷新。
	GUI.Label (new Rect (100, 200, 400, 60), scanStatus);
    }

    // 用户取消了扫码
    void cancelScan(string str){
	scanStatus = str;
    }

    // 获取二维码成功
    void getQRSuccess(string str){
	scanStatus = @"二维码内容:" + str;
    }

    // 向右转函数接口
    void turnRight(string num){
	float f;
	if (float.TryParse (num, out f)) {// 将string转换为float,数据之间的传递只能以string类型
	    Vector3 r = new Vector3 (cube.transform.rotation.x, cube.transform.rotation.y - 10f, cube.transform.rotation.z);
	    cube.transform.Rotate (r);
	} 
    }
}

2、iOS代码:

iOS端主要在UnityAppController.mm文件中编写代码 (创建一个LARManager.h文件并创建一些交互方法)。

// MARK: - 直接加载unity页面
- (void)startUnity:(UIApplication*)application{
    //新增代码
    [self showUnityPage];
    
    /* 隐藏了一些Unity代码 */
}

// MARK: - 展示Unity页面
- (void)showUnityPage {
    if ([LARManager sharedInstance].unityIsPaused) {
        UnityPause(false);//打开Unity
        [LARManager sharedInstance].unityIsPaused = NO;
        //设置rootView为Unity界面
        self.window.rootViewController = self.rootViewController;
    }
}

iOS调用Unity:通过UnitySendMessage方法实现。

UnitySendMessage("gameobject", "Method", msg);
参数一为unity脚本挂载的gameobject
参数二为unity脚本中要调用的方法名
参数三为传递的数据,*注意:传递的数据只能是char 类型


// MARK: - iOS传递事件给Unity  ScanDelegate
//取消扫描
- (void)cancelScan {
    [self showUnityPage];
    UnitySendMessage("Main Camera", "cancelScan", [@"取消扫描" UTF8String]);
}

//获取二维码信息成功
- (void)getQRSuccess:(NSString *)str{
    [self showUnityPage];
    UnitySendMessage("Main Camera", "getQRSuccess", [str UTF8String]);
}

- (void)turnRight{//右转
    const char* str = [[NSString stringWithFormat:@"10"] UTF8String];
    UnitySendMessage("Main Camera", "turnRight", str);//IOS调用Unity的方法,通过UnitySendMessage方法实现。
}

- (void)turnLeft{//左转
    const char* str = [[NSString stringWithFormat:@"10"] UTF8String];
    UnitySendMessage("Main Camera", "turnLeft", str);
}

Unity调用iOS:实现Unity的调用方法

// MARK: - Unity传递事件给iOS (跳转到iOS界面,Unity界面暂停)
 extern "C"{
    void unityToIOS(char* str){// 对Unity中的unityToIOS方法进行实现
        NSLog(@"*************%s",str);// Unity传递过来的参数
        UnityPause(true);//暂停Unity
        [LARManager sharedInstance].unityIsPaused = YES;
    
        //扫码页面
        ScanController *vc = [ScanController new];
        vc.delegate = GetAppController().self;//添加代理
        GetAppController().scanVC = vc;
        // GetAppController()获取appController,相当于self; UnityGetGLView()获取UnityView,相当于_window; 点击按钮后跳转到IOS界面,设置界面为IOS界面
        GetAppController().window.rootViewController = GetAppController().scanVC;
    }
}
 

.

二、遇到的问题:

1、在Unity中: C#脚本Test和控件Cube要建立好绑定关系,不然无效.

2、(巨坑:浪费了我不少时间~.~)

Xcode:打包出来没有在IOS中实现Unity定义的交互函数,运行Xcode就报错,还以为是在网上下载的demo代码有问题。 原因:
没有实现Unity定义的交互函数_unityToIOS

解决:
extern "C”{ 中实现相关函数

3、把IOS代码拖入工程后运行__weak typeof(self) wSelf = self 声明报错:

a parameter list without types is only allowed in a function definition。

原因:
可能是编译器识别不了typeof关键字

解决:
Apple LLVM 6.1 - Language设置C Language Dialect为Compiler Default或者GNU99[-std=gnu99]

4、继续报错

Undefined symbols for architecture arm64: "_kCGImagePropertyExifDictionary", referenced from: -[SGQRCodeObtain captureOutput:didOutputSampleBuffer:fromConnection:] in SGQRCodeObtain.o

原因:
引用第三方库时是直接把代码拖进工程的,可能漏了某些文件.

解决:
直接用pod导入第三方库.

5、用到了相机、相册或其他功能忘记添加访问权限配置,导致闪退

解决:
要在info.plist中添加访问权限配置

.

三、拓展:

1、Unity导出Xcode工程:

下载好Unity项目并打开 -> File -> Building Setting -> iOS-> Switch Platform -> Add Open Scenes -> Player Setting -> .NET 2.0 -> Build

a、首先在File->Build Settings

b、选择iOS,第一次装的时候需要先下载一个iOS支持文件,下载完成后安装。

重启unity->Build(release)
这样就创建成功一个苹果工程了
选择iOS后要点击Switch Platform,不然打不了iOS包

点击player settings->Target SDK可以选择映射出来的苹果项目是运行于模拟器的还是真机的。

2、打包上架遇坑:

在给游戏打苹果包的时候,发现在最后一步一直显示Compiling bitcode超时

原因:
Enable Bitcode设置的YES,工程进行了Bitcode编译很耗时。我查看了其他工程都是设置的NO

解决:
Build Settings->Enable Bitcode设置为NO

.

3、探索:(待完善)

游戏端的代码更新了,最好可以直接在原有的Xcode工程上替换unity相关文件,而不需要每次都重新生成Xcode工程,再在新工程上重新写一遍IOS代码;
如果必须每次都写一遍的话,那就把代码封装到工具类中,每次只需要拖入工具并改少量的代码就行。把iOS代码复用性做到最高,耦合性降到最低。

扫码相关的内容就不细说了,可以下载我的代码 MyUnityToIOS 了解 提取码:feeg。里面有Unity和Xcode两端的代码,感兴趣的可以自己下载下来慢慢看~.~

资料

iOS与Unity3d交互
Unity里调用iOS原生
Unity3D与iOS的交互
swift-unity