NDK研究ノート(1)

NDK研究ノート(1)

Android アプリケーションが Java で記述されていることは誰もが知っていますが、開発に C/C++ を使用する必要がある場合や、基礎となるレイヤーと対話する必要がある場合があります。Java 自体は JNI メソッドを提供しますが、Android 開発には技術的な障害があります。たとえば、プログラムが複雑になり、互換性の保証が難しくなり、Framework API にアクセスできなくなり、デバッグが難しくなります。そこでNDKが誕生しました。NDK の正式名称は Native Development Kit です。NDKのリリースにより、ついに「Java+C」開発手法が肯定的なものとなり、正式にサポートされる開発手法となった。NDK は、C 開発をサポートする Android プラットフォームの始まりとなります。

NDKを使用するメリット

  1. 移植が容易で、C/C++ で書かれたライブラリは他のプラットフォームでも簡単に再利用できます。
  2. コード保護。Java 層のコードは逆コンパイルされやすく、C/C++ ライブラリの逆コンパイルはより困難です。
  3. プログラムの実行効率を向上させるためには、C/C++を用いて高性能なアプリケーションロジックを開発する必要があり、アプリケーションプログラムの実行効率が向上します。
  4. 既存のオープン ソース ライブラリにアクセスするには、基礎となる API にアクセスするか、C/C++ のみを備えたいくつかのライブラリを参照する必要があります。

NDK環境を構成する

NDK をダウンロードした場合は、そのパス ( [ファイル] -> [プロジェクト構造] でAndroid NDK の場所)を設定できます。デフォルトは SDK パス\ndk-bundle です。ダウンロードされていない場合は、「ダウンロード」をクリックしてダウンロードしてください。もちろん、
他のバージョンをダウンロードして任意の場所に配置し、手動でパスを設定することもできます。
設定が成功すると、NDK パスがプロジェクトのlocal.propertiesファイルに追加されます。

ndk.dir=D\:\\Android\\Sdk\\ndk-bundle

そうでない場合は、手動で追加できます。また、ビルド時に以下のようなエラーが発生した場合は、

Error:(12, 0) Error: NDK integration is deprecated in the current plugin.  
Consider trying the new experimental plugin.  
For details, see http://tools.android.com/tech-docs/new-build-system/gradle-experimental.  
Set "android.useDeprecatedNdk=true" in gradle.properties to continue using the current NDK integration.

これは、NDK バージョンと AS バージョンの間の不一致が原因で発生します。gradle.propertiesファイルの下に次の行を追加するだけですandroid.useDeprecatedNdk=true
(コマンド ラインを使用する場合は、システム環境変数を追加し、新しい変数名 ANDROID_NDK_HOME を作成する必要があります。対応する変数値は ndk ルート ディレクトリのアドレス、つまり $SDKpath\ndk-bundle です。次に、ANDROID_NDK_HOME をパス (%ANDROID_NDK_HOME% ; )に追加し、OK を確認します。)

ネイティブ ファイルを自分で作成する

さて、これで最初の NDK アプリケーションを作成できます。最も単純な例では、C は文字列を出力し、それを Android で呼び出して表示します。まずはいつものように New a Project です。次に、新しい Java クラスを作成し、JniUtils という名前を付けます。ここでダイナミックライブラリをロードし、ネイティブメソッドを作成します。(実際には、これを MainActivity で実行することもできますが、コードをより明確に見せるために、やはり個別に記述することにします。また、これはアプリ モジュール内では実行できず、別のモジュールで実行します。)ネイティブ
メソッド、つまり JNI インターフェイスは、C/C++ と Java の間のブリッジです。

public class JniUtils {
    
    
    static{
        System.loadLibrary("ndk");
    }
    public static native String getStringFromC();
}

この時点では、このメソッドの実装が見つからないため、getStringFromCの色は赤になっていることがわかります。次にこのメソッドを書いていきます。
デフォルトが Android ビューの場合は、プロジェクト ビューに調整します。$ProjectName/app/src/mainの下に、タイプがJNI Folderである新しいフォルダーを作成しますこのディレクトリには主に jni ファイル、つまり c/cpp ファイルとヘッダー ファイルが保存されます。次に、C ファイルを作成するには、gradle バージョンに応じて 2 つの方法があります。個別に説明して比較してみましょう。

安定したプラグイン

プロジェクトの下の build.gradle が次のようになっている場合:

  dependencies {
        classpath 'com.android.tools.build:gradle:2.1.0'
    }

プラグインの安定版です。
前の手順が完了したら、プロジェクトをクリーンアップして再ビルドして$ProjectName/app/build/intermediats/classes/ が存在するかどうかを確認し、ターミナルを開いてコマンドを入力します。

cd app/build/intermediates/classes/debug

次に、次のコマンドを入力します。

javah -jni com.example.yaoobs.ndkjnidemo.JniUtils

class/debug の下に追加のcom_example_yaoobs_ndkjnidemo_JniUtils.hがあることがわかりますこれを以前に作成した JNI フォルダーに切り取り、新しい C/C++ ソース ファイルを作成し、jniUtils.cという名前を付けます。com_example_yaoobs_ndkjnidemo_JniUtils.hのメソッド名に従ってjniUtils.cを変更します。

実験的プラグイン (Gradle 実験的プラグイン)

Gradle Experimental Plugin は、プロジェクトの構成時間を短縮し、より優れた NDK サポートを提供するために、Gradle の新機能に基づいて開発されています。
(これは単なるプラグインであり、gradle 自体のサポートが必要であり、そのバージョンに対応していることに注意してください。作成者の gradle バージョンは 2.1.0 で、対応する gradle-experimental は 0.7.0 です。)では、最初に をビルドする必要があります
。gradle で gradle 参照を変更します。

buildscript {
    ...
    dependencies {
//        classpath 'com.android.tools.build:gradle:2.1.0'
        classpath 'com.android.tools.build:gradle-experimental:0.7.0'
    }
...
}

次に、モジュールの下の build.gradle を変更します。文法的な違いがいくつかあります。古いものはコメントアウトされています。比較できます。

//apply plugin: 'com.android.application'
apply plugin: 'com.android.model.application'
//
//android {
    
    
//    compileSdkVersion 23
//    buildToolsVersion "23.0.2"
//    defaultConfig {
    
    
//        applicationId "com.example.yaoobs.ndkjnidemo"
//        minSdkVersion 14
//        targetSdkVersion 23
//        versionCode 1
//        versionName "1.0"
//        ndk {
    
    
//            moduleName = "ndk"
//            abiFilters 'armeabi', 'x86', 'armeabi-v7a', 'x86_64', 'arm64-v8a', 'mips', 'x86_64'
//        }
//    buildTypes {
    
    
//        release {
    
    
//            minifyEnabled false
//            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
//        }
//    }
//}

model {
    android {
        compileSdkVersion = 23
        buildToolsVersion = "23.0.2"
        defaultConfig.with {
            applicationId = "com.example.yaoobs.ndkjnidemo"
            minSdkVersion.apiLevel = 14
            targetSdkVersion.apiLevel = 23
            versionCode = 1
            versionName = "1.0"
        }
        ndk {
            moduleName = "ndk"
            toolchain = 'clang'  //必加项,否则c文件报错
            CFlags.addAll(['-Wall'])
        }
        buildTypes {
            release {
                minifyEnabled = false
                proguardFiles.add(file('proguard-rules.txt'))
            }
        }
        productFlavors {
            create("arm") {
                ndk.abiFilters.add("armeabi")
            }
            create("arm7") {
                ndk.abiFilters.add("armeabi-v7a")
            }
            create("arm8") {
                ndk.abiFilters.add("arm64-v8a")
            }
            create("x86") {
                ndk.abiFilters.add("x86")
            }
            create("x86-64") {
                ndk.abiFilters.add("x86_64")
            }
            create("mips") {
                ndk.abiFilters.add("mips")
            }
            create("mips-64") {
                ndk.abiFilters.add("mips64")
            }
            create("all")
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support.constraint:constraint-layout:1.0.0-alpha1'
    compile 'com.android.support:appcompat-v7:23.0.0'
}

完了後、JniUtils.class にネイティブ メソッド getStringFromC() が見つかります。Alt+Enter を押すと、次の図に示すようにプロンプ​​トが表示されます: Enter を押すと、JNI の下に作成された jniutils.c ファイルが見つかります
促す
。フォルダ。

ネイティブファイルの書き込み

まず、Java のガイド パッケージと同様のヘッダー ファイルを追加します。ここで最初に追加するのは、Java と C/C++ 間の言語変換のコア ファイルである jni.h です。詳細については、D:\ を確認してください。 ndk ディレクトリ \ndk-bundle\platforms\android-23\arch-arm\usr\include\jni.h 内の android-sdk では、ここで別の文字列を処理する必要があるため、文字列のヘッダー ファイルもインクルードする必要があります。 h も上記のディレクトリにあります include .
次に、Java のネイティブ メソッドの実装を追加します。jstring:戻り値の型、Java_com_example_yaoobs_HelloJni_stringFromJNI(JNIEnv *env, jobject jobj):実装メソッド名、固定形式、Java_ 実装するメソッド名をアンダースコアに置き換えたJavaクラスの参照アドレス _ メソッド名(JNI環境変数) env、JNI 環境オブジェクト jobj); このうち、env メソッドと jobj メソッドは使用できませんが、ソース コードで説明されているように、宣言する必要もあります。一般的な機能は、env が JNINativeInterface ポインタとして使用されることです。 Java と C/C++ 間の関数 環境変数の真ん中にあるブリッジですが、最初は深くは説明しません。
完全な jniutils.c:

#include <string.h>
#include <jni.h>

jstring
Java_com_example_yaoobs_ndkjnidemo_JniUtils_getStringFromC( JNIEnv* env, jobject thiz ) {

    return (*env)->NewStringUTF(env, "Hello NDK! ");
}

最後にアクティビティを呼び出します。

public class MainActivity extends Activity {
    
    

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ((TextView)findViewById(R.id.txt)).setText(JniUtils.getStringFromC());
    }
}

正常に実行されました:
正常に実行されました

ダイナミックリンクライブラリの直接使用

ほとんどの場合、NDK を使用する場合はネイティブ ファイルを自分で作成する必要はなく、ダイナミック リンク ライブラリ、つまり .so ファイルを直接使用するだけです。多くのサードパーティ SDK は完全なソリューションを提供します。
AS に so ファイルが保存されるディレクトリは、デフォルトでは main/jniLibs の下にありますが、私たちは依然として so ファイルと jar パッケージを app/libs の下に置くことに慣れていますが、次のように gradle に設定を追加する必要があります。

android {
...
 sourceSets {
        main {
            jniLibs.srcDirs = ['libs']
        }
     }
...

このようにして、システムがロードされると、libs ディレクトリに移動してロードされます。
先ほどの例に従うと、app\build\intermediates\ndk\debug\lib の下に、lib+modulename という名前が付いたさまざまなアーキテクチャの so ファイルが見つかります。
これらをすべて libs の下にコピーし、jniutils.c を削除して、実行時にエラーが発生するかどうかを確認できます。

ソース コードは GitHub にアップロードされています。アドレス: https://github.com/Yaoobs/NdkJniDemo

参考記事:
http://blog.csdn.net/yilip/article/details/45200861
http://www.jianshu.com/p/9aff422204eb
http://www.jianshu.com/p/d8cde65cb4f7
http:// www.taoweiji.cn/2016/08/02/ndk/?hmsr=toutiao.io&utm_medium=toutiao.io&utm_source=toutiao.io
http://www.cnblogs.com/zhuyuliang/p/5007016.html

おすすめ

転載: blog.csdn.net/Yaoobs/article/details/51365126