Unity3D Native 插件开发(2)— 小试牛刀
发表于2016-05-17
这篇文章,将用实例进行演示,让开发者对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目录下(如果没有则需要创建)
2、C#调用代码
根据前一教程中的对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