方法一.开机自启动,注册广播的方式,这种方式比较慢,一般需要很久
原理:监听接收 android.intent.action.BOOT_COMPLETED 广播
添加开机广播接收器
public class BootReceiver extends BroadcastReceiver{
public void onReceive(Context context,Intent intent){
Intent mIntent = new Intent(context,MainActivity.class);
startActivity(mIntent);
}
}
在 AndroidManifest.xml 文件中添加权限
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
在 AndroidManifest.xml 文件中注册开机广播接收器
<receiver android:name="BootReceiver" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</receiver>
方法二.在开机向导之后开机自启动
原理:在开机向导结束之后会修改数据库将 Settings.Secure.USER_SETUP_COMPLETE 的值修改为 1,Google开机向导和OOBE开机向导都会修改这个值,具体代码如下:
//OOBE
mediatek/packages/apps/OOBE/src/com/mediatek/oobe/basic/MainActivity.java
private void finishOOBE() {
...
Settings.Secure.putInt(getContentResolver(), Settings.Secure.USER_SETUP_COMPLETE, 1);
...
}
//SetupWizard
com/google/android/setupwizard/BaseActivity.java
protected void onSetupComplete(boolean paramBoolean){
...
Settings.Secure.putInt(getContentResolver(), "user_setup_complete", 1);
...
}
//在SystemUI中已经有了对 Settings.Secure.USER_SETUP_COMPLETE 的监听
在 frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
中有
private void resetUserSetupObserver() {
...
mContext.getContentResolver().registerContentObserver(Settings.Secure.getUriFor(Settings.Secure.USER_SETUP_COMPLETE), true, mUserSetupObserver, mCurrentUserId);
...
}
private ContentObserver mUserSetupObserver = new ContentObserver(new Handler()) {
@Override
public void onChange(boolean selfChange) {
final boolean userSetup = 0 != Settings.Secure.getIntForUser(mContext.getContentResolver(), Settings.Secure.USER_SETUP_COMPLETE, 0 , mCurrentUserId);
if (mSettingsButton != null && mHasFlipSettings) {
mSettingsButton.setVisibility(userSetup ? View.VISIBLE : View.INVISIBLE);
}
if (mSettingsPanel != null) {
mSettingsPanel.setEnabled(userSetup);
}
if (userSetup != mUserSetup) {
mUserSetup = userSetup;
if (!mUserSetup && mStatusBarView != null){
animateCollapseQuickSettings();
}
}
}
};
初步修改后的代码如下
boolean isFirstBoot = Settings.Secure.getInt(mContext.getContentResolver(), "isFirstBoot", 0) == 0; //设置标志位,只有在恢复出厂设置的时候启动一次
if(userSetup && isFirstBoot){
try{
Intent intent = new Intent();
intent.setComponent(new android.content.ComponentName("za.co.axon.mdas.roid","za.co.axon.mdas.roid.Splash"));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
mContext.startActivity(intent);
Settings.Secure.putInt(mContext.getContentResolver(), "isFirstBoot", 1); //将标志为设置为1,表示启动成功
} catch(Exception e) {
e.printStackTrace(); //这里加try,catch防止内置的APK face2face 丢失
}
}
但经过强度测试之后发现了一个小问题,概率性的出现应用程序不启动的现象?
从Log中可以看出:
正常启动的Log:
01-01 00:01:19.656195 719 1095 I am_create_activity: [0,1113075664,4,za.co.axon.mdas.roid/.Splash,NULL,NULL,NULL,272629760
01-01 00:01:19.656700 719 1095 I wm_task_created: [4,1
01-01 00:01:19.656803 719 1095 I wm_task_moved: [4,1,2
01-01 00:01:19.700131 719 1157 I am_proc_died: [0,1169,com.google.android.setupwizard
01-01 00:01:19.705203 719 1157 I am_destroy_service: [0,1107535152,1254
01-01 00:01:19.732961 719 1157 I am_finish_activity: [0,1110412608,2,com.google.android.setupwizard/.NoAccountTosActivity,proc died without state saved
01-01 00:01:19.847742 719 1157 I am_finish_activity: [0,1112688672,2,com.google.android.setupwizard/.NoAccountTosActivity,proc died without state saved
01-01 00:01:19.940255 719 1157 I am_proc_start: [0,2045,10039,za.co.axon.mdas.roid,activity,za.co.axon.mdas.roid/.Splash
01-01 00:01:20.019586 719 730 I am_proc_bound: [0,2045,za.co.axon.mdas.roid
01-01 00:01:20.253625 719 730 I am_restart_activity: [0,1113075664,4,za.co.axon.mdas.roid/.Splash
01-01 00:01:20.315298 719 742 I notification_enqueue: [com.mediatek.mtklogger,2130837522,NULL,0,Notification(pri=0 contentView=com.mediatek.mtklogger/0x109006b vibrate=null sound=null defaults=0x0 flags=0x60 kind=[null])
01-01 00:01:20.316353 719 719 I notification_cancel: [com.mediatek.mtklogger,2130837522,NULL,0,0,0
01-01 00:01:20.532800 2045 2045 I am_on_resume_called: [0,za.co.axon.mdas.roid.Splash
01-01 00:01:20.571890 719 1157 I wm_task_moved: [4,1,2
01-01 00:01:20.572002 719 1157 I am_create_activity: [0,1110419464,4,za.co.axon.mdas.roid/.About,NULL,NULL,NULL,0
01-01 00:01:20.582907 719 1157 I am_pause_activity: [0,1113075664,za.co.axon.mdas.roid/.Splash
01-01 00:01:20.593922 719 1014 I am_finish_activity: [0,1113075664,4,za.co.axon.mdas.roid/.Splash,app-request
01-01 00:01:20.636227 2045 2045 I am_on_paused_called: [0,za.co.axon.mdas.roid.Splash
01-01 00:01:20.667373 719 2043 I am_restart_activity: [0,1110419464,4,za.co.axon.mdas.roid/.About
01-01 00:01:20.723902 719 1157 I am_create_service: [0,1114379064,.SIMProcessorService,10003,1781
01-01 00:01:20.785342 719 1563 I am_create_service: [0,1114110688,.DownloadService,10005,1489
01-01 00:01:20.847981 719 735 I notification_cancel_all: [com.android.providers.downloads,0,0,64
01-01 00:01:20.915881 2045 2045 I am_on_resume_called: [0,za.co.axon.mdas.roid.About
异常不启动的Log:
01-01 00:01:12.916516 720 1170 I am_create_activity: [0,1113616608,3,za.co.axon.mdas.roid/.Splash,NULL,NULL,NULL,272629760
01-01 00:01:12.916972 720 1170 I wm_task_created: [3,1
01-01 00:01:12.917066 720 1170 I wm_task_moved: [3,1,1
01-01 00:01:12.917903 720 1170 I am_pause_activity: [0,1107807432,com.google.android.setupwizard/.NoAccountTosActivity
01-01 00:01:12.944667 720 1147 I am_create_task: [0,4
01-01 00:01:12.944957 720 1147 I am_create_activity: [0,1111200792,4,com.android.launcher3/.Launcher,android.intent.action.MAIN,NULL,NULL,270532608
01-01 00:01:12.945345 720 1147 I wm_task_created: [4,0
01-01 00:01:12.945431 720 1147 I wm_task_moved: [4,1,2
01-01 00:01:13.121927 720 1122 I am_create_service: [0,1109984720,.SIMProcessorService,10003,1652
01-01 00:01:13.201850 720 732 I am_proc_died: [0,1188,com.google.android.setupwizard
01-01 00:01:13.203463 720 732 I am_destroy_service: [0,1110166664,1302
01-01 00:01:13.210043 720 732 I am_finish_activity: [0,1107807432,2,com.google.android.setupwizard/.NoAccountTosActivity,proc died without state saved
01-01 00:01:13.242921 720 732 I am_finish_activity: [0,1108071280,2,com.google.android.setupwizard/.DateTimeSetupActivity,proc died without state saved
01-01 00:01:13.263721 157 157 I sf_frame_dur: [com.google.android.setupwizard/com.google.android.setupwizard.NoAccountTosActivity,2,3,0,0,2,0,0
01-01 00:01:13.329596 720 732 I am_proc_start: [0,1924,10012,com.android.launcher3,activity,com.android.launcher3/.Launcher
01-01 00:01:13.339900 720 1090 I am_create_service: [0,1113635320,.DownloadService,10005,1208
01-01 00:01:13.420749 720 736 I am_proc_bound: [0,1924,com.android.launcher3
01-01 00:01:13.481537 720 968 I notification_cancel_all: [com.android.providers.downloads,0,0,64
01-01 00:01:14.885420 720 736 I am_restart_activity: [0,1111200792,4,com.android.launcher3/.Launcher
01-01 00:01:14.903973 720 1090 I am_destroy_service: [0,1113635320,1208
01-01 00:01:14.912448 720 743 I am_finish_activity: [0,1113616608,3,za.co.axon.mdas.roid/.Splash,no-history //za.co.axon.mdas.roid.Splash 被莫名其妙地 finish 掉了
01-01 00:01:14.918549 720 743 I am_destroy_activity: [0,1113616608,3,za.co.axon.mdas.roid/.Splash,finish-imm
根据这种情况,再次做了修改
private ContentObserver mUserSetupObserver = new ContentObserver(new Handler()) {
@Override
public void onChange(boolean selfChange) {
...
if (userSetup != mUserSetup) {
mUserSetup = userSetup;
boolean isFirstBoot = Settings.Secure.getInt(mContext.getContentResolver(), "isFirstBoot", 0) == 0;
if(userSetup && isFirstBoot){
try{
Intent intent = new Intent();
intent.setComponent(new android.content.ComponentName("za.co.axon.mdas.roid","za.co.axon.mdas.roid.Splash"));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
mContext.startActivity(intent);
Settings.Secure.putInt(mContext.getContentResolver(), "isFirstBoot", 1);
new Thread(new Runnable(){ //在这个地方启动一个线程,再次启动这个应用
public void run(){
try{
while(!isStartSuccess){
Thread.sleep(2000);
handler.sendEmptyMessage(1);
}
}catch(Exception e){
e.printStackTrace();
}
}
}).start();
}catch(Exception e){
e.printStackTrace();
}
}
...
}
}
};
private boolean isStartSuccess = false;
Handler handler = new Handler(){
public void handleMessage(Message msg){
switch(msg.what){
case 1:
String topActivityName = getTopActivityName(mContext);
if(topActivityName != null && topActivityName.contains("za.co.axon.mdas.roid")){
isStartSuccess = true;
} else {
Intent intent = new Intent();
intent.setComponent(new android.content.ComponentName("za.co.axon.mdas.roid","za.co.axon.mdas.roid.Splash"));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(intent);
}
break;
default:
break;
}
}
};
/**获取栈顶Activity的名称*/
private String getTopActivityName(Context context) {
ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<android.app.ActivityManager.RunningTaskInfo> runningTaskInfos = activityManager.getRunningTasks(1);
if (runningTaskInfos != null) {
return (runningTaskInfos.get(0).topActivity).toString();
} else {
return null;
}
}