iOS4U3D插件开发


目标

实现Unity中调用iOS原生方法,并传递参数;实现iOS方法中调用Unity3D中的方法,并传递参数,本文主要教会大家开发方式与流程,具体需要在iOS原生代码下执行哪些功能,因人而异,可自由发挥。

实现方法

鉴于iOS开发可使用oc或swift语言,同时支持c与c++代码混合开发,各位看官用什么语言请自行变通、不必过于死板,本文以oc为例。

  1. 网上大多的方法是创建.mm文件并编写相应的oc与c++的代码,实现相关功能后将文件放入Unity3D中的Assets/Plugins/iOS文件夹下,然后编写对应的c#类文件引用.mm文件中的方法,从而完成互相调用;

  2. 理解过程及交互方式后,本文打算从Unity3D方向,也就是从c#代码到oc代码的方式来讲解这一插件开发过程;

  3. 首先在Unity3D中创建相应的c#脚本,定义你将使用到的功能函数,只要按特定方式定义即可,这就要求大家对自己要开发的功能明确清晰,此处以打开相册功能举例:

     [DllImport ("__Internal")]
     private static extern void _iosOpenPhotoLibrary (string unityGameObject, string unityMethodName);
    
     [DllImport ("__Internal")]
     private static extern void _iosOpenPhotoAlbums (string unityGameObject, string unityMethodName);
    
     void unityMethodName(string fileName) { // Do something.}
    
     // 这里的带有[DllImport ("__Internal")]标记的方法将对应到oc中的方法
     // 同时注意,方法声明需要添加extern前缀,我们的目的是调用iOS的方法打开相册选择图片
     // 同时,考虑到完成这一过程后,我们需要向Unity3D发送一个通知来调用相关的方法,而这个回调的方法为:
     UnitySendMessage(unityGameObject, unityMethodName, 传递的参数);
     // 因而我们在Unity3D中调用oc的方法的时候传递了对象名及方法名的参数给它,以此来实现动态的调用不同的对象上的不同方法
     // 注意这个方法的调用是不区分脚本名称的,只要是该对象上的脚本中存在该方法,就会被调用到,这里我们将被oc回调的函数直接创建在同一个脚本文件中;
    
  4. 编写完c#的脚本,现在让我们来编写oc的代码,你可以将Unity3D的工程导出成Xcode的工程,然后进行开发,或者直接新建一个Xcode的工程,然后进行oc代码的开发;

  5. 两种方法的不同点在于,第一种直接就可以边开发边调试了,而后者需要将实现好的功能代码拷贝到Unity3D中后再导出工程才可看具体效果,我们直接采用前者;

  6. 将Unity3D工程导出成为Xcode工程,在Unity3D工程中,iOS的代码文件是放在Assets/Plugins/iOS目录下的,导出后可在Xcode工程中的Libraries/Plugins/iOS目录下找到,因为我们是先导出工程在编写oc代码的,所以我们直接在Xcode对应的目录下创建oc代码文件,接下来我们就来编写下oc代码:

     // 头文件:IosPhotoHelper.h
     @interface IosPhotoHelper : UIViewController<UIImagePickerControllerDelegate,UINavigationControllerDelegate>
     @end
    
     // 实现文件:IosPhotoHelper.mm
     #import "IosPhotoHelper.h"
     @implementation IosPhotoHelper
     char _unityGameObject[30] = "Controller";
     char _unityMethodName[30] = "unityMethodName";
    
     - (void)showPicker:(UIImagePickerControllerSourceType)type allowsEditing:(BOOL)flag
     {
         UIImagePickerController *picker = [[UIImagePickerController alloc] init];
         picker.delegate = self;
         picker.sourceType = type;
         picker.allowsEditing = flag;
         [self presentViewController:picker animated:YES completion:nil];
     }
    
     - (void)imagePickerController:(UIImagePickerController*)picker didFinishPickingMediaWithInfo:(NSDictionary*)info
     {
         UIImage *rawImage;
    
         // 获取图像
         if (picker.allowsEditing) {
             rawImage = [info objectForKey:UIImagePickerControllerEditedImage];
         } else {
             rawImage = [info objectForKey:UIImagePickerControllerOriginalImage];
         }
    
         // 缩放图像
         UIGraphicsBeginImageContext(CGSizeMake(256,256));
         [rawImage drawInRect:CGRectMake(0, 0, 256, 256)];
         UIImage *scaledImage = UIGraphicsGetImageFromCurrentImageContext();
         UIGraphicsEndImageContext();
    
         // 获取图像数据
         NSData *imgData = UIImagePNGRepresentation(scaledImage);
         if(imgData == nil)
         {
             imgData= UIImageJPEGRepresentation(rawImage, 1.0);
         }
    
         // 保存图像到沙盒
         NSString *photoName = @"imageios.png";
         NSString *path = [[NSHomeDirectory() stringByAppendingPathComponent:@"Documents"] stringByAppendingPathComponent:photoName];
         [imgData writeToFile:path atomically:YES];
    
         // 关闭相册并通知Unity根据图像名称去获取图像
         [picker dismissViewControllerAnimated:YES completion:^{
             UnitySendMessage(_unityGameObject, _unityMethodName, photoName.UTF8String);
         }];
         [self dismissViewControllerAnimated:YES completion:nil];
     }
    
     - (void)imagePickerControllerDidCancel:(UIImagePickerController*)picker
     {
         [picker dismissViewControllerAnimated:YES completion:^{
             UnitySendMessage(_unityGameObject, _unityMethodName, "Cancel");
         }];
         [self dismissViewControllerAnimated:YES completion:nil];
     }
     @end
    
     #if defined (__cplusplus)
     extern "C" {
     #endif
         void _iosOpenPhotoLibrary(char *unityGameObject, char *unityMethodName)
         {
             strcpy(_unityGameObject, unityGameObject);
             strcpy(_unityMethodName, unityMethodName);
    
             if([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary]) {
                 IosPhotoHelper * app = [[IosPhotoHelper alloc] init];
                 [UnityGetGLViewController() presentViewController:app animated:YES completion:nil];
                 [app showPicker:UIImagePickerControllerSourceTypePhotoLibrary allowsEditing:NO];
             } else {
                 UnitySendMessage(_unityGameObject, _unityMethodName, "Cancel");
             }
         }
    
         void _iosOpenPhotoAlbums(char *unityGameObject, char *unityMethodName)
         {
             strcpy(_unityGameObject, unityGameObject);
             trcpy(_unityMethodName, unityMethodName);
    
             if([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeSavedPhotosAlbum]) {
                 IosPhotoHelper * app = [[IosPhotoHelper alloc] init];
                 [UnityGetGLViewController() presentViewController:app animated:YES completion:nil];
                 [app showPicker:UIImagePickerControllerSourceTypeSavedPhotosAlbum allowsEditing:NO];
             } else {
                 _iosOpenPhotoLibrary(_unityGameObject, _unityMethodName);
             }
         }
     #if defined (__cplusplus)
     }
     #endif
    
  7. 代码编写完成后,别急着运行工程,否则你会发现有可能点击开启相册按钮就Crash了,原因很简单,需要添加相册使用权限,在Xcode工程中的info.plist文件中添加一个字符串字段:NSPhotoLibraryUsageDescription,内容自行填写,例如:需要使用相册来选择图片;

  8. 准备就绪,现在让我们运行Xcode工程进行测试,测试OK后,将对应的.h和.mm文件拷贝到Unity3D工程中的Assets/Plugins/iOS目录下,若Unity3D的功能还未开发完全,则可继续开发,后续编译后刚才的功能已经可以用了,当然,刚才导出并测试OK的Xcode工程也是可以直接发布app的;

  9. 注意,c#中的string传递到c++中的方法时,对应为指针类型的char,若需要与NSString之间转换,则调用NSString的一些UTF8的静态方法即可实现,在Xcode中用代码提示就可以看到相应方法了,各位自行尝试,另外,Unity3D中的Application.persistentDataPath目录对应的是iOS中的NSHomeDirectory()方法调用后返回的目录下的Documents目录,即:[NSHomeDirectory() stringByAppendingPathComponent:@"Documents"]目录,明确这点后,就可以实现在iOS存储好图片,然后返回文件名在Unity3D中再将该文件进行各种的操作的功能;

  10. 好了,Unity3D工程的iOS插件开发教程到此结束,若实际项目开发过程中有遇到问题,可细细斟酌以上小点,看看是哪里没注意到,结合Debug的日志打印,相信你能很快解决问题;

Copyright © zhengxiangqi 2018 all right reserved,powered by Gitbook该文件修订时间: 2019-09-30 02:14:29

results matching ""

    No results matching ""