Notas de estudio del NDK (1)

Notas de estudio del NDK (1)

Todos sabemos que las aplicaciones de Android están escritas en Java, pero a veces necesitamos usar C/C++ para el desarrollo, o necesitamos interactuar con la capa subyacente. Java mismo proporciona el método JNI, pero existen obstáculos técnicos en el desarrollo de Android. Por ejemplo, el programa es más complicado, la compatibilidad es difícil de garantizar, no se puede acceder a Framework API y la depuración es más difícil. Así nació NDK. El nombre completo de NDK es Native Development Kit. El lanzamiento de NDK finalmente convirtió el método de desarrollo "Java+C" en uno positivo, convirtiéndose en un método de desarrollo con soporte oficial. NDK será el comienzo de la plataforma Android para admitir el desarrollo de C.

Ventajas de usar NDK

  1. Es fácil de trasplantar y la biblioteca escrita en C/C++ se puede volver a usar fácilmente en otras plataformas.
  2. Protección de código, porque el código de la capa Java es fácil de descompilar y la descompilación de la biblioteca C/C++ es más difícil.
  3. Mejorar la eficiencia de ejecución del programa requerirá que se desarrolle una lógica de aplicación de alto rendimiento usando C/C++, mejorando así la eficiencia de ejecución del programa de aplicación.
  4. Para acceder a las bibliotecas de código abierto existentes, debe acceder a la API subyacente o hacer referencia a algunas bibliotecas que solo tienen C/C++.

Configurar el entorno NDK

Si ha descargado el NDK, puede establecer su ruta, la ubicación del NDK de Android en Archivo->Estructura del proyecto , el valor predeterminado es su ruta SDK\ndk-bundle. Si no se ha descargado, simplemente haga clic en descargar para descargar. Por supuesto, también puede
descargar otras versiones y colocarlas en cualquier lugar, y luego configurar manualmente la ruta.
Si la configuración es correcta, la ruta del NDK se agregará en el archivo local.properties del proyecto:

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

Si no, se puede agregar manualmente. Además, durante la compilación, si ocurre un error de la siguiente manera:

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.

Es causado por la inconsistencia entre su versión NDK y la versión AS, solo agregue una línea debajo del archivo gradle.propertiesandroid.useDeprecatedNdk=true : .
(Si desea utilizar la línea de comandos, debe agregar una variable de entorno del sistema, crear un nuevo nombre de variable ANDROID_NDK_HOME y el valor de la variable correspondiente es la dirección del directorio raíz de ndk, es decir, $SDKpath\ndk-bundle, y luego agregue ANDROID_NDK_HOME a la Ruta (%ANDROID_NDK_HOME% ; ) , confirme OK.)

Escriba archivos nativos usted mismo

Bien, ahora podemos escribir nuestra primera aplicación NDK. En el ejemplo más simple, C genera una cadena y luego la llama en Android para mostrarla. En primer lugar, como siempre, New a Project. Luego cree una nueva clase Java, la llamamos JniUtils. Aquí cargaremos la biblioteca dinámica y crearemos métodos nativos. (De hecho, también puede hacer esto en MainActivity, pero para que el código se vea más claro, aún elegimos escribirlo por separado. Además, no puede hacer esto en el módulo de la aplicación, sino en un módulo separado). Primero cree
un El método nativo, es decir, la interfaz JNI, es un puente entre C/C++ y Java.

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

En este momento, vemos que el color de getStringFromC es rojo, porque no se ha encontrado la implementación de este método. A continuación escribiremos este método.
Si la vista predeterminada es Android, ajústela a la vista Proyecto. En $ProjectName/app/src/main , cree una nueva carpeta cuyo tipo sea JNI Folder . Este directorio almacena principalmente archivos jni, a saber, archivos c/cpp y archivos de encabezado. A continuación, hay dos formas de crear un archivo C, dependiendo de su versión de Gradle, hablemos de ello por separado y comparemos:

Complemento estable

Si su build.gradle en Proyecto se ve así:

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

Es una versión estable del plugin.
Después de completar el paso anterior, limpie el proyecto y reconstruya el proyecto para ver si $ProjectName/app/build/intermediats/classes/ existe, y luego abra la Terminal para ingresar el comando:

cd app/build/intermediates/classes/debug

Luego ingrese el comando:

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

Se encuentra que hay un com_example_yaoobs_ndkjnidemo_JniUtils.h adicional en classes/debug . Córtelo en la carpeta JNI creada anteriormente, cree un nuevo archivo fuente C/C++ y asígnele el nombre jniUtils.c . Modifique jniUtils.c según el nombre del método en com_example_yaoobs_ndkjnidemo_JniUtils.h .

Complemento experimental (Complemento experimental de Gradle)

El complemento experimental de Gradle se desarrolló en función de las nuevas características de Gradle para reducir el tiempo de configuración del proyecto y brindar una mejor compatibilidad con NDK.
(Tenga en cuenta que esto es solo un complemento, que requiere el soporte de gradle y corresponde a su versión. La versión de gradle del autor es 2.1.0, y el gradle-experimental correspondiente es 0.7.0). Para usar el complemento: en, primero tenemos que compilar
Modifique la referencia de gradle en gradle:

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

Luego modifique build.gradle debajo del módulo. Hay algunas diferencias gramaticales. Las antiguas están comentadas. Puede compararlas:

//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'
}

Después de completar, encontrará el método nativo getStringFromC() en JniUtils.class Presione Alt+Enter y aparecerá un mensaje, como se muestra en la siguiente figura: presione Enter
Inmediato
y encontrará un archivo jniutils.c creado bajo JNI Carpeta.

Escribir archivos nativos

Primero, agregue un archivo de encabezado, similar al paquete de guía en java. Lo primero que debe agregar aquí es jni.h, que es el archivo principal para la conversión de idioma entre java y c/c++. Para obtener más información, puede consultar D:\ android-sdk en el directorio ndk \ndk-bundle\platforms\android-23\arch-arm\usr\include\jni.h, se debe procesar otra cadena aquí, por lo que también debe incluir el archivo de encabezado de la cadena. h, que también se puede encontrar en el directorio anterior include
Luego, agregue la implementación del método nativo en java. jstring: Tipo de valor devuelto, Java_com_example_yaoobs_HelloJni_stringFromJNI(JNIEnv *env, jobject jobj): Nombre del método implementado, formato fijo, Java_ La dirección de referencia de la clase Java donde el nombre del método que se implementará se reemplaza por un guión bajo _ Nombre del método (variable de entorno JNI env, objeto de entorno JNI jobj); entre ellos, no se pueden usar los métodos env y jobj, pero también se debe declarar, como se explica en el código fuente, la función general es que se use env como un puntero JNINativeInterface, que es un función entre java y c/c++ El puente en medio de la variable de entorno, no profundicemos primero.
El jniutils.c completo:

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

jstring
Java_com_example_yaoobs_ndkjnidemo_JniUtils_getStringFromC( JNIEnv* env, jobject thiz ) {

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

Finalmente llame a Actividad:

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());
    }
}

Ejecutar con éxito:
ejecutar con éxito

Uso directo de bibliotecas de enlaces dinámicos

En la mayoría de los casos, no necesitamos escribir archivos nativos nosotros mismos cuando usamos NDK, solo usamos la biblioteca de vínculos dinámicos, es decir, el archivo .so directamente. Muchos SDK de terceros proporcionan soluciones completas.
El directorio donde se almacenan los archivos so en AS está predeterminado en main/jniLibs, pero todavía estamos acostumbrados a poner archivos so y paquetes jar en app/libs, pero necesitamos agregar una configuración en gradle, como sigue:

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

De esta manera, cuando el sistema cargue, irá al directorio libs para cargar.
Siguiendo el ejemplo de ahora, en app\build\intermediates\ndk\debug\lib, encontrará archivos so de varias arquitecturas, nombrados por lib+modulename.
Puede copiarlos todos en libs y luego eliminar jniutils.c para ver si habrá un error al ejecutar.

El código fuente ha sido subido a GitHub, dirección: https://github.com/Yaoobs/NdkJniDemo

Artículo de referencia:
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

Supongo que te gusta

Origin blog.csdn.net/Yaoobs/article/details/51365126
Recomendado
Clasificación