Android应用如何监听自己是否被卸载及卸载反馈功能的实现

来源:互联网 发布:淘宝老店新开没流量 编辑:程序博客网 时间:2024/04/18 12:28

转自 http://blog.csdn.net/jackrex/article/details/11192047 

一个应用被用户卸载肯定是有理由的,而开发者却未必能得知这一重要的理由,毕竟用户很少会主动反馈建议,多半就是用得不爽就卸,如果能在被卸载后获取到用户的一些反馈,那对开发者进一步改进应用是非常有利的。目前据我所知,国内的Android应用中实现这一功能的只有360手机卫士、360平板卫士,那么如何实现这一功能的?

  我们可以把实现卸载反馈的问题转化为监听自己是否被卸载,只有得知自己被卸载,才可以设计相应的反馈处理流程。以下的列表是我在研究这一问题的思路:

  1,注册BroadcastReceiver,监听"android.intent.action.PACKAGE_REMOVED"系统广播

  结果:NO。未写代码,直接分析,卸载的第一步就是退出当前应用的主进程,而此广播是在已经卸载完成后才发出的,此时主进程都没有了,去哪onReceive()呢?

  2,若能收到"将要卸载XX包"的系统广播,在主进程被退出之前就抢先进行反馈处理就好了,可惜没有这样的系统广播,不过经过调研,倒是发现了一个办法,读取系统log,当日志中包含"android.intent.action.DELETE"和自己的包名时,意味着自己将要被卸载。

  结果:NO。调试时发现此方法有两个缺陷,(1)点击设置中的卸载按钮即发出此Intent,此时用户尚未在弹框中确认卸载;(2)pm命令卸载不出发此Intent,意味着被诸如手机安全管家,豌豆荚等软件卸载时,无法提前得知卸载意图。

  3,由于时间点不容易把控,所以干脆不依赖系统广播或log,考虑到卸载过程会删除"/data/data/包名"目录,我们可以用线程直接轮询这个目录是否存在,以此为依据判断自己是否被卸载。

  结果:NO。同方法1,主进程退出,相应的线程必定退出,线程还没等到判断目录是否存在就已经被销毁了。

  4,改用C端进程轮询"/data/data/包名"目录是否存在

  结果:YES。借助Java端进程fork出来的C端进程在应用被卸载后不会被销毁。

  OK,上代码!

Activity启动时fork出C端进程轮询目录:

复制代码
 1 package main.activity; 2  3 import pym.test.uninstalledmoniter.R; 4 import android.app.Activity; 5 import android.os.Bundle; 6 import android.util.Log; 7  8 /** 9  * @author pengyiming10  * @note 监听此应用是否被卸载,若被卸载则弹出卸载反馈11  *12  */13 14 public class UninstalledMoniterActivity extends Activity15 {16     /* 数据段begin */17     private static final String TAG = "UninstalledMoniterActivity";18     /* 数据段end */19     20     /* 函数段begin */21     private native void init();22     static23     {24         Log.d(TAG, "load libuninstalled_moniter");25         System.loadLibrary("uninstalled_moniter");26     }27     28     @Override29     public void onCreate(Bundle savedInstanceState)30     {31         super.onCreate(savedInstanceState);32         Log.d(TAG, "onCreate");33         34         setContentView(R.layout.uninstalled_moniter_layout);35         36         init();37     }38     /* 函数段end */39 }
复制代码

核心——native方法头文件:

复制代码
 1 /* 头文件begin */ 2 #include <jni.h> 3 #include <stdio.h> 4 #include <string.h> 5 #include <android/log.h> 6 #include <unistd.h> 7 /* 头文件end */ 8  9 /* 宏定义begin */10 //清0宏11 #define MEM_ZERO(pDest, destSize) memset(pDest, 0, destSize)12 13 //LOG宏定义14 #define LOG_INFO(tag, msg) __android_log_write(ANDROID_LOG_INFO, tag, msg)15 #define LOG_DEBUG(tag, msg) __android_log_write(ANDROID_LOG_DEBUG, tag, msg)16 #define LOG_WARN(tag, msg) __android_log_write(ANDROID_LOG_WARN, tag, msg)17 #define LOG_ERROR(tag, msg) __android_log_write(ANDROID_LOG_ERROR, tag, msg)18 /* 宏定义end */19 20 #ifndef _Included_main_activity_UninstalledMoniterActivity21 #define _Included_main_activity_UninstalledMoniterActivity22 #ifdef __cplusplus23 extern "C" {24 #endif25 26 #undef main_activity_UninstalledMoniterActivity_MODE_PRIVATE27 #define main_activity_UninstalledMoniterActivity_MODE_PRIVATE 0L28 #undef main_activity_UninstalledMoniterActivity_MODE_WORLD_READABLE29 #define main_activity_UninstalledMoniterActivity_MODE_WORLD_READABLE 1L30 #undef main_activity_UninstalledMoniterActivity_MODE_WORLD_WRITEABLE31 #define main_activity_UninstalledMoniterActivity_MODE_WORLD_WRITEABLE 2L32 #undef main_activity_UninstalledMoniterActivity_MODE_APPEND33 #define main_activity_UninstalledMoniterActivity_MODE_APPEND 32768L34 #undef main_activity_UninstalledMoniterActivity_MODE_MULTI_PROCESS35 #define main_activity_UninstalledMoniterActivity_MODE_MULTI_PROCESS 4L36 #undef main_activity_UninstalledMoniterActivity_BIND_AUTO_CREATE37 #define main_activity_UninstalledMoniterActivity_BIND_AUTO_CREATE 1L38 #undef main_activity_UninstalledMoniterActivity_BIND_DEBUG_UNBIND39 #define main_activity_UninstalledMoniterActivity_BIND_DEBUG_UNBIND 2L40 #undef main_activity_UninstalledMoniterActivity_BIND_NOT_FOREGROUND41 #define main_activity_UninstalledMoniterActivity_BIND_NOT_FOREGROUND 4L42 #undef main_activity_UninstalledMoniterActivity_BIND_ABOVE_CLIENT43 #define main_activity_UninstalledMoniterActivity_BIND_ABOVE_CLIENT 8L44 #undef main_activity_UninstalledMoniterActivity_BIND_ALLOW_OOM_MANAGEMENT45 #define main_activity_UninstalledMoniterActivity_BIND_ALLOW_OOM_MANAGEMENT 16L46 #undef main_activity_UninstalledMoniterActivity_BIND_WAIVE_PRIORITY47 #define main_activity_UninstalledMoniterActivity_BIND_WAIVE_PRIORITY 32L48 #undef main_activity_UninstalledMoniterActivity_BIND_IMPORTANT49 #define main_activity_UninstalledMoniterActivity_BIND_IMPORTANT 64L50 #undef main_activity_UninstalledMoniterActivity_BIND_ADJUST_WITH_ACTIVITY51 #define main_activity_UninstalledMoniterActivity_BIND_ADJUST_WITH_ACTIVITY 128L52 #undef main_activity_UninstalledMoniterActivity_CONTEXT_INCLUDE_CODE53 #define main_activity_UninstalledMoniterActivity_CONTEXT_INCLUDE_CODE 1L54 #undef main_activity_UninstalledMoniterActivity_CONTEXT_IGNORE_SECURITY55 #define main_activity_UninstalledMoniterActivity_CONTEXT_IGNORE_SECURITY 2L56 #undef main_activity_UninstalledMoniterActivity_CONTEXT_RESTRICTED57 #define main_activity_UninstalledMoniterActivity_CONTEXT_RESTRICTED 4L58 #undef main_activity_UninstalledMoniterActivity_RESULT_CANCELED59 #define main_activity_UninstalledMoniterActivity_RESULT_CANCELED 0L60 #undef main_activity_UninstalledMoniterActivity_RESULT_OK61 #define main_activity_UninstalledMoniterActivity_RESULT_OK -1L62 #undef main_activity_UninstalledMoniterActivity_RESULT_FIRST_USER63 #define main_activity_UninstalledMoniterActivity_RESULT_FIRST_USER 1L64 #undef main_activity_UninstalledMoniterActivity_DEFAULT_KEYS_DISABLE65 #define main_activity_UninstalledMoniterActivity_DEFAULT_KEYS_DISABLE 0L66 #undef main_activity_UninstalledMoniterActivity_DEFAULT_KEYS_DIALER67 #define main_activity_UninstalledMoniterActivity_DEFAULT_KEYS_DIALER 1L68 #undef main_activity_UninstalledMoniterActivity_DEFAULT_KEYS_SHORTCUT69 #define main_activity_UninstalledMoniterActivity_DEFAULT_KEYS_SHORTCUT 2L70 #undef main_activity_UninstalledMoniterActivity_DEFAULT_KEYS_SEARCH_LOCAL71 #define main_activity_UninstalledMoniterActivity_DEFAULT_KEYS_SEARCH_LOCAL 3L72 #undef main_activity_UninstalledMoniterActivity_DEFAULT_KEYS_SEARCH_GLOBAL73 #define main_activity_UninstalledMoniterActivity_DEFAULT_KEYS_SEARCH_GLOBAL 4L74 75 /*76  * Class:     main_activity_UninstalledMoniterActivity77  * Method:    init78  * Signature: ()V79  */80 JNIEXPORT void JNICALL Java_main_activity_UninstalledMoniterActivity_init(JNIEnv *, jobject);81 82 #ifdef __cplusplus83 }84 #endif85 #endif
复制代码

核心——native方法实现:

复制代码
 1 /* 头文件begin */ 2 #include "main_activity_UninstalledMoniterActivity.h" 3 /* 头文件end */ 4  5 #ifdef __cplusplus 6 extern "C" { 7 #endif 8  9 /* 内全局变量begin */10 static char c_TAG[] = "UninstalledMoniterActivity.init";11 static jboolean b_IS_COPY = JNI_TRUE;12 /* 内全局变量 */13 14 /*15  * Class:     main_activity_UninstalledMoniterActivity16  * Method:    init17  * Signature: ()V18  */19 JNIEXPORT void JNICALL Java_main_activity_UninstalledMoniterActivity_init(JNIEnv *env, jobject obj)20 {21     jstring tag = (*env)->NewStringUTF(env, c_TAG);22 23     //初始化log24     LOG_DEBUG((*env)->GetStringUTFChars(env, tag, &b_IS_COPY)25             , (*env)->GetStringUTFChars(env, (*env)->NewStringUTF(env, "init OK"), &b_IS_COPY));26 27     //fork子进程,以执行轮询任务28     pid_t pid = fork();29     if (pid < 0)30     {31         //出错log32         LOG_ERROR((*env)->GetStringUTFChars(env, tag, &b_IS_COPY)33                 , (*env)->GetStringUTFChars(env, (*env)->NewStringUTF(env, "fork error !!!"), &b_IS_COPY));34     }35     else if (pid == 0)36     {37         //子进程轮询"/data/data/pym.test.uninstalledmoniter"目录是否存在,若不存在则说明已被卸载38         while (1)39         {40             FILE *p_file = fopen("/data/data/pym.test.uninstalledmoniter", "r");41             if (p_file != NULL)42             {43                 fclose(p_file);44 45                 //目录存在log46                 LOG_DEBUG((*env)->GetStringUTFChars(env, tag, &b_IS_COPY)47                             , (*env)->GetStringUTFChars(env, (*env)->NewStringUTF(env, "I'm OK !!!"), &b_IS_COPY));48 49                 sleep(1);50             }51             else52             {53                 //目录不存在log54                 LOG_DEBUG((*env)->GetStringUTFChars(env, tag, &b_IS_COPY)55                             , (*env)->GetStringUTFChars(env, (*env)->NewStringUTF(env, "I'm NOT OK !!!"), &b_IS_COPY));56 57                 //执行命令am start -a android.intent.action.VIEW -d http://shouji.360.cn/web/uninstall/uninstall.html58                 execlp("am", "am", "start", "-a", "android.intent.action.VIEW", "-d", "http://shouji.360.cn/web/uninstall/uninstall.html", (char *)NULL);59             }60         }61     }62     else63     {64         //父进程直接退出,使子进程被init进程领养,以避免子进程僵死65     }66 }67 68 #ifdef __cplusplus69 }70 #endif
复制代码

注1:为了调试方便,包含<android/log.h>,使得so在执行过程中也可以像Java端一样方便得打出log。相应的mk文件需要加上以下两句声明

LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
LOCAL_LDLIBS += -L$(SYSROOT)/usr/lib -llog

注2:代码中引用了360手机卫士的反馈地址,仅供大家学习、测试使用~~~

http://www.cnblogs.com/zealotrouge/p/3157126.html


https://github.com/sevenler/Uninstall_Statics

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 小孩社保卡掉了怎么办 社区医保本丢了怎么办 宝宝医保卡掉了怎么办 同煤医疗卡丢了怎么办 杭州医保卡丢了怎么办 新的医保卡丢了怎么办 二代医保卡丢了怎么办 老医保卡丢了怎么办 上海医保卡余额用完了怎么办 身份证丢了医疗报销怎么办 取公积金身份证丢了怎么办 身份证丢了怎么办就诊卡 人在外地怎么办农村社保卡 武汉医保卡丢了怎么办 济宁社保卡丢了怎么办 农村医疗本丢了怎么办 常熟医保卡丢了怎么办 农民社保卡丢了怎么办 常熟社保卡坏了怎么办 社保卡丢失补办期看病怎么办 社保卡补办期间看病怎么办 医保卡冻结了出院结算怎么办 住院医保卡钱不够怎么办 住院押金条丢了怎么办 急用新社保卡要怎么办 看病没带社保卡怎么办 医保卡掉了住院怎么办 厦门医保卡丢了怎么办 成都医保卡丢了怎么办 长春医保卡丢了怎么办 县城医保卡丢了怎么办 医保卡丢了怎么办南宁 西安职工医保丢了怎么办 重庆医保卡丢了怎么办 外地医保卡丢了怎么办 换单位后医保卡怎么办 单位没交失业金怎么办 沈阳医保卡密码忘了怎么办 西安网约车资格证怎么办 红跑车卡丢了怎么办 苏州住房公积金密码忘了怎么办