最近做一个需求需要在Android版本8.1手机上启动一个3方服务.在SystemUI这类应用中启动3方应用,一定要在开机广播中启动.
客户提供了3应用,没有源码,apk形式,文档上提供的调用方式.
步骤很少:检查对应的service是否存在,如果存在就启动服务
public void startGupshupServiceIfNeeded() {
Intent implicitIntent = new Intent("xxxx");
Intent explicitIntent = convertImplicitIntentToExplicitIntent(implicitIntent);
if (explicitIntent != null) {
mContext.startForegroundService(explicitIntent);
}
}
//查找服务是否存在
public Intent convertImplicitIntentToExplicitIntent(Intent implicitIntent) {
PackageManager pm = mContext.getPackageManager();
List resolveInfoList = pm.queryIntentServices(implicitIntent, 0);
if (resolveInfoList == null || resolveInfoList.size() != 1) {//1
Log.v(TAG,"staring service failed");
return null;
}
ResolveInfo serviceInfo = resolveInfoList.get(0);
ComponentName component = new ComponentName(serviceInfo.serviceInfo.packageName,serviceInfo.serviceInfo.name);
Intent explicitIntent = new Intent(implicitIntent);
explicitIntent.setComponent(component);
return explicitIntent;
}
需要开机启动,但是客户给的这个应用本身没有监听开机广播,需要由一个开机启动的应用把它调起来.打算就在SystemUI里面启动,开始的时候在SystemUIApplication的onCreate里面调用startGupshupServiceIfNeeded,发现在查找这个service的时候为空(上面1处),打印"staring service failed",但是如果使用adb方式和测试应用就能够检查到.
adb shell am start-foreground-service包名/服务名
说明SystemUI刚启动的时候,PMS还没有准备好,导致 pm.queryIntentServices无法查到对应的Service,我们需要在系统完全启动之后启动这个服务器
SystemIU应用的各个模块都是通过SystemUI的子类管理的,SystemUI有一个onBootCompleted方法,他会在监听到开机广播的时候调用,而此时也是系统完全起来的时候.如果系统完全启动了,就不会有查找不到应用的问题.
private final Class>[] SERVICES = new Class[] {
Dependency.class,
NotificationChannels.class,
CommandQueue.CommandQueueStart.class,
KeyguardViewMediator.class,
Recents.class,
VolumeUI.class,
Divider.class,
SystemBars.class,
StorageNotification.class,
PowerUI.class,
RingtonePlayer.class,
KeyboardUI.class,
PipUI.class,
ShortcutKeyDispatcher.class,
VendorServices.class,
GarbageMonitor.Service.class,
LatencyTester.class,
GlobalActionsComponent.class,
RoundedCorners.class,
GupshupService.class,
};
GupshupService.class,这个新建的类,用于启动3方应用
SystemUIApplication.java
--- base/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java ---
public class SystemUIApplication extends Application implements SysUiServiceProvider {
/**
* The classes of the stuff to start.
*/
private final Class>[] SERVICES = new Class[] {
Dependency.class,
NotificationChannels.class,
....
RoundedCorners.class,
+ GupshupService.class,
};
GupshupService继承SystemUI
package com.android.systemui;
import java.util.ArrayList;
import java.util.List;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.Context;
import android.content.Intent;
import android.content.ComponentName;
public class GupshupService extends SystemUI {
@Override
public void start() {
}
@Override
protected void onBootCompleted() {
startGupshupServiceIfNeeded();
}
/* start gupshup if need @{ */
public void startGupshupServiceIfNeeded() {
Intent implicitIntent = new Intent("xxxxxx");
Intent explicitIntent = convertImplicitIntentToExplicitIntent(implicitIntent);
if (explicitIntent != null) {
mContext.startForegroundService(explicitIntent);
}
}
public Intent convertImplicitIntentToExplicitIntent(Intent implicitIntent) {
PackageManager pm = mContext.getPackageManager();
List resolveInfoList = pm.queryIntentServices(implicitIntent, 0);
if (resolveInfoList == null || resolveInfoList.size() != 1) {
return null;
}
ResolveInfo serviceInfo = resolveInfoList.get(0);
ComponentName component = new ComponentName(serviceInfo.serviceInfo.packageName,serviceInfo.serviceInfo.name);
Intent explicitIntent = new Intent(implicitIntent);
explicitIntent.setComponent(component);
return explicitIntent;
}
}
这样启动3方应用就像其他SystemUI模块一样启动了.SystemUI是在AMS ready之后启动,比同在AMS ready的launcher还早,这个时候PMS还没有完成对整个系统apk的遍历,如果等待遍历完开机时候就太长了,所有出现这个问题是可以理解的
之所以我会在继承SystemIU上写这个,是为了统一管理这些需要开机启动的3方App,实际上就在开机广播里面处理也是没有问题的.