android ndkで外部ライブラリを使用する方法

多分もっと良い方法があると思うが、とりあえず動いた方法


# ライブラリの準備

- ソースコードを取ってきて  
```shell  
git clone --recursive https://github.com/ARMmbed/mbedtls.git
```  

- ビルド
```shell
cd mbedtls
export NDK_HOME=${HOME}/Android/Sdk/ndk/26.1.10909125
for a in arm64-v8a armeabi-v7a x86 x86_64
do mkdir build_${a}; cd build_${a}
cmake -DCMAKE_TOOLCHAIN_FILE=$NDK_HOME/build/cmake/android.toolchain.cmake -DANDROID_ABI=${a} -DANDROID_PLATFORM=android-31 .. 
make
cd ..
done
```

- コピー
```shell
for a in arm64-v8a armeabi-v7a x86 x86_64
do mkdir -p /path/to/android/app/src/main/cpp/${a}
for b in `find build_$a -name *.a`
do cp $b /path/to/android/app/src/main/cpp/${a}/
done
done

```

# android側

## ファイル作成とか修正
- app/src/main/cpp/CMakeLists.txt

```cmake
cmake_minimum_required(VERSION 3.4.1)

set(MBEDTLS_DIR "${CMAKE_SOURCE_DIR}/../../../../../oss/mbedtls/")

add_library(mbedtls STATIC IMPORTED)
set_target_properties(mbedtls PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/${ANDROID_ABI}/libmbedtls.a)

add_library(mbedcrypto STATIC IMPORTED)
set_target_properties(mbedcrypto PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/${ANDROID_ABI}/libmbedcrypto.a)

add_library(mbedx509 STATIC IMPORTED)
set_target_properties(mbedx509 PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/${ANDROID_ABI}/libmbedx509.a)

include_directories(${MBEDTLS_DIR}/include)

add_library(native-lib SHARED ${CMAKE_SOURCE_DIR}/native-lib.cpp)

target_link_libraries(native-lib mbedtls mbedcrypto mbedx509)

```

app/build.gradle
```diff
diff --git a/android/app/build.gradle b/android/app/build.gradle
index e8bd5e3..1e6cc14 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -81,6 +81,14 @@ android {
         targetSdkVersion rootProject.ext.targetSdkVersion
         versionCode 1
         versionName "1.0"
+        ndk {
+            abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86'
+        }
+    }
+    externalNativeBuild {
+        cmake {
+            path "src/main/cpp/CMakeLists.txt"
+        }
     }
     signingConfigs {
         debug {
```

- app/src/main/cpp/native-lib.cpp
クラス名は使用する場所に合わせる
```cpp
#include <jni.h>
#include <string>
#include "mbedtls/aes.h"

extern "C"
    JNIEXPORT void JNICALL
    Java_com_sample_SampleClass_encryptAES(JNIEnv *env, jobject thiz, jbyteArray inputData,
                                         jbyteArray key, jbyteArray outputData) {

    // Initialize AES context
    mbedtls_aes_context aes;
    mbedtls_aes_init(&aes);

    // Convert Java byte arrays to C arrays
    jbyte* input = env->GetByteArrayElements(inputData, nullptr);
    jbyte* keyData = env->GetByteArrayElements(key, nullptr);

    // Set the AES key
    mbedtls_aes_setkey_enc(&aes, (const unsigned char *) keyData, 128);

    // Encrypt the data
    size_t length = env->GetArrayLength(inputData);
    jbyte* output = env->GetByteArrayElements(outputData, nullptr);

    mbedtls_aes_crypt_ecb(&aes, MBEDTLS_AES_ENCRYPT, (const unsigned char *) input, (unsigned char *) output);

    // Release the AES context
    mbedtls_aes_free(&aes);

    // Release the Java byte arrays
    env->ReleaseByteArrayElements(inputData, input, 0);
    env->ReleaseByteArrayElements(key, keyData, 0);
    env->ReleaseByteArrayElements(outputData, output, 0);
}


```

- app/src/main/java/com/sample/SampleClass.java
```java
public class SampleClass {
    static {
        System.loadLibrary("native-lib");
    }

    public native void encryptAES(byte[] inputData, byte[] key, byte[] output);

    public void test() {
        byte[] data = "Hello, World!".getBytes();
        byte[] key = "1234567890123456".getBytes();
        byte[] output = new byte[data.length];
        encryptAES(data, key, output); 
        // omit log output
```

## ビルド
```
./gradlew assemble
```


# サンプル出力
```
48 65 6C 6C 6F 2C 20 57 6F 72 6C 64 21  -> D5 C6 3B E1 59 57 0E E7 70 38 46 F9 D8
```