1. 程式人生 > >Android應用實現安裝後自啟動

Android應用實現安裝後自啟動

和網上大多數方法一樣,使用廣播手段:

ACTION_PACKAGE_ADDED 一個新應用包已經安裝在裝置上,資料包括包名(最新安裝的包程式不能接收到這個廣播
ACTION_PACKAGE_REPLACED 一個新版本的應用安裝到裝置,替換之前已經存在的版本
ACTION_PACKAGE_CHANGED 一個已存在的應用程式包已經改變,包括包名
ACTION_PACKAGE_REMOVED 一個已存在的應用程式包已經從裝置上移除,包括包名(正在被安裝的包程式不能接收到這個廣播
ACTION_PACKAGE_RESTARTED 使用者重新開始一個包,包的所有程序將被殺死,所有與其聯絡的執行時間狀態應該被移除,包括包名(重新開始包程式不能接收到這個廣播


ACTION_PACKAGE_DATA_CLEARED 使用者已經清除一個包的資料,包括包名(清除包程式不能接收到這個廣播

直接思路:註冊廣播接收以上需要的action來實現。

但是,在安卓3.1之後,有了以下機制:

force-stop in Manage Application of Settings makes App in a stopped state!

Here is what Google describes

What is Stopped State

Starting from Android 3.1, the system’s package manager keeps track of applications that are in a stopped state and provides a means of controlling their launch from background processes and other applications.

Note that an application’s stopped state is not the same as an Activity’s stopped state. The system manages those two stopped states separately.

Why Android Adds this

Note that the system adds FLAG_EXCLUDE_STOPPED_PACKAGES to all broadcast intents. It does this to prevent broadcasts from background services from inadvertently or unnecessarily launching components of stoppped applications. A background service or application can override this behavior by adding the FLAG_INCLUDE_STOPPED_PACKAGES flag to broadcast intents that should be allowed to activate stopped applications.

As the above references point out it will prevent broadcast intents delivering to stopped packages. Actually this control mechanism will ensure safety and save energy.


Android 3.1 APIs

翻譯:     在 系統設定 - 應用管理 中的“強制停止” 作用是讓app處於(stopped)停止狀態。 下面是google的官方描述:     什麼是停止狀態?         從Andriod3.1開始,系統包管理服務會一直追蹤處於停滯狀態的app,並提供了控制它們從後臺程序或其他應用程式啟動的方法。         注意:應用程式的停止狀態不同於activity(活動)的停止狀態。系統是分開來處理這兩類停止狀態的。 為什麼Android要新增這個功能?        注意:系統為所有用於傳送廣播的Intent預設添加了FLAG_EXCLUDE_STOPPED標誌。這樣做是為了阻止傳送自後臺service的廣播不小心啟動某個已停止應用的元件。一個後臺service服務或app應用程式可以 通過向廣播的Intent物件新增FLAG_INCLUDE_STOPPED_PACKAGES標誌,覆蓋重寫這個行為,使得該廣播可以啟用處於停止狀態的應用程式。 上述描述指出:系統預設會阻止停止狀態的app接收廣播。這個控制機制的目的是保證安全、節約電量。 所以,要實現安裝apk後自啟動,前提是

    1、觸發ACTION_PACKAGE_REPLACED 廣播(也就是apk覆蓋替換安裝才接收的到,初次安裝的廣播ACTION_PACKAGE_ADDED 不會被當前安裝包觸發,因為該app未執行過)

    2、在app專案中使用靜態註冊廣播(因為動態廣播是app執行後才可以接受到)

    3、app曾經執行過(即不處於stopped狀態)

在Android5.1真機上測試:

初次安裝的app不會觸發廣播。

覆蓋安裝未執行過的app,不會觸發廣播

安裝完執行app後,退出App(點選返回鍵、並從recent任務中移除,此時在設定-應用中檢視,app仍未處於stop狀態)。覆蓋安裝後,app成功自動執行。(可看做實現安裝後自啟動

此時退出App,並在設定-應用中把app進行【強制停止】。覆蓋安裝後,app沒有自動執行。(此時在設定-應用中檢視,app處於stop狀態)

     所以,只要在App執行時,直接覆蓋安裝apk,是可以用廣播接收器實現安裝完後自啟動的。   (至少在android 5.1上 ^,^)    

下面簡單介紹下程式碼:

(1)自定義廣播接收器:

public class MyReceiver extends BroadcastReceiver {

	@Override
	public void onReceive(Context context, Intent intent) {
		String action = intent.getAction();
		String localPkgName = context.getPackageName();//取得MyReceiver所在的App的包名
		Uri data = intent.getData();
		String installedPkgName = data.getSchemeSpecificPart();//取得安裝的Apk的包名,只在該app覆蓋安裝後自啟動
		if((action.equals(Intent.ACTION_PACKAGE_ADDED)
				|| action.equals(Intent.ACTION_PACKAGE_REPLACED)) && installedPkgName.equals(localPkgName)){
			Intent launchIntent = new Intent(context,MainActivity.class);
			launchIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
			context.startActivity(launchIntent);
		}
	}
}


(2)AndroidManifest.xml中靜態註冊廣播接收器

<application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.mydemo.MainActivity"
        	android:configChanges="orientation|keyboard"
            android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <receiver android:name="com.example.mydemo.MyReceiver">
            <intent-filter>
                <action android:name="android.intent.action.PACKAGE_ADDED" /> 
                <action android:name="android.intent.action.PACKAGE_REPLACED" />
                <action android:name="android.intent.action.PACKAGE_REMOVED" />
                <data android:scheme="package"/>
            </intent-filter>
        </receiver>
    </application>