質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.39%
JNI

JNI(Java Native Interface)は、Javaプラットフォームにおいて、Javaで記述されたプログラムと、他の言語で書かれたネイティブコードを連携するためのインタフェース仕様である

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Android Studio

Android Studioは、 Google社によって開発された、 Androidのネイティブアプリケーション開発に特化した統合開発ツールです。

Android NDK

Android NDKとは、Android SDKと対を成すツールです。ネイティブコードのアプリ、またはC/C++言語の既存のポートライブラリでパフォーマンスクリティカルな部分を構築できます。ヘッダ、ライブラリを提供して、アクティビティやユーザ入力処理などを構築できます。

Q&A

解決済

1回答

6280閲覧

JNIを使用したライブラリを配布したい

Wind

総合スコア442

JNI

JNI(Java Native Interface)は、Javaプラットフォームにおいて、Javaで記述されたプログラムと、他の言語で書かれたネイティブコードを連携するためのインタフェース仕様である

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Android Studio

Android Studioは、 Google社によって開発された、 Androidのネイティブアプリケーション開発に特化した統合開発ツールです。

Android NDK

Android NDKとは、Android SDKと対を成すツールです。ネイティブコードのアプリ、またはC/C++言語の既存のポートライブラリでパフォーマンスクリティカルな部分を構築できます。ヘッダ、ライブラリを提供して、アクティビティやユーザ入力処理などを構築できます。

0グッド

1クリップ

投稿2020/03/03 00:45

前提・実現したいこと

ビルド済みライブラリの使用に書いてる「ソースを配布せずに、独自のライブラリをサードパーティの NDK デベロッパーに配布する。」を行いたいのですが、やり方がわかりません。
JNIや中の関数だけをライブラリにする方法はありませんでしょうか?

発生している問題・エラーメッセージ

JNIでC++のソースコード・共有オブジェクトをAndroidから利用するチュートリアルをやってみたの様に、
JNIで作成したnativeライブラリ(soファイルもしくはaarモジュール)を別のプロジェクトで再利用したいのですが、JNICALL以下の名前でプロジェクト名を使用する為、結局ソースが必要になってしまいます。
AndroidStudio 他のプロジェクトのモジュール内のC++を参照しよう(Java / kotlin)でもcppの中身が見えてしまいます。

該当のソースコード

Java

1public class MainActivity extends AppCompatActivity { 2 static { 3 System.loadLibrary("native-lib"); 4 } 5 6 @Override 7 protected void onCreate(Bundle savedInstanceState) { 8 super.onCreate(savedInstanceState); 9 setContentView(R.layout.activity_main); 10 11 TextView tv = findViewById(R.id.sample_text); 12 13 int[] intArray = new int[10]; 14 for(int i=0;i<intArray.length;i++) 15 intArray[i] = i+1; 16 17 final int[] intAns = intFromJNI(intArray); 18 19 tv.setText("Size:" + intAns.length + " " + intAns[1] + " " + intAns[2]); // 個数と2個目と3個目を表示 20 } 21 22 public native int[] intFromJNI(int[] intArr); 23}

配布したいJNI部分

C++

1#include <jni.h> 2#include <string> 3#include <vector> 4 5extern "C" JNIEXPORT jintArray JNICALL 6Java_s_test_cppmodule_MainActivity_intFromJNI( 7 JNIEnv *env, 8 jobject 9 , jintArray intInput) { 10 const jint intInputSize = env->GetArrayLength(intInput); 11 jint *intArr = env->GetIntArrayElements(intInput, 0); 12 13 // 処理内容だけでもいい 14 int intOutSize = intInputSize / 2; 15 int intValues[intOutSize]; 16 for(int i=0;i<intOutSize;i++) 17 intValues[i] = intArr[i*2] * 10; 18 19 env->ReleaseIntArrayElements(intInput, intArr, false); // 開放 20 21 jintArray intOutArray = env->NewIntArray(intOutSize); 22 env->SetIntArrayRegion(intOutArray, 0, intOutSize, intValues); 23 return intOutArray; 24}

試したこと

1.Android Studioで *.jar, *.soを追加するを参考にsoファイルが入っている
\app\build\intermediates\stripped_native_libs\debug\out\lib
フォルダを別プロジェクトの\src\mainの下へコピーし、jniLibsとして置いてみましたが、使えませんでした。

2.AndroidStudio モジュール内のC++を参照するを参考にモジュールのAARを作成し、別プロジェクトで[File]->[New]->[New Module]->[Import .JAR/.AAR Package]で作成したAARを読み込んでみましたが、モジュール名が見えるだけでヘッダファイルが参照出来ず、中の関数は使用出来ませんでした。

3.[File]->[New]->[New Module]->[Android Library]でモジュールを作成し、
モジュールフォルダにcppフォルダをコピーしてみましたが、Synchronizeしても表示されませんでした。

補足情報(FW/ツールのバージョンなど)

Windows 10
AndroidStudio 3.5.3

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

試しにやってみたらできたので手順を書きます。

  1. Empty Activity のプロジェクトを作ります。このアプリは JNI のテスト用です。
  2. File メニューの New - New Modue... から Android Library モジュールを作ります。モジュール名は仮に myjnilib とします。
  3. myjnilib/build.gradle を編集します。
apply plugin: 'com.android.library' android { compileSdkVersion 29 buildToolsVersion "29.0.3" defaultConfig { minSdkVersion 15 targetSdkVersion 29 versionCode 1 versionName "1.0" externalNativeBuild { cmake { cppFlags "" } } } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } externalNativeBuild { cmake { path "src/main/cpp/CMakeLists.txt" version "3.10.2" } } } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) }
  1. myjnilib/src/main/cpp フォルダを作って CMakeLists.txt と myjnilib.cpp を書きます。
# For more information about using CMake with Android Studio, read the # documentation: https://d.android.com/studio/projects/add-native-code.html # Sets the minimum version of CMake required to build the native library. cmake_minimum_required(VERSION 3.4.1) # Creates and names a library, sets it as either STATIC # or SHARED, and provides the relative paths to its source code. # You can define multiple libraries, and CMake builds them for you. # Gradle automatically packages shared libraries with your APK. add_library( # Sets the name of the library. myjnilib # Sets the library as a shared library. SHARED # Provides a relative path to your source file(s). myjnilib.cpp) # Searches for a specified prebuilt library and stores the path as a # variable. Because CMake includes system libraries in the search path by # default, you only need to specify the name of the public NDK library # you want to add. CMake verifies that the library exists before # completing its build. find_library( # Sets the name of the path variable. log-lib # Specifies the name of the NDK library that # you want CMake to locate. log) # Specifies libraries CMake should link to your target library. You # can link multiple libraries, such as libraries you define in this # build script, prebuilt third-party libraries, or system libraries. target_link_libraries( # Specifies the target library. myjnilib # Links the target library to the log library # included in the NDK. ${log-lib})

cpp

1#include <jni.h> 2#include <string> 3 4extern "C" JNIEXPORT jstring JNICALL 5Java_com_example_myjnilib_MyJNILib_helloFromJNI( 6 JNIEnv *env, 7 jobject /* this */) { 8 std::string hello = "Hello from JNI!"; 9 return env->NewStringUTF(hello.c_str()); 10}
  1. MyJNILib.java クラスを作ります。

Java

1package com.example.myjnilib; 2 3public class MyJNILib { 4 static { 5 System.loadLibrary("myjnilib"); 6 } 7 8 public native String helloFromJNI(); 9}
  1. 同じプロジェクトの app モジュールから JNI を呼べるように、app/build.gradle を編集して依存関係を追加します。
dependencies { implementation project(":myjnilib") // 以下略 }
  1. MyActivity から JNI を呼び出します。
// import 追加 import com.example.myjnilib.MyJNILib; // JNI 呼び出し String str = new MyJNILib().helloFromJNI();
  1. Gradle ペインから myjnilib/Tasks/build/assemble をダブルクリックして *.aar をビルドします。

myjnilib/build/outputs/aar に myjnilib-release.aar と myjnilib-debug.aar ができます。

イメージ説明

  1. JNI を使いたいプロジェクトの app/libs に *.aar ファイル(myjnilib-release.aar と myjnilib-debug.aar のどちらか)をコピーし、app/build.gradle を編集すれば、7) と同様に JNI を呼び出せるはず。
dependencies { implementation fileTree(dir: 'libs', include: ['*.aar']) // 以下略 }

投稿2020/03/03 09:56

hoshi-takanori

総合スコア7899

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Wind

2020/03/04 05:59

詳しく手順を書いて頂き、本当にありがとうございます。 最初からモジュールにJNIを入れて作るのですね。 JNI入りaarを読み込んで、他のプロジェクトから動作させることが出来ました。 ちょっとアレンジして、値を入れても動作させることも出来ました。
hoshi-takanori

2020/03/04 06:06

自分でも興味があったので…。 この方法だと aar ファイルを一つ配るだけで良いので、配布する側も利用する側も幸せになれますよね。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.39%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問