Android Studio 3.0 更新了很多新特性,其中对C++开发者也越来越友好。目前Android Studio默认构建工具是CMake(当然也是支持ndk-build),我们将使用Cmake来开始编写我们的Helleworld。
更新我们的sdk-tool中的LLDB、CMake和NDK三个选项。
可以先创建一个helloWorld项目来看下它和普通的Android项目的区别。
这样一步步的next创建了一个简单的Helleworld的用CMake作为构建工具的JNI程序。
来看下它和普通的Android程序的区别吧。
这三处使我们和一般应用程序中所没有的,所以我们在普通程序中添加这三处也是可以添加自己的c/c++代码的。
cpp文件夹使我们的c/c++代码代码的目录,这和src是我们的源代码目录类似。
CMakeLists.txt
是和Gradle交互的一个桥梁,里面的内容类似于我们之前写的make文件。
在主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 { ...... } ...... }
之前在网易工作时,发现网易系的有些应用是通过so文件来保证数据校验,如加密一个字符串,同时会传一个Context,这样可以通过context来校验是不是正版应用,校验应用的安全信息。我们就来实现一个通过Context来获取包名。
native方法
我们是通过java代码调用native方法,所以先声明一个native方法:
package me.cyning.helloworld; import android.content.Context; public class NativeUtils{ public static native String getPackageName(Context context); }
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; }
让我们来解释下:
jni编程的类型和java类型的区别
JNI 函数访问 Java 对象的变量
结合上面的具体代码,很容易理解,先拿到 Context
对应的class类,通过这个类得到 getPackageName
方法的id,通过 CallObjectMethod
这个 Context
实例的 getPackageName
方法,看着很像反射的用法。