您好,登錄后才能下訂單哦!
這篇文章主要介紹了android監聽應用是否被卸載的方法,具有一定借鑒價值,需要的朋友可以參考下。如下資料是關于android實現監聽的詳細步驟內容。
一 效果演示
打開應用效果圖:
圖1
點擊卸載后提示,如下圖:
圖2
然后退出應用,卸載程序,會發現當應用被卸載以后,會彈出調用瀏覽器的提示,這里隨便放了一個搜狐瀏覽頁面,在自己的應用中應該調用的一般都是調查頁面。如下圖:
圖3
ok,效果前面已經演示了,現在需要討論一下其具體實現了。
首先,通過adb shell進入手機,然后第一次進入應用,像圖1一樣,不點擊按鈕,通過 ps | busybox grep ubuntu 看這個應用的進程信息,如下圖:
這個時候只有
u0_a108 2953 124 490956 47792 ffffffff 40052a40 S com.example.ubuntuforandroid
2953 這一個進程
點擊 卸載后提示 按鈕再次,執行剛才執行的ps命令,發現已經有兩個進程了如下圖:
其實新產生的進程是通過程序調用jni接口
public static native int Reguninstall(String path,String url);
這個接口fork了一個進程,而新fork的進程負責監聽本應用是否被卸載了
二 源碼分析
java層的代碼如下,很簡單,就是調用一下jni接口
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initInjectFunction("testfile"); test = (TextView)this.findViewById(R.id.testview); test.setText("點擊卸載后提示按鈕,你的應用在卸載以后會調用瀏覽器,然后調用你需要的頁面。"); btn = (Button)this.findViewById(R.id.testbtn); btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub String directory = MainActivity.this.getFilesDir().getAbsolutePath(); String url = "http://www.sohu.com/"; JniExec.Reguninstall(directory,url); test.setText("現在可以退出應用,然后卸載應用,看看是否有效果"); } }); }
一目了然,不用多言了
現在就分析
package com.example.ubuntuforandroid; public class JniExec { static { System.loadLibrary("uninstall"); } public static native int Reguninstall(String path,String url); }
Reguninstall 這個jni接口里面做了什么事情,能夠達到監聽本身應用卸載的效果。
native代碼分析
jint Java_com_example_ubuntuforandroid_JniExec_Reguninstall(JNIEnv* env, jobject thiz, jstring path, jstring url) { LOGI("Java_com_example_ubuntuforandroid_JniExec_Reguninstall"); char *listenpath = (char*) (*env)->GetStringUTFChars(env,path, 0); char *jumpurl = (char*) (*env)->GetStringUTFChars(env,url, 0); LOGI("notify path is %s",listenpath); LOGI("jumpurl is %s",jumpurl); pid_t pid; pid = fork(); if(pid == 0) { //子進程 inotify_main(listenpath,jumpurl); } //父進程不阻塞調用 waitpid ok 子進程變成了孤兒進程,被init進程收養了 pid = waitpid(-1,0,1); LOGI("father bye bye"); return 0; }
這個接口里面最關鍵的是調用了 inotify_main 這個函數。如果看這段代碼比較費力的話,建議先弄清楚linux 下的fork機制,搞清楚 孤兒進程 僵尸進程這些如何產生的情況。
下面看 inotify_main 這個函數
void inotify_main(char *path,char *url) { struct pollfd poll_list[2]; poll_list[0].fd = inotify_init(); poll_list[0].events = POLLIN; int wd = inotify_add_watch(poll_list[0].fd, path, IN_DELETE | IN_CREATE); if(wd < 0) { fprintf(stderr, "could not add watch for %s, %s\n", path, strerror(errno)); return ; } int retval; while(1) { retval = poll(poll_list,(unsigned long)1,-1); /* retval 總是大于0或為-1,因為我們在阻塞中工作 */ LOGI("retval = %d\n",retval); if(retval < 0) { fprintf(stderr,"poll錯誤: %s/n",strerror(errno)); return; } if((poll_list[0].revents & POLLIN) == POLLIN) { LOGI("poll_list[0].revents&POLLIN\n"); inotify_handle(poll_list[0].fd,url); } } inotify_rm_watch(poll_list[0].fd,wd); }
這個函數,這里面用到了 inotify_init inotify_add_watch inotify_rm_watch 這幾個linux接口,這幾個接口主要的作用就是監聽指定的目錄,其配合poll函數,能夠監聽目錄下的任何改動,當要監聽的目錄有任何改動的時候,會觸發poll函數的 POLLIN
有可讀數據到來事件。
在本應用中,監聽的是 /data/data/com.example.ubuntuforandroid/files/ 這個目錄,因為在卸載的時候卸載程序會刪除監聽目錄的,而fork出來的守護進程當發現自身應用的目錄被卸載程序刪除了也就是卸載了,這個時候調用 inotify_handle
這個函數,然后調用 am命令啟動瀏覽器,調用自己需要調用界面。
當然,在調用am指令以后,記得自身守護進程的使命也完成了,需要exit退出一下。
inotify接口的用處很多,擴展一下,也可以用于守護進程,比如A進程和B進程是共生共死的,這里有一種實現的方式就是 A進程用inotify 監聽 /proc/B進程id目錄,當B進程結束的時候,A進程就能知道B進程不在了,從而結束自己。
上文描述的就是android監聽應用是否被卸載的方法,具體使用情況還需要大家自己動手實驗使用過才能領會。如果想了解更多相關內容,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。