如何安全退出已調用多個Activity的Application?


 

轉載自: 

如何安全退出已調用多個Activity的Application?

使用ActivityManager的forceStopPackage方法結束進程

 

對於單一Activity的應用來說,退出很簡單,直接finish()即可。
當然,也可以用killProcess()和System.exit()這樣的方法。

但是,對於多Activity的應用來說,在打開多個Activity后,如果想在最后打開的Activity直接退出,上邊的方法都是沒有用的,因為上邊的方法都是結束一個Activity而已。
當然,網上也有人說可以。
就好像有人問,在應用里如何捕獲Home鍵,有人就會說用keyCode比較KEYCODE_HOME即可,而事實上如果不修改framework,根本不可能做到這一點一樣。
所以,最好還是自己親自試一下。

那么,有沒有辦法直接退出整個應用呢?

現提供幾個方法,供參考:

1、拋異常強制退出:
該方法通過拋異常,使程序Force Close。
驗證可以,但是,需要解決的問題是,如何使程序結束掉,而不彈出Force Close的窗口。

2、記錄打開的Activity:
每打開一個Activity,就記錄下來。在需要退出時,關閉每一個Activity即可。

public class ActivityManagerApplication extends Application { private static Map<String,Activity> destoryMap = new HashMap<>(); private ActivityManagerApplication() { } /** * 添加到銷毀隊列 * * @param activity 要銷毀的activity */

    public static void addDestoryActivity(Activity activity,String activityName) { destoryMap.put(activityName,activity); } /** *銷毀指定Activity */
    public static void destoryActivity(String activityName) { Set<String> keySet=destoryMap.keySet(); for (String key:keySet){ destoryMap.get(key).finish(); } } }

 


3、發送特定廣播:
在需要結束應用時,發送一個特定的廣播,每個Activity收到廣播后,關閉即可。

4、遞歸退出
在打開新的Activity時使用startActivityForResult,然后自己加標志,在onActivityResult中處理,遞歸關閉。

除了第一個,都是想辦法把每一個Activity都結束掉,間接達到目的。
但是這樣做同樣不完美。你會發現,如果自己的應用程序對每一個Activity都設置了nosensor,在兩個Activity結束的間隙,sensor可能有效了。
但至少,我們的目的達到了,而且沒有影響用戶使用。

為了編程方便,最好定義一個Activity基類,處理這些共通問題。

 

5、在2.1之前,可以使用ActivityManager的restartPackage方法。

它可以直接結束整個應用。在使用時需要權限Android.permission.RESTART_PACKAGES。
注意不要被它的名字迷惑。

可是,在2.2,這個方法失效了。
在2.2添加了一個新的方法,killBackgroundProcesses(),需要權限 android.permission.KILL_BACKGROUND_PROCESSES。
可惜的是,它和2.2的restartPackage一樣,根本起不到應有的效果。

另外還有一個方法,就是系統自帶的應用程序管理里,強制結束程序的方法,forceStopPackage()。
它需要權限android.permission.FORCE_STOP_PACKAGES。
並且需要添加android:sharedUserId="android.uid.system"屬性
同樣可惜的是,該方法是非公開的,他只能運行在系統進程,第三方程序無法調用。
因為需要在Android.mk中添加LOCAL_CERTIFICATE := platform。
而Android.mk是用於在Android源碼下編譯程序用的。

從以上可以看出,在2.2,沒有辦法直接結束一個應用,而只能用自己的辦法間接辦到。

 

使用forceStopPackage的方法如下

做一個應用,需要強制關閉進程。

可以使用ActivityManager的killBackgroundProcesses方法,需要權限Android.permission.KILL_BACKGROUND_PROCESSES。但使用此方法殺死進程后,進程會重啟。源碼中解釋如下:

Have the system immediately kill all background processes associated with the given package.  This is the same as the kernel killing those processes to reclaim memory; the system will take care of restarting these processes in the future as needed.

 

為了強制關閉進程,希望使用ActivityManager的另外一個方法,forceStopPackage。源碼中解釋如下:

Have the system perform a force stop of everything associated with the given application package.  All processes that share its uid will be killed, all services it has running stopped, all activities removed, etc.  In addition, a {@link Intent#ACTION_PACKAGE_RESTARTED} broadcast will be sent, so that any of its registered alarms can be stopped, notifications removed, etc.

使用這個方法有兩點需要注意:

- 此方法是@hide的方法:

解決方案是使用java的反射機制完成調用,代碼如下:

 

[java] view plain copy
 
 print?
  1. ActivityManager mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);  
  2. Method method = Class.forName("android.app.ActivityManager").getMethod("forceStopPackage", String.class);  
  3. method.invoke(mActivityManager, packageName);  //packageName是需要強制停止的應用程序包名  

 

- 此方法需要權限:android.permission.FORCE_STOP_PACKAGES

下面着手分析這個權限。

這個權限在frameworks/base/core/res/AndroidManifest.xml文件中聲明,如下:

 

[java] view plain copy
 
 print?
  1.   
[html] view plain copy
 
 print?
  1. <permission android:name="android.permission.FORCE_STOP_PACKAGES"  
  2.  android:permissionGroup="android.permission-group.SYSTEM_TOOLS"  
  3.  android:protectionLevel="signature"  
  4.  android:label="@string/permlab_forceStopPackages"  
  5.  android:description="@string/permdesc_forceStopPackages"/>  

注意protectionLevel屬性值未signature。看sdk文檔http://developer.android.com/guide/topics/manifest/permission-element.html#plevel中對這一屬性的解釋如下:

A permission that the system grants only if the requesting application is signed with the same certificate as the application that declared the permission. If the certificates match, the system automatically grants the permission without notifying the user or asking for the user's explicit approval.

意思是:app使用FORCE_STOP_PACKAGES權限,app必須和這個權限的聲明者的簽名保持一致!

FORCE_STOP_PACKAGES的聲明者是frameworks/base/core/res/,可以在frameworks/base/core/res/Android.mk中看到它的簽名信息:

 

[html] view plain copy
 
 print?
  1. LOCAL_NO_STANDARD_LIBRARIES := true  
  2. LOCAL_PACKAGE_NAME := framework-res  
  3. LOCAL_CERTIFICATE := platform  


即,簽名為platform. 

最終得到結論,app需要是platform簽名,才可以使用forceStopPackage方法!

網上有很多文章提及,需要在app的AndroidManifest.xml中添加android:sharedUserId="android.uid.system"一句話。看sdk(http://developer.android.com/guide/topics/manifest/manifest-element.html)對此的解釋:

android:sharedUserId
The name of a Linux user ID that will be shared with other applications. By default, Android assigns each application its own unique user ID. However, if this attribute is set to the same value for two or more applications, they will all share the same ID — provided that they are also signed by the same certificate. Application with the same user ID can access each other's data and, if desired, run in the same process.

意思是,兩個app使用了相同的user id,就可以互相訪問對方的數據。因此,app使用android.uid.system的user id,就可以訪問系統數據。注意背景為黃色的一句,這里依然需要兩個app有相同的簽名才行。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM