我们经常会有一些需求,当应用被卸载的时候,发起一个问卷调查,或者清楚推送标识,避免应用都被卸载了还能收到推送(我们公司的项目就这样。。当初可郁闷了)
网上流行的答案: 注册一个receiver.....监听应用被卸载。 我对这个回答的看法与实践:纯属扯淡!
难道就没人去验证一下。。?网上都抄来抄去的。。。应用都被卸载了,你的java代码都被清除了,你些的java代码还能起作用吗。?
思路:开启C进程,监控应用包是否存在,如果不存在了,说明应用被卸载了。
原理:我们都知道,应用时以包名来区分唯一的,而应用包会装载/data/data目录下,而C进程是独立于java进程的,说明java程序被卸载了,它也还是会执行(除非被ROM杀死)
不知道如何开启C进程的童鞋,请看上一篇文章: JNI基础(八)开辟C进程
java代码:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final JNI jni = new JNI();
((Button) findViewById(R.id.bt_fuck)).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// new Thread(
// new Runnable() {
// @Override
// public void run() {
// jni.uninstallListener();
// }
// }
// ).start();
jni.uninstallListener();
}
});
}
}
在这里经过我的测试。。在主线程中调用C开辟新进程的C代码,C代码中有死循环,竟然会阻塞主线程。。我很茫然,都开辟了新进程去执行了为什么还会阻塞主线程,不应该有这种的情况的,但确实现象是这样的,所以上述代码中,有一段开子线程启动jni的代码(执不执行都无所谓,懂原理就行了)。
public class JNI {
/**
* 加载动态链接库
* 也就是c代码编译好的so文件
*/
static {
System.loadLibrary("app");
}
public native void uninstallListener();
}
C代码:
JNIEXPORT void JNICALL
Java_com_example_jnidemo_JNI_uninstallListener(JNIEnv *env, jobject instance) {
//开辟C进程
int pid = fork();
//如果大于等于0,说明进程开辟成功
if(pid >= 0){
int flag = 1;
while (flag){
//这个1就代表1秒,与C语言的Sleep函数有区别的,请区分清楚,这个函数首字母不大写
sleep(1);
/**
* C语言读取文件....
* 第一个参数:路径
* 第二个参数:文件mode,分为rwx : linux系统的文件权限,r代表读,w代表写,x代表可执行
*/
FILE *file = fopen("/data/data/com.example.jnidemo","r");
if(file == NULL){
LOGI("软件不在了,被卸载了T T....");
// //跳出循环,退出进程。
// flag = 0;
} else{
LOGI("软件运行良好→_→.");
}
}
}
}
使用FILE指针,需要导入头文件
#include <stdio.h>
结果:
这样就可以监听到了。有了这样的思路,类似的业务场景都可以解决。