[Xamarin.Android] Binding Java Library

2017. 6. 22. 11:55Mobile/Xamarin

Android에는 수많은 라이브러리가 존재합니다. Xamarin.Android는 이러한 Android를 위한 자바 라이브러리를 사용할 수 있는 2가지 방법을 제공합니다.

  • Binding Library 생성 : 자바 라이브러리를 C# Wrapper로 감싸고 이를 C#에서 호출할 수 있습니다.
  • Java Native Interface (JNI) 사용 : 자바 라이브러리 코드를 직접적으로 호출할 수 있습니다.

여기서는 Binding Library를 생성하고 자바 라이브러리나 어셈블리를 C# Wrapper로 감쌈 후 C#에서 사용하는 방법에 대해서 소개합니다. JNI에 대해 확인하시려면 Working with JNI를 참조하세요.

Binding Library란?

Xamarin.Android는 Managed Callable Wrappers (MCW)를 통해 Binding을 구현하고 있습니다. MCW는 JNI 브릿지로서 Managed Code가 Java Code를 호출해야할 때 사용됩니다. 또한 MCW는 Java Type이나 Java의 가상 메서드의 오버라이딩을 지원합니다. 마찬가지로 Android Runtime (ART) 코드가 Manage Code를 호출해야할 때는  Android Callable Wrappers (ACW)불리는 JNI Bridge를 사용합니다. 이러한 구조는 아래 그림에서 잘 표현하고 있습니다.

Binding Library는 Managed Callable Wrapper에 포함된 어셈블리로써 Manage Code가 Java Code를 호출해야할 때 사용됩니다. 예제를 통해 설명하면 먼저 아래 MyClass는 Binding Library로 감쌀 Java Code 입니다.

package com.xamarin.mycode;

public class MyClass
{
    public String myMethod (int i) { ... }
}

위 코드를 .jar 패키지로 생성한 후 Binding Library를 생성하면 아래와 같이 C#에서 MyClass를 이용할 수 있게 됩니다.

var instance = new MyClass ();

string result = instance.MyMethod (42);

Binding Library를 생성하려면 Xamarin.Android Java Bindings Library 템플릿을 사용해야 합니다. Binding Library Project을 통해 MCW Class와 Android 라이브리리를 위한 리소스가 포함된 .NET 어셈블리를 생성하실 수 있습니다. Binding Library는 .jar 파일 뿐만 아니라 Android Archive (.AAR) 파일이나 Eclipse Android Library Project도 지원합니다.

Binding Library가 Java Type을 참조할 때에는 Binding Library에 적절한 네임스페이스를 선언해야 합니다. 일반적으로 Java Type의 패키지 이름은 Manage Code의 네임스페이스로 사용하게 됩니다. 예를들어 아래와 같이 .jar에 포함된 Java 패키지명은 C#의 using 문으로 변경할 수 있습니다.

//.jar의 패키지명
com.company.package

//C#의 using 네임스페이스
using Com.Company.Package;

그외 Binding Library를 생성할 때 유의사항은 아래와 같습니다.

  • 자바 라이브러리가 사용하는 외부참조가 있나요? - 자바 라이브러리가 사용하는 외부 라이브러리나 어셈블리는 반드시 Xamarin.Android 프로젝트에 ReferenceJar 혹은 EmbeddedReferenceJar로 포함되어야 합니다. Native Assembly는 반드시 EmbeddedNativeLibrary로 Binding Project에 포함되어야 합니다.
  • Android Library가 타겟으로하는 API 버전은 어떻게 되나요? - API 버전을 다운그레이드 할 수 없습니다. Xamarin.Android Binding Project는 반드시 동일한 API 버전이나 상위버전을 사용해야 합니다.
  • JDK가 라이브러리를 컴파일 할 때 사용했던 버전은 어떻게 되나요? - Android Library가 빌드될 때 사용했던 JDK 버전과 Xamarin.Android에서 사용하는 JDK 버전이 다를 경우 Binding 오류가 발생할 수 있습니다. Xamarin.Android의 JDK 버전에 맞추어 Android Library를 리빌드하는 것도 JDK버전을 일치시키는 방법 중 하나 입니다.

Build Actions

Binding Library를 생성할 때 .jar, .AAR 파일의 Build Action을 적절하게 선택해야 합니다. 선택한 Build Action에 따라 .jar, .AAR파일이 .NET 어셈블리 파일에 완전히 포함될 수도 있고 아니면 파일에 대한 참조만 유지할 수도 있습니다. 아래는 주요 Build Action에 대한 설명입니다.

  • EmbeddedJar - .jar 파일을 Bindings Library가 생성하는 DLL 파일에 포함시킵니다. Embedded Resource로 포함되기 때문에 .jar파일은 바이트 코드로 컴파일되고 .NET 어셈블리 파일에 완전히 통합됩니다.
  • InputJar - Bindings Library가 생성하는 DLL 파일은 .jar파일에 대한 참조만 유지합니다. 라이선스 등의 이유로 .jar파일을 .NET 어셈블리에 포함하고 싶지 않을 때 사용할 수 있습니다. 이 Build Action을 선택한 경우 반드시 .jar파일은 .NET 어셈블리가 참조하고 있는 위치에 존재해야 합니다.
  • LibraryProjectZip - .AAR 파일을 Binding Library가 생성하는 DLL 파일에 포함시킵니다. EmbeddedJar와 유사하지만 Java Code 뿐만 아니라 포함된 리소스 들도 참조할 수 있다는 차이가 있습니다.
  • ReferenceJar - .jar 참조를 정의합니다. .jar 참조는 Binding Library에서 사용하는 .jar, .AAR 파일이 의존하는 .jar을 말합니다. 이렇게 설정된 .jar 파일에 대한 참조는 컴파일 시 의존성을 충족시키기 위해 사용됩니다. 이 Build Action을 선택하면 .jar에 대한 C# Binding을 생성하지 않으며 .NET DLL에 .jar가 포함되지 않습니다. 아직 .jar에 대한 Binding Library가 생성되지 않았고 추후 .jar에 대한 Binding Library를 생성할 예정이라면 이 옵션을 유용하게 사용할 수 있습니다. 이 Build Action은 여러개의 .jar (혹은 .AAR)을 여러 개의 독립적인 Binding Library로 생성하실 때도 유용합니다.
  • EmbeddedReferenceJar - .jar 참조를 .NET DLL 파일에 포함합니다. .jar파일과 모든 .jar 참조에 대해 C# Binding을 생성하실 경우 이 옵션을 선택해주세요.
  • EmbeddedNativeLibrary - .so 파일을 Binding에 포함시킵니다. Binding Library에서 사용하는 .jar파일이 필요로 하는 .so 파일에 대한 Build Action입니다. 자바 라이브러리가 실행 될 때 .so 라이브러리를 수동으로 로드해야할 수 있습니다. 이에 대한 설명은 아래에서 이어집니다.

추가적으로 아래 Build Action은 Java API 문서를 C# XML 문서로 변경하는데 사용됩니다.

  • JavaDocJar - 자바 라이브러리에 대한 Javadoc Archive Jar에 대한 참조를 위해 사용됩니다. Maven 패키지 스타일(FOOBAR-javadoc**.jar*)을 따릅니다.
  • JavaDocIndex -  Java API HTML 문서의 index.html를 가리키기 위해 사용됩니다.

API 문서는 Java8, Java7, Java6(각각 포멧이 다름)의 default doclet이거나 DroidDoc 스타일이어야 합니다.

.so파일 로드하기

Binding Library가 자바 라이브러리를 바인딩 할 때 필요로 하는 .so파일도 같이 Binding Library Project에 포함하게 됩니다. Binding Library에 포함된 자바 라이브러리가 실행될 때 Xamarin.Android는 java.lang.UnsatisfiedLinkError: Native method not found: 메시지를 logcat에 출력 하면서 JNI 호출에 실패하는 경우가 발생할 수 있습니다.

이러한 문제는 포함된 .so파일을 직접 로드함으로써 해결하실 수 있습니다. .so파일은 Java.Lang.JavaSystem.LoadLibrary을 호출하여 로드하실 수 있습니다. 예를들어 Binding Library Project에 libpocketsphinx_jni.so 파일이 EmbeddedNativeLibrary Build Action으로 포함되어있다고 가정하면, 아래 코드를 통해 so파일을 로드하실 수 있습니다.

Java.Lang.JavaSystem.LoadLibrary("pocketsphinx_jni");

Java API가 C#으로 변환되는 규칙

Xamarin.Android Binding Generator는 자바 라이브러리에 포함된 자바구문이나 패턴을 .NET 패턴에 적합하게 변경하게 됩니다. 이러한 규칙은 아래와 같습니다.

  • 자바의 Setter/Getter 메서드는 .NET의 Property로 변경됩니다.
  • 자바의 Field는 .NET의 Property로 변경됩니다.
  • 자바의 Listener/Listener Interface는 .NET의 Event로 변경됩니다. Callback 메서드의 매개변수들은 EventArgs 하위 Class로 표현됩니다.
  • 자바의 Static Nasted Class는 .NET의 Nested Class로 변경됩니다.
  • 자바의 Innser Class는 C#의 인스턴스 생성자를 포함하는 Nested Class로 변환됩니다.

바인딩 시나리오

시나리오별 상세한 바인딩 방법은 아래 메뉴얼을 참조해주세요.