Android APP監聽自己被解除安裝以及解除安裝後的邏輯處理
兩個月前發了兩篇有關監聽自己是否被解除安裝和解除安裝反饋功能實現的部落格,第二版的地址如下:http://www.cnblogs.com/zealotrouge/p/3159772.html,感謝@whiletrue_童鞋發現了我的程式碼在4.2.2系統上無法實現解除安裝反饋,經過除錯,有了問題的解決方案,但是由於發完部落格後即處於閉關開發階段,沒時間打理部落格,所以解決方案遲遲沒有與大家見面,最近空閒下來,將解決思路及方案發出來給大家看看還有沒有問題。
除錯發現,監聽依然沒有問題,畢竟是Linux Kernel中的介面,Framework層再怎麼改也改不到那兒去,那麼問題出在哪呢?阻塞結束後,通過呼叫exec函式發出am命令調起瀏覽器訪問網頁,在API16(Android 4.1.x)的裝置上尚可正常訪問網頁,而API17(Android 4.2.x)的裝置上連瀏覽器也不能調起。
通過分析log,發現了一條線索,如下面的log的所示:
W/ActivityManager( 387): Permission Denial: startActivity asks to run as user -2 but is calling from user 0; this requires android.permission.INTERACT_ACROSS_USERS_FULL
log中直接給出提示,需要加一個許可權INTERACT_ACROSS_USERS_FULL,這個許可權時API17新引入的,目的在於允許不同使用者的應用之間可以產生互動。可是加上去之後發現,還不是無法調起瀏覽器,而且log依然提示需要許可權INTERACT_ACROSS_USERS_FULL,很是奇怪,於是繼續分析。
首先說明一下Linux中的pid和uid,以及android擴充套件的userSerialNumber。pid是Process的標識,用於系統對程序的控制,從API層面看就是用於Process.killProcess()和Process.sendSignal();uid在Linux系統中是用來標識使用者的,而在android將uid視為app的標識id,用於"sandbox"安全模型,即用於app許可權控制;而對於API17引入的多使用者支援(目前只支援平板),uid已經被佔用,只好新引入userSerialNumber來標識使用者。
回到剛才的問題,log中告知startActivity時執行使用者標識為-2,而呼叫卻是由使用者標識0發起,導致拒絕執行。用這句話搜尋,發現在Google開發者網站中有相關的issue,連結如下:
解決方案:增加處理分支,若API>=17,將userSerialNumber傳遞給C端程序,然後在am命令中帶上引數--user userSerialNumber即可。
Java端程式碼如下:
1 package main.activity; 2 3 import java.lang.reflect.InvocationTargetException; 4 import java.lang.reflect.Method; 5 6 import pym.test.uninstalledobserver.R; 7 import android.app.Activity; 8 import android.os.Build; 9 import android.os.Bundle; 10 import android.util.Log; 11 12 /** 13 * @author pengyiming 14 * @note 監聽此應用是否被解除安裝,若被解除安裝則彈出解除安裝反饋 15 * @note 由於API17加入多使用者支援,原有命令在4.2及更高版本上執行時缺少userSerial引數,特此修改 16 * 17 */ 18 19 public class UninstalledObserverActivity extends Activity 20 { 21 /* 資料段begin */ 22 private static final String TAG = "UninstalledObserverActivity"; 23 24 // 監聽程序pid 25 private int mObserverProcessPid = -1; 26 /* 資料段end */ 27 28 /* static */ 29 // 初始化監聽程序 30 private native int init(String userSerial); 31 static 32 { 33 Log.d(TAG, "load lib --> uninstalled_observer"); 34 System.loadLibrary("uninstalled_observer"); 35 } 36 /* static */ 37 38 /* 函式段begin */ 39 @Override 40 public void onCreate(Bundle savedInstanceState) 41 { 42 super.onCreate(savedInstanceState); 43 44 setContentView(R.layout.uninstalled_observer_layout); 45 46 // API level小於17,不需要獲取userSerialNumber 47 if (Build.VERSION.SDK_INT < 17) 48 { 49 mObserverProcessPid = init(null); 50 } 51 // 否則,需要獲取userSerialNumber 52 else 53 { 54 mObserverProcessPid = init(getUserSerial()); 55 } 56 } 57 58 @Override 59 protected void onDestroy() 60 { 61 super.onDestroy(); 62 63 // 示例程式碼,用於結束監聽程序 64 // if (mObserverProcessPid > 0) 65 // { 66 // android.os.Process.killProcess(mObserverProcessPid); 67 // } 68 } 69 70 // 由於targetSdkVersion低於17,只能通過反射獲取 71 private String getUserSerial() 72 { 73 Object userManager = getSystemService("user"); 74 if (userManager == null) 75 { 76 Log.e(TAG, "userManager not exsit !!!"); 77 return null; 78 } 79 80 try 81 { 82 Method myUserHandleMethod = android.os.Process.class.getMethod("myUserHandle", (Class<?>[]) null); 83 Object myUserHandle = myUserHandleMethod.invoke(android.os.Process.class, (Object[]) null); 84 85 Method getSerialNumberForUser = userManager.getClass().getMethod("getSerialNumberForUser", myUserHandle.getClass()); 86 long userSerial = (Long) getSerialNumberForUser.invoke(userManager, myUserHandle); 87 return String.valueOf(userSerial); 88 } 89 catch (NoSuchMethodException e) 90 { 91 Log.e(TAG, "", e); 92 } 93 catch (IllegalArgumentException e) 94 { 95 Log.e(TAG, "", e); 96 } 97 catch (IllegalAccessException e) 98 { 99 Log.e(TAG, "", e); 100 } 101 catch (InvocationTargetException e) 102 { 103 Log.e(TAG, "", e); 104 } 105 106 return null; 107 } 108 /* 函式段end */ 109 }
核心——native方法標頭檔案:
1 /* 標頭檔案begin */ 2 #include <jni.h> 3 #include <stdlib.h> 4 #include <stdio.h> 5 #include <string.h> 6 #include <unistd.h> 7 #include <fcntl.h> 8 #include <sys/inotify.h> 9 #include <sys/stat.h> 10 11 #include <android/log.h> 12 /* 標頭檔案end */ 13 14 /* 巨集定義begin */ 15 //清0巨集 16 #define MEM_ZERO(pDest, destSize) memset(pDest, 0, destSize) 17 18 //LOG巨集定義 19 #define LOG_INFO(tag, msg) __android_log_write(ANDROID_LOG_INFO, tag, msg) 20 #define LOG_DEBUG(tag, msg) __android_log_write(ANDROID_LOG_DEBUG, tag, msg) 21 #define LOG_WARN(tag, msg) __android_log_write(ANDROID_LOG_WARN, tag, msg) 22 #define LOG_ERROR(tag, msg) __android_log_write(ANDROID_LOG_ERROR, tag, msg) 23 /* 巨集定義end */ 24 25 #ifndef _Included_main_activity_UninstalledObserverActivity 26 #define _Included_main_activity_UninstalledObserverActivity 27 #ifdef __cplusplus 28 extern "C" { 29 #endif 30 31 #undef main_activity_UninstalledObserverActivity_MODE_PRIVATE 32 #define main_activity_UninstalledObserverActivity_MODE_PRIVATE 0L 33 #undef main_activity_UninstalledObserverActivity_MODE_WORLD_READABLE 34 #define main_activity_UninstalledObserverActivity_MODE_WORLD_READABLE 1L 35 #undef main_activity_UninstalledObserverActivity_MODE_WORLD_WRITEABLE 36 #define main_activity_UninstalledObserverActivity_MODE_WORLD_WRITEABLE 2L 37 #undef main_activity_UninstalledObserverActivity_MODE_APPEND 38 #define main_activity_UninstalledObserverActivity_MODE_APPEND 32768L 39 #undef main_activity_UninstalledObserverActivity_MODE_MULTI_PROCESS 40 #define main_activity_UninstalledObserverActivity_MODE_MULTI_PROCESS 4L 41 #undef main_activity_UninstalledObserverActivity_BIND_AUTO_CREATE 42 #define main_activity_UninstalledObserverActivity_BIND_AUTO_CREATE 1L 43 #undef main_activity_UninstalledObserverActivity_BIND_DEBUG_UNBIND 44 #define main_activity_UninstalledObserverActivity_BIND_DEBUG_UNBIND 2L 45 #undef main_activity_UninstalledObserverActivity_BIND_NOT_FOREGROUND 46 #define main_activity_UninstalledObserverActivity_BIND_NOT_FOREGROUND 4L 47 #undef main_activity_UninstalledObserverActivity_BIND_ABOVE_CLIENT 48 #define main_activity_UninstalledObserverActivity_BIND_ABOVE_CLIENT 8L 49 #undef main_activity_UninstalledObserverActivity_BIND_ALLOW_OOM_MANAGEMENT 50 #define main_activity_UninstalledObserverActivity_BIND_ALLOW_OOM_MANAGEMENT 16L 51 #undef main_activity_UninstalledObserverActivity_BIND_WAIVE_PRIORITY 52 #define main_activity_UninstalledObserverActivity_BIND_WAIVE_PRIORITY 32L 53 #undef main_activity_UninstalledObserverActivity_BIND_IMPORTANT 54 #define main_activity_UninstalledObserverActivity_BIND_IMPORTANT 64L 55 #undef main_activity_UninstalledObserverActivity_BIND_ADJUST_WITH_ACTIVITY 56 #define main_activity_UninstalledObserverActivity_BIND_ADJUST_WITH_ACTIVITY 128L 57 #undef main_activity_UninstalledObserverActivity_CONTEXT_INCLUDE_CODE 58 #define main_activity_UninstalledObserverActivity_CONTEXT_INCLUDE_CODE 1L 59 #undef main_activity_UninstalledObserverActivity_CONTEXT_IGNORE_SECURITY 60 #define main_activity_UninstalledObserverActivity_CONTEXT_IGNORE_SECURITY 2L 61 #undef main_activity_UninstalledObserverActivity_CONTEXT_RESTRICTED 62 #define main_activity_UninstalledObserverActivity_CONTEXT_RESTRICTED 4L 63 #undef main_activity_UninstalledObserverActivity_RESULT_CANCELED 64 #define main_activity_UninstalledObserverActivity_RESULT_CANCELED 0L 65 #undef main_activity_UninstalledObserverActivity_RESULT_OK 66 #define main_activity_UninstalledObserverActivity_RESULT_OK -1L 67 #undef main_activity_UninstalledObserverActivity_RESULT_FIRST_USER 68 #define main_activity_UninstalledObserverActivity_RESULT_FIRST_USER 1L 69 #undef main_activity_UninstalledObserverActivity_DEFAULT_KEYS_DISABLE 70 #define main_activity_UninstalledObserverActivity_DEFAULT_KEYS_DISABLE 0L 71 #undef main_activity_UninstalledObserverActivity_DEFAULT_KEYS_DIALER 72 #define main_activity_UninstalledObserverActivity_DEFAULT_KEYS_DIALER 1L 73 #undef main_activity_UninstalledObserverActivity_DEFAULT_KEYS_SHORTCUT 74 #define main_activity_UninstalledObserverActivity_DEFAULT_KEYS_SHORTCUT 2L 75 #undef main_activity_UninstalledObserverActivity_DEFAULT_KEYS_SEARCH_LOCAL 76 #define main_activity_UninstalledObserverActivity_DEFAULT_KEYS_SEARCH_LOCAL 3L 77 #undef main_activity_UninstalledObserverActivity_DEFAULT_KEYS_SEARCH_GLOBAL 78 #define main_activity_UninstalledObserverActivity_DEFAULT_KEYS_SEARCH_GLOBAL 4L 79 80 /* 81 * Class: main_activity_UninstalledObserverActivity 82 * Method: init 83 * Signature: (Ljava/lang/String;)V 84 */ 85 JNIEXPORT int JNICALL Java_main_activity_UninstalledObserverActivity_init(JNIEnv *, jobject, jstring); 86 87 #ifdef __cplusplus 88 } 89 #endif 90 #endif
核心——native方法實現:
1 /* 標頭檔案begin */ 2 #include "main_activity_UninstalledObserverActivity.h" 3 /* 標頭檔案end */ 4 5 #ifdef __cplusplus 6 extern "C" 7 { 8 #endif 9 10 /* 內全域性變數begin */ 11 static char TAG[] = "UninstalledObserverActivity.init"; 12 static jboolean isCopy = JNI_TRUE; 13 14 static const char APP_DIR[] = "/data/data/pym.test.uninstalledobserver"; 15 static const char APP_FILES_DIR[] = "/data/data/pym.test.uninstalledobserver/files"; 16 static const char APP_OBSERVED_FILE[] = "/data/data/pym.test.uninstalledobserver/files/observedFile"; 17 static const char APP_LOCK_FILE[] = "/data/data/pym.test.uninstalledobserver/files/lockFile"; 18 /* 內全域性變數 */ 19 20 /* 21 * Class: main_activity_UninstalledObserverActivity 22 * Method: init 23 * Signature: ()V 24 * return: 子程序pid 25 */ 26 JNIEXPORT int JNICALL Java_main_activity_UninstalledObserverActivity_init(JNIEnv *env, jobject obj, jstring userSerial) 27 { 28 jstring tag = (*env)->NewStringUTF(env, TAG); 29 30 LOG_DEBUG((*env)->GetStringUTFChars(env, tag, &isCopy) 31 , (*env)->GetStringUTFChars(env, (*env)->NewStringUTF(env, "init observer"), &isCopy)); 32 33 // fork子程序,以執行輪詢任務 34 pid_t pid = fork(); 35 if (pid < 0) 36 { 37 LOG_ERROR((*env)->GetStringUTFChars(env, tag, &isCopy) 38 , (*env)->GetStringUTFChars(env, (*env)->NewStringUTF(env, "fork failed !!!"), &isCopy)); 39 40 exit(1); 41 } 42相關推薦
Android APP監聽自己被解除安裝以及解除安裝後的邏輯處理
兩個月前發了兩篇有關監聽自己是否被解除安裝和解除安裝反饋功能實現的部落格,第二版的地址如下:http://www.cnblogs.com/zealotrouge/p/3159772.html,感謝@whiletrue_童鞋發現了我的程式碼在4.2.2系統上無法實現解除安裝反饋,經過除錯,有了問題的解決方案
Android App監聽軟鍵盤按鍵的三種方式
前言: 我們在android手機上面有時候會遇到監聽手機軟鍵盤按鍵的時候,例如:我們在瀏覽器輸入url完畢後可以點選軟鍵盤右下角的“GO”按鍵載入url頁面;在點選搜尋框的時候,點選右下角的search符號鍵可以進行搜尋;或者在全部資料輸入完畢後,點選右下角的"done"
Android App監聽軟鍵盤按鍵的三種方式與改變軟鍵盤右下角確定鍵樣式
actionNone : 回車鍵,按下後游標到下一行actionGo : Go,actionSearch : 放大鏡actionSend : SendactionNext : Nextacti
Android應用如何監聽自己是否被解除安裝及解除安裝反饋功能的實現(第二版)
原文地址為: Android應用如何監聽自己是否被解除安裝及解除安裝反饋功能的實現(第二版) 昨天發了一篇有關監聽自己是否被解除安裝和解除安裝反饋功能實現的部落格,地址如下:http://www.cnblogs.com/zealotrouge/p/3157126.html,發出去後收
Android應用如何監聽自己是否被解除安裝及解除安裝反饋功能的實現
一個應用被使用者解除安裝肯定是有理由的,而開發者卻未必能得知這一重要的理由,畢竟使用者很少會主動反饋建議,多半就是用得不爽就卸,如果能在被解除安裝後獲取到使用者的一些反饋,那對開發者進一步改進應用是非常有利的。目前據我所知,國內的Android應用中實現這一功能的只有360手機衛士、360平板衛士,那麼如
Android應用如何監聽自己是否被解除安裝及解除安裝反饋功能的實現(第三版)
1 /* 標頭檔案begin */ 2 #include "main_activity_UninstalledObserverActivity.h" 3 /* 標頭檔案end */ 4 5 #ifdef __cplusplus 6 extern "C" 7 { 8 #en
android 如何監聽自身應用被解除安裝
前段時間有個同事問我android應用在解除安裝以後,如何能夠通知一下伺服器,讓使用者填寫一下解除安裝的原因,以求為將來的應用修改積累資料。當時他是有段原始碼的,但是有點小問題,我只是幫他定位一下了程式碼的問題,具體細節沒有研究。又加上最近工作比較繁忙,所以就放下來了,今天稍微有點空,就自己
Android 如何監聽App的輸入了那些內容
監聽手機上任意一個App都輸入了哪類內容,比如像QQ聊天等。其實Android給我們提供了一個輔助類AccessibilityService,這個類能幹很多事情,模擬點選(比如自動搶紅包例項,感謝CSDN_SXL:http://blog.csdn.net/csdn_sxl/article
android 通過監聽edittext實現button的點擊事件
監聽 edittext 如果你沒有接第三方的輸入設備,那麽點擊按鈕只需找到你的button然後:button.performClick();就可以了那麽如果你用到第三方輸入法,有些時候監聽就沒有這麽好使了:以下場景為:外接輸入服務,直接給我丟一串字符,我拿到字符後執行按鈕事件代碼如下: editTe
android 真正監聽軟鍵盤得彈起和收
在開發中我們有時需要監聽鍵盤得變化情況 Softkeyboardlistener.class 工具類 public class Softkeyboardlistener { private View rootView;//activity的根
Android如何監聽藍芽耳機的按鍵事件
分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!  
Android 手勢監聽demo
package com.shengfang.demo.testdemo; import android.content.Context; import android.view.GestureDetector; import android.view.MotionEvent; import and
Android中監聽ScrollView滑動停止和滑動到底部
分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!  
如何實現android中監聽來電並生成懸浮窗體提示
分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!  
Android的監聽事件
案例一 事件監聽(三種寫法) 1.1 標籤上直接繫結監聽方法 public void xxx(View view) //第一種 public void xxx(View view) 1.2 建立監聽器物件,元件再繫結監聽器物件 1.2.1 匿名內部類 1.2
Android實時監聽軟鍵盤顯示或隱藏
搞了一個實時監聽軟鍵盤顯示或隱藏,當軟鍵盤隱藏了,做邏輯;軟鍵盤顯示出來了,做邏輯; 直接上程式碼了,下面是我寫的工具類,名字為 SoftKeyBoardListener : import android.app.Activity; import android.graphics.
Android動態監聽網路變化
廣播接收器可以自由地對自己感興趣的廣播進行註冊,這樣當有相應的廣播接收時,廣播接收器就能收到該廣播,並在內部處理其相應的邏輯。廣播註冊的方法有兩種,在程式碼中註冊與在AndridManifest.xml中註冊,前者稱為動態註冊,後者為靜態註冊,接下來我們就說說關於動態註冊
Android之監聽View的兩個指頭是放大和縮小
我們有時需要對view進行手勢監聽,通過兩個手指開始距離和結束距離,來判斷放大縮小,下面是實現程式碼,所有View通用。 private double nLenStart = 0;//監聽 WebView所用手勢 @Override public boolean on
android 實現監聽簡訊接收並將當前位置傳送出去
1、獲取定位地址,這裡使用高德定位,從官網下載定位的jar包AMap_Location_V3.50_20170731.jar包然後在build.gradlecompile files('libs/AMap_Location_V3.5.0_20170731.jar')然後在許
xamarin android如何監聽單擊事件
在xamarin android單擊事件是最基礎的事情,看過菜鳥上的android教程時,java寫的都是監聽事件,為一個按鈕,單選按鈕、多選按鈕的單擊事件有三種,前面兩種用的非常普遍,也很簡易,我這裡主要就是寫一下xamarin android中的監聽事件。 1.使用委託