#include <jni.h>
JNIEXPORT jint JNICALL
Java_jnidemo_hlq_com_jnidemo_JNI_checkUser(JNIEnv *env, jobject instance, jstring name_,
jstring pass_) {
const char *name = (env)->GetStringUTFChars(name_, 0);
const char *pass = (env)->GetStringUTFChars(pass_, 0);
// TODO
(env)->ReleaseStringUTFChars( name_, name);
(env)->ReleaseStringUTFChars( pass_, pass);
}
在这里要注意一下,这里我们建的是.cpp文件,至于.c 和 .cpp 就是一个是c一个是c++
c++中代码是
const char *name = (env)->GetStringUTFChars(name_, 0);
c中对应的就是
const char *name = (*env)->GetStringUTFChars(env,name_, 0);
接下来我们要在cmake中进行配置
add_library( # Sets the name of the library.
checkuser
SHARED
src/main/cpp/cheruser.cpp
)
checkuser 就是配置生成的so名称为libcheckuser.so,SHARED配置库文件是共享, src/main/cpp/cheruser.cpp就是对应的路径了
target_link_libraries( # Specifies the target library.
checkuser
Links the target library to the log library
included in the NDK.
${log-lib} )
checkuser保持和上面名字对应就可以了。
这样我们就可以在JNI类中,加载这个库
static {
System.loadLibrary(“checkuser”);
}
在C代码中我们已经得到了name和pass
const char *name = (env)->GetStringUTFChars(name_, 0);
const char *pass = (env)->GetStringUTFChars(pass_, 0);
直接和用户名密码比较即可,这里在代码中将变量名定义为name 密码为123
const char *tureName = “name”;
const char *turePass = “123”;
使用strcmp函数来比较,两个字符串相等则返回0,记得引用string.h头文件
#include <string.h>
if (strcmp(name,tureName) == 0 && strcasecmp(pass,turePass) == 0){
return 1;
} else{
return 0;
}
我们在Activity中输入用户名密码,调用C方法,若返回1则说明登陆成功,若返回0则说明用户名密码不正确,登陆失败
if (new JNI().checkUser(“name”, “123”) == 1) {
Toast.makeText(MainActivity.this, “登陆成功”, Toast.LENGTH_LONG).show();
} else {
Toast.makeText(MainActivity.this, “登陆shibai”, Toast.LENGTH_LONG).show();
}
2.2 c语言调用Java方法
首先我们在JNI类中新建一个sum方法,返回两数之和
public int sum(int i, int j) {
Log.d(“—”, “我是java 我被c调用了” + (i + j));
return i + j;
}
C调用Java肯定要Java调用C的某个方法,在这个方法中调用java方法,所以我们再来新建一个testHello方法
public native String testHello();
默认生成的C方法为
JNIEXPORT jstring JNICALL
Java_jnidemo_hlq_com_jnidemo_JNI_testHello(JNIEnv *env, jobject) {
return (env)->NewStringUTF(“huanglinqing”);
}
我们要调用的java方法在JNI类中,想想java可以通过反射来调用另一个类的方法,那么C其实也是通过反射的,首先我们定义要调用方法的路径,JNI类全路径为jnidemo.hlq.com.jnidemo.JNI,在C中将.替换为/
const char *className = “jnidemo/hlq/com/jnidemo/JNI”;
方法名为sum
const char *sum = “sum”;
通过findClass获取class对象,然后通过AllocObject获取类的实例
jclass jclass1 = env->FindClass(className);
jobject jobject1 = env->AllocObject(jclass1);
然后我们获取到要调用方法的methodId
jmethodID jmethodID1 = env->GetMethodID(jclass1, sum,“(II)I”);
第一个参数是class对象,第二个参数是函数名,第三个参数是方法签名
复制项目app\build\intermediates\classes\debug文件路径,打开cmd,进入路径,(如果之前没有编译过项目记得先编译一下,这样才能获取class文件),使用命令 javap -s jnidemo.hlq.com.jnidemo.JNI jnidemo.hlq.com.jnidemo.JNI是调用方法的全路径。
运行可以看到sum方法的签名是(II)I
获取到方法的jmethodID1之后调用CallIntMethod即可调用方法
jint value = env->CallIntMethod(jobject1, jmethodID1,1,2);
第一个参数是类的实例,第二个参数是获取的jmethodID1,后面就是sum函数依次对应的参数。
代码整体为:
const char *className = “jnidemo/hlq/com/jnidemo/JNI”;
const char *sum = “sum”;
jclass jclass1 = env->FindClass(className);
jmethodID jmethodID1 = env->GetMethodID(jclass1, sum,“(II)I”);
jobject jobject1 = env->AllocObject(jclass1);
jint value = env->CallIntMethod(jobject1, jmethodID1,1,2);
printf(“c 运行结果为 %d”,value);
我们在activity中调用
new JNI().testHello();
上述即为C语言调用了java的方法
- 2.3 检测APP的卸载
相信很多伙伴在面试的时候,总会被问到APP保活的问题,如果你回答不上来,面试官还会一脸鄙视的看着你,APP如何保活?
websocket心跳?三方推送?JNI fork进程?其实我觉得都是扯淡,系统版本越高Google限制的越严格,我们自己做的APP除非是大厂,有白名单,否则不可能做到保活,而这个问题其实问的也没有多大的意义。我曾经试过fork保活,杀死也是秒死。
检测APP卸载就是,当APP被用户卸载之后,自动打开浏览器网页跳转到一个调查问卷让用户去填写为什么会卸载,这个功能PC端软件经常可以看到,APP用的不多,但是也是挺有意思的,但是和保活一样这个功能很鸡肋,版本稍微高一点,就彻底死了,但是我们了解一下还是很有必要的。
首先,我们定义一个方法,传递当前应用包名和当前系统版本
public native void uninstall(String packageName, int versionCode);
在c中使用
尾声
以薪资待遇为基础,以发展为最终目标,要在高薪资的地方,谋求最好的发展!
下面是有几位Android行业大佬对应上方技术点整理的一些进阶资料。
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门,即可获取!
,但是和保活一样这个功能很鸡肋,版本稍微高一点,就彻底死了,但是我们了解一下还是很有必要的。
首先,我们定义一个方法,传递当前应用包名和当前系统版本
public native void uninstall(String packageName, int versionCode);
在c中使用
尾声
以薪资待遇为基础,以发展为最终目标,要在高薪资的地方,谋求最好的发展!
下面是有几位Android行业大佬对应上方技术点整理的一些进阶资料。
[外链图片转存中…(img-aA68CNCT-1715392810079)]
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门,即可获取!