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 方法,看着很像反射的用法。