Android应用监听自己被卸载

最近做项目需要知道自己何时被卸载了,开始就想到监听程序被卸载的广播。但是这样并不行,想了想当程序被卸载时,首先系统会退出程序在内存的进程,进程都没有了,广播当然也收不到了。
网上搜索了下,发现几篇博客很有用。。。

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

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

项目中会用到一些jni文件,项目github地址:

https://github.com/sevenler/Uninstall_Statics

download下来的项目有这几个重要的文件

这里写图片描述

MyActivity:
public class MyActivity extends Activity {
    /**
     * Called when the activity is first created.
     */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        initPackageRemovedListener();
    }
    private void initPackageRemovedListener() {
        Intent intent = new Intent(this, SDCardListenSer.class);
        startService(intent);
        init();
    }
    private native void init();
    static {
        Log.d("onEvent", "load jni lib");
        System.loadLibrary("hello-jni");
    }
}
SDCardListenSer:
这就是监听文件状态的serveice类
注意/data/data/com.example.untitled 这个报名要换成自己的包名;
public class SDCardListenSer extends Service {

    SDCardListener[] listenners;

    @Override
    public void onCreate() {
        SDCardListener[] listenners = {new SDCardListener("/data/data/com.example.untitled", this),
                new SDCardListener(Environment.getExternalStorageDirectory() + File.separator + "1.txt", this)};
        this.listenners = listenners;
        Log.i("onEvent", "=========onCreate============");
        for (SDCardListener listener : listenners) {
            listener.startWatching();
        }
        File file = new File(Environment.getExternalStorageDirectory() + File.separator + "1.txt");
        Log.i("onEvent", "dddddddddddddddddddddd nCreate============");
        if (file.exists())
            file.delete();
        try {
            file.createNewFile();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    @Override
    public void onDestroy() {
        for (SDCardListener listener : listenners) {
            listener.stopWatching();
        }
    }
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}

class SDCardListener extends FileObserver {
    private String mPath;
    private final Context mContext;
    public SDCardListener(String parentpath, Context ctx) {
        super(parentpath);
        this.mPath = parentpath;
        this.mContext = ctx;
    }

    @Override
    public void onEvent(int event, String path) {
        int action = event & FileObserver.ALL_EVENTS;
        switch (action) {
            case FileObserver.DELETE:
                Intent intent = new Intent();
                //exeShell("am start -a android.intent.action.VIEW -d http:aoi.androidesk.com");
                Log.i("onEvent", "打包请关闭****DELETE 删除 " + mPath + File.separator + path);
                Log.i("onEvent", "打包请关闭****DELETE 删除 " + mPath + File.separator + path);
                Log.i("onEvent", "打包请关闭****DELETE 删除 " + mPath + File.separator + path);
                Log.i("onEvent", "打包请关闭****DELETE 删除 " + mPath + File.separator + path);
                Log.i("onEvent", "打包请关闭****DELETE 删除 " + mPath + File.separator + path);
                Log.i("onEvent", "打包请关闭****DELETE 删除 " + mPath + File.separator + path);
                Log.i("onEvent", "打包请关闭****DELETE 删除 " + mPath + File.separator + path);
                Log.i("onEvent", "打包请关闭****DELETE 删除 " + mPath + File.separator + path);
                Log.i("onEvent", "打包请关闭****DELETE 删除 " + mPath + File.separator + path);
                Log.i("onEvent", "打包请关闭****DELETE 删除 " + mPath + File.separator + path);
                //openBrowser();
                break;
            case FileObserver.MODIFY:
                Log.i("onEvent", "打包请关闭****MODIFY 修改 " + mPath + File.separator + path);
                break;
            case FileObserver.CREATE:
                Log.i("onEvent", "打包请关闭****CREATE 创建 " + mPath + File.separator + path);
                break;
            default:
                break;
        }
    }

    protected void openBrowser() {
        Uri uri = Uri.parse("http://aoi.androidesk.com");
        Intent intent = new Intent(Intent.ACTION_VIEW, uri);
        mContext.startActivity(intent);
    }

    public void exeShell(String cmd){
        try{
            Runtime.getRuntime().exec(cmd);
            /*BufferedReader in = new BufferedReader(
                    new InputStreamReader(
                            p.getInputStream()));
            String line = null;
            while ((line = in.readLine()) != null) {
                Log.i("exeShell",line);
            }*/

        }
        catch(Throwable t)
        {
            t.printStackTrace();
        }
    }
}
Android.mk:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE    := hello-jni
LOCAL_SRC_FILES := hello-jni.c
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
LOCAL_LDLIBS += -L$(SYSROOT)/usr/lib -llog
include $(BUILD_SHARED_LIBRARY)
hello-jni.c:
1. 记住如果是要在自己项目中添加了jni文件,这个类名“Java_com_example_untitled_MyActivity_init”要换成自己的哟。
2. "/data/data/com.example.untitled"    自己的包名也要改哟。
jstring
Java_com_example_untitled_MyActivity_init( JNIEnv* env,
                                                 jobject thiz )
{
    jstring tag = (*env)->NewStringUTF(env, c_TAG);

    //初始化log
    LOG_DEBUG((*env)->GetStringUTFChars(env, tag, &b_IS_COPY)
            , (*env)->GetStringUTFChars(env, (*env)->NewStringUTF(env, "init OK"), &b_IS_COPY));

    //fork子进程,以执行轮询任务
    pid_t pid = fork();
    if (pid < 0)
    {
        //出错log
        LOG_ERROR((*env)->GetStringUTFChars(env, tag, &b_IS_COPY)
                , (*env)->GetStringUTFChars(env, (*env)->NewStringUTF(env, "fork failed !!!"), &b_IS_COPY));
    }
    else if (pid == 0)
    {
        //子进程注册"/data/data/pym.test.uninstalledobserver"目录监听器
        int fileDescriptor = inotify_init();
        if (fileDescriptor < 0)
        {
            LOG_DEBUG((*env)->GetStringUTFChars(env, tag, &b_IS_COPY)
                    , (*env)->GetStringUTFChars(env, (*env)->NewStringUTF(env, "inotify_init failed !!!"), &b_IS_COPY));

             exit(1);
        }

        int watchDescriptor;
        watchDescriptor = inotify_add_watch(fileDescriptor, "/data/data/com.example.untitled", IN_DELETE);
        if (watchDescriptor < 0)
        {
            LOG_DEBUG((*env)->GetStringUTFChars(env, tag, &b_IS_COPY)
                    , (*env)->GetStringUTFChars(env, (*env)->NewStringUTF(env, "inotify_add_watch failed !!!"), &b_IS_COPY));

            exit(1);
        }

        //分配缓存,以便读取event,缓存大小=一个struct inotify_event的大小,这样一次处理一个event
        void *p_buf = malloc(sizeof(struct inotify_event));
        if (p_buf == NULL)
        {
            LOG_DEBUG((*env)->GetStringUTFChars(env, tag, &b_IS_COPY)
                    , (*env)->GetStringUTFChars(env, (*env)->NewStringUTF(env, "malloc failed !!!"), &b_IS_COPY));

            exit(1);
        }
        //开始监听
        LOG_DEBUG((*env)->GetStringUTFChars(env, tag, &b_IS_COPY)
                    , (*env)->GetStringUTFChars(env, (*env)->NewStringUTF(env, "start observer"), &b_IS_COPY));
        size_t readBytes = read(fileDescriptor, p_buf, sizeof(struct inotify_event));

        //read会阻塞进程,走到这里说明收到目录被删除的事件,注销监听器
        free(p_buf);
        inotify_rm_watch(fileDescriptor, IN_DELETE);

        //目录不存在log
        LOG_DEBUG((*env)->GetStringUTFChars(env, tag, &b_IS_COPY)
                    , (*env)->GetStringUTFChars(env, (*env)->NewStringUTF(env, "uninstalled"), &b_IS_COPY));

        //执行命令am start -a android.intent.action.VIEW -d http://shouji.360.cn/web/uninstall/uninstall.html
       // execlp("am", "am", "start", "-a", "android.intent.action.VIEW", "-d", "http://shouji.360.cn/web/uninstall/uninstall.html", (char *)NULL);
        //4.2以上的系统由于用户权限管理更严格,需要加上 --user 0
       execlp("am", "am", "start","--user", "0" ,"-a", "android.intent.action.VIEW", "-d", "https://www.google.com", (char *)NULL);

    }
    else
    {
        //父进程直接退出,使子进程被init进程领养,以避免子进程僵死
    }

    return (*env)->NewStringUTF(env, "Hello from JNI !");
}
libhello-jni.so:就是c文件编译的so文件。
如果是集成在自己的项目中,就得更换调用jni native 方法的那个类名,在.C文件中,还有更换包名,上面有说;最后集成ndk工具包,编译出新的.so文件就好了。

参考博客:http://blog.csdn.net/laczff21/article/details/7542236

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值