code style

9/30/2016

How to load dynamic library with Unity plugin on Mac OSX

When develop Unity plugin on Mac, you might want to load third party dynamic library. But it usually occurs "fail to load" situation. That is because loading path is different between development and production environment.

For instance, when you develop in Edit mode, the loading path will be
 ./Assets/Plugins/osxplugin.bundle/Contents/Resources/thirdparty.dylib

But when you build a release version, the loading path will be
./Contents/Plugins/osxplugin.bundle/Contents/Resources/thirdparty.dylib

Mac OSX provide a command line tool to modify that.

$ install_name_tool -id @loader_path/thirdparty.dylib thirdparty.dylib

You could use otool to check dylib status.

eg.
$ otool -L libcurl.dylib 
libcurl.dylib:
 @loader_path/libcurl.dylib (compatibility version 0.0.0, current version 0.0.0)
 /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1226.10.1)
 /usr/lib/libz.1.dylib (compatibility version 1.0.0, current version 1.2.5)

Now, you can develop and build a unity app without dylib loading issue.

9/07/2016

How to create an Unity AAR Plugin for Android

Environment: Android Studio 2.1.3

1. new Module -> Android Library

2. new -> Java Class for your Java code.

3. new -> Folder -> JNI folder

4. new -> C++ Class for your C++ code

5. new -> Folder -> Assets folder for your plugin asset files.

6. edit build.gradle for your library

apply plugin: 'com.android.library'

android {
    compileSdkVersion 24
    buildToolsVersion "24.0.1"

    defaultConfig {
        minSdkVersion 15
        targetSdkVersion 24
        versionCode 1
        versionName "1.0"

        ndk {
            moduleName "unity_plugin"

            // STL library
            stl "gnustl_static"

            // target platforms
            abiFilters "armeabi-v7a", "x86"

            // link other libraries for your C++ code
            String path = file(projectDir).absolutePath + "/src/main/jniLibs/\$(TARGET_ARCH_ABI)/"
            ldLibs "log", "z", "m", "android", path+"libCustom.so"
        }
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_6
        targetCompatibility JavaVersion.VERSION_1_6
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:24.2.0'

    // reference for Unity Java classes,
    // see https://docs.unity3d.com/Manual/PluginsForAndroid.html
    // "Extending the UnityPlayerActivity Java Code" part
    provided files('classes.jar') 
}

7. add permissions in AndroidManifest.xml,
 such as < uses-permission android:name="android.permission.INTERNET" >

8. double click on YourApplication.:YourLibrary.Tasks.build.assembleRelease in Gradle projects panel to generate the release version of AAR.

9. copy AAR to Unity Assets/Plugins/Android folder.

Unity Plugin Tips

Unity WebCamTexture Fast Copy

讀取WebCamTexture內容是用Color32 type,但是Texture2D更新內容需要byte type。
使用StructLayout宣告可以將不同type資料共用同一個記憶體位址。
(Win/Mac測試ok)

[StructLayout(LayoutKind.Explicit)]
public struct Color32Bytes{
  [FieldOffset(0)]
  public byte[] byteArray;

  [FieldOffset(0)]
  public Color32[] colors;
}

colorData = new Color32Bytes();
colorData.colors = new Color32[webCamTexture.width * webCamTexture.height]; 

webCamTexture.GetPixels32(colorData.colors);
displayTexture.LoadRawTextureData(colorData.byteArray);
displayTexture.Apply();



Unity Native Plugin Fast C# Callback

使用MonoPInvokeCallback宣告,可以讓C++ Plugin呼叫C#函式。
(Android測試ok)

[C#]
// declare callback
delegate void RenderCallback(int request);

[MonoPInvokeCallback(typeof(RenderCallback))]  
static void RenderFunc(int request) {
  // do something
}

[DllImport("unity_plugin")]  
static extern void RegisterCallbacks(RenderCallback cb);


[C++]
typedef void (*RenderCB)(int event);
static RenderCB sfpRender = nullptr;
extern "C" void RegisterCallbacks(RenderCB cb) {
    sfpRender = cb;
}