Unity3D Native 插件开发(2)— 小试牛刀

发表于2016-05-17
评论0 3k浏览
这是一个系列教程,主要内容是如何开发 Unity 插件,在理解这个教程之前需要读者有一定的 Unity、iOS、Android 开发知识:
       

Unity3D Native 插件开发(1)— 原理解析


  这篇文章,将用实例进行演示,让开发者对Unity插件有个具体的认识
  实例:获取UUID
  在开发过程当中,最常见的问题是获取用户身份,这个示例就来演示如何在Unity实现这样的调用

实现原理
iOS和Android获取UUID的方法基本是类似的,获取应用的唯一ID
·  identifierForVendor,在iOS环境是作为用户标识的最好选择,
·  uuid,在android环境下,这个是最好的选择,参见Google官方POST :http://android-developers.blogspot.com/2011/03/identifying-app-installations.html
  上述两个方案都有一个弊端,当用户删掉开发者的应用时,这个id会丢失。
  在iOS环境下,一般配合KeyChain,可以在用户删除应用的时候找回;
  Android下面就没有这么好运了,目前没有较好的方案解决这个问题

Android实现
  方案1:C# 加 Jar 包模式
  这种方案,需要将Java类编译成jar包,C#中直接生成这个类的对象,对其进行调用。
1、编译Jar包
  这个是Android开发工程师的基本功,这里以Android Studio为例,只做简单介绍
  菜单导航到 File -> New -> New Module … ,选择 Android Library,包名(Package name)设定为com.tencent.imsdk.util,完成后等待gradle完成
  在新建的util模块中,添加Installation.java文件,文件内容如下:
package com.tencent.imsdk.util; 
import android.content.Context; 
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.UUID; 
public class Installation {
   private static String sID = null;
   private static final String INSTALLATION = "INSTALLATION";  
   public synchronized static String id(Context context) {
       if (sID == null) {
           File installation = new File(context.getFilesDir(), INSTALLATION);
           try {
               if (!installation.exists())
                   writeInstallationFile(installation);
               sID = readInstallationFile(installation);
           } catch (Exception e) {
               throw new RuntimeException(e);
           }
       }
       return sID;
   } 
   private static String readInstallationFile(File installation) throws IOException {
       RandomAccessFile f = new RandomAccessFile(installation, "r");
       byte[] bytes = new byte[(int) f.length()];
       f.readFully(bytes);
       f.close();
       return new String(bytes);
   }  
   private static void writeInstallationFile(File installation) throws IOException {
       FileOutputStream out = new FileOutputStream(installation);
       String id = UUID.randomUUID().toString();
       out.write(id.getBytes());
       out.close();
   }
}
  编译,获取jar包,放到Unity的Assets/Plugins/Android/libs目录下(如果没有则需要创建)
2C#调用代码
  根据前一教程中的对Android帮助类的说明,很容易编写以下代码:
using System;
using UnityEngine;
using System.Collections;  
public class UUID {
   ///  
   /// Get UUID 
   ///  
   /// The UUID 
   public string GetUUID() {
#if UNITY_ANDROID
       try {
           // get unity player class 
           AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
           // get class static member "currentActivity" 
           AndroidJavaObject currentActivity = unityPlayer.GetStatic("currentActivity"); 
           // get self defined Installation class 
           AndroidJavaClass installation = new AndroidJavaClass ("com.tencent.imsdk.util.Installation");
           // call Installation "id" function with param currentActivity 
           string uuid = installation.CallStatic ("id", currentActivity);
           return uuid;
       }
       catch(AndroidJavaException e) {
           Debug.LogError("get uuid catch error : " + e.Message);
           return null;
       }
#elif UNITY_IOS
       //TODO 
#else
       return null;
#endif
   }
}
方案2:Java代码逻辑上移到C
  这种方案适合对Android系统不是很熟悉的Unity开发者,只调用Java中的核心逻辑,其他文件操作全都由C#完成
  Java代码的逻辑实际上是,通过UUID获取一个随机ID,然后写在Android应用的私有文件/data/data//files/INSTALLATION中,了解了这个逻辑,C#代码就非常简单了
  C#获取UUID的代码如下:
  public string GenerateUUID() {
#if UNITY_ANDROID
      try {
          AndroidJavaClass uuidClass = new AndroidJavaClass ("java.util.UUID");
          AndroidJavaObject uuidObject = uuidClass.CallStatic ("randomUUID");
          string uuid = uuidObject.Call ("toString");
          return uuid;
      }
      catch (AndroidJavaException e) {
          Debug.LogError("generate uuid catch error : " + e.Message);
          return null;
      }
#else
      return null;
#endif
  }
  剩下还需要做的就是保存在文件,这个就不属于插件开发的范畴,开发者可以自己试验。

iOS实现
  C#部分
  C#提供了DllImport机制,来实现C#和C语言的方法调用,在Unity中,C方法的声明语法如下:
[DllImport ("__Internal")]
private static extern string IOS_GetUUID ();
  这样,就告知Unity我们声明了一个方法叫IOS_GetUUID,返回值为string,并会在C语言中实现其具体内容
  我们就可以在C#中如此调用,填充Android章节中的TODO代码:
string uuid = IOS_GetUUID();
return uuid;
  C语言部分
  在前一章节中已经提到过Unity的插件工程架构,好在这个方法实现非常简单,没有特殊依赖,一个.mm文件即可实现相应的内容,所以,我们在Asset/Plugins/iOS目录下新建一个UUID.mm文件,代码实现如下:
#import 
extern "C" {
    char* IOS_GetUUID() {
        NSUUID* uuid = [[UIDevice currentDevice] identifierForVendor];
        NSString* uuidString = [uuid UUIDString];
        int length = [uuidString length];
        char* retString = (char*)malloc(length+1);
        memset(retString, 0, length+1);
        strncpy(retString, uuidString.UTF8String, length);
        return retString;
    }
}
  注意:文件必须是.mm才能混编;使用malloc替代new以避免ARC自动释放;Unity会自动释放返回的char*指针,没有内存泄露问题

Unity测试与运行结果
  这部分就不过多描述了,对Unity有一定的了解即可实现。创建空的GameObject并绑定脚本,运行时只写如下代码:
UUID uuid = new UUID ();
Debug.Log ("Get UUID : " + uuid.GetUUID ());
Android的运行结果(LogCat中查看):
I/Unity: Get UUID : 597bb511-d6c3-4fdb-8766-36fdbe6e46c2
iOS运行结果:
Get UUID : 955BDE98-20D5-4E3A-B182-540A3D185502

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引