转载

JNI开发笔记(1)

Android Studio 3.0 更新了很多新特性,其中对C++开发者也越来越友好。目前Android Studio默认构建工具是CMake(当然也是支持ndk-build),我们将使用Cmake来开始编写我们的Helleworld。

准备

更新我们的sdk-tool中的LLDB、CMake和NDK三个选项。

JNI开发笔记(1)

创建项目

可以先创建一个helloWorld项目来看下它和普通的Android项目的区别。

JNI开发笔记(1)

JNI开发笔记(1)

这样一步步的next创建了一个简单的Helleworld的用CMake作为构建工具的JNI程序。

来看下它和普通的Android程序的区别吧。

JNI开发笔记(1)

这三处使我们和一般应用程序中所没有的,所以我们在普通程序中添加这三处也是可以添加自己的c/c++代码的。

  1. cpp文件夹使我们的c/c++代码代码的目录,这和src是我们的源代码目录类似。

  2. CMakeLists.txt 是和Gradle交互的一个桥梁,里面的内容类似于我们之前写的make文件。

  3. 在主APP下要写两处 externalNativeBuild ,一处是可以根据处理的来打某一个平台的so文件,而另一处是为了将 CMakeLists.txt 和Gradle构建关联。

运行项目,通过 Analyze APK 是可以直接看到打出来的APK是有这个so的。

配置某个平台(如x86)的so

如上图上的标记3,在第一处添加cpu对应的架构:

>

android {
    defaultConfig {

        ......
        externalNativeBuild {
            cmake {
                cppFlags ""
            }
            ndk {
                abiFilters  'x86'
            }
// ndk {
// abiFilters 'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a','armeabi'
// }
        }
    }
    buildTypes {
        ......
    }
    ......
}

编写一个简单的JNI程序

之前在网易工作时,发现网易系的有些应用是通过so文件来保证数据校验,如加密一个字符串,同时会传一个Context,这样可以通过context来校验是不是正版应用,校验应用的安全信息。我们就来实现一个通过Context来获取包名。

  1. native方法

    我们是通过java代码调用native方法,所以先声明一个native方法:

    package me.cyning.helloworld;
    
    import android.content.Context;
    
    public class NativeUtils{
    
        public static native String getPackageName(Context context);
    }
    
  2. native代码

    在我们的 native-lib.cpp 来实现具体的功能:

    #include<jni.h>
    #include<string>
    
    extern "C" JNIEXPORT jstring
    JNICALL
    Java_me_cyning_helloworld_NativeUtils_getPackageName(
            JNIEnv *env, jclass clazz, jobject instance) {
        jclass nativeClass = env->GetObjectClass(instance);
        jmethodID jmethodID1 = env->GetMethodID(nativeClass, "getPackageName", "()Ljava/lang/String;");
        jstring packageName = static_cast<jstring>(env->CallObjectMethod(instance, jmethodID1));
        return  packageName;
    }
    

让我们来解释下:

  • 函数签名:Java-(包名+类型+函数)(参数)
  • jni编程的类型和java类型的区别

    JNI开发笔记(1)
  • JNI 函数访问 Java 对象的变量

    JNI开发笔记(1)

结合上面的具体代码,很容易理解,先拿到 Context 对应的class类,通过这个类得到 getPackageName 方法的id,通过 CallObjectMethod 这个 Context 实例的 getPackageName 方法,看着很像反射的用法。

原文  http://blog.cyning.cc/2018/05/02/JNI开发笔记(1)/
正文到此结束
Loading...