JNI开发笔记(1)- 入门
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对应的架构:
1 | android { |
编写一个简单的JNI程序
之前在网易工作时,发现网易系的有些应用是通过so文件来保证数据校验,如加密一个字符串,同时会传一个Context,这样可以通过context来校验是不是正版应用,校验应用的安全信息。我们就来实现一个通过Context来获取包名。
native方法
我们是通过java代码调用native方法,所以先声明一个native方法:1
2
3
4
5
6
7
8package me.cyning.helloworld;
import android.content.Context;
public class NativeUtils {
public static native String getPackageName(Context context);
}native代码
在我们的native-lib.cpp
来实现具体的功能:1
2
3
4
5
6
7
8
9
10
11
12
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 函数访问 Java 对象的变量
结合上面的具体代码,很容易理解,先拿到Context
对应的class类,通过这个类得到getPackageName
方法的id,通过CallObjectMethod
这个Context
实例的getPackageName
方法,看着很像反射的用法。
参考
- 本文链接:http://ownwell.github.io/2018/04/27/JNI开发笔记(1)/
- 版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC-SA 3.0 CN 许可协议。转载请注明出处!