背景

项目apk需要在升级之后自启动(新安装从未启动过),设备由UPS供电
但从Android3.1开始,新安装从未启动过的app不能收到系统广播(启动完成,网络状态变化等)

解决方案:

将app做成系统应用

系统APK可以正常接收系统广播
怎么将app做成系统应用?:

加入到Android源码编译

解压apk文件得到lib,将编译好的apk(xxx.apk)放到系统源码的packages/apps/xxx(xxx为自己创建)中,解压得到的lib文件夹也放到xxx文件夹中(没有源码)
添加Android.mk文件:

include $(CLEAR_VARS)
# Module name should match apk name to be installed
LOCAL_MODULE := Test
LOCAL_MODULE_TAGS := optional  //不管是user 还是eng 版本都会编译此app
LOCAL_SRC_FILES := $(LOCAL_MODULE).apk
LOCAL_MODULE_CLASS := APPS
LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX)
LOCAL_PREBUILT_JNI_LIBS := \
	@lib/armeabi/libtest.so \  //注意前面要用tab键隔开
	@lib/armeabi/libtest2.so   //这是你需要添加的so 如果是 armeabi-v7a 直接替换掉armeabi
LOCAL_CERTIFICATE := PRESIGNED  //表示app已经签名
include $(BUILD_PREBUILT)

在系统预置app的配置文件(device/xxxx/xxxx.mk)中添加我们目录
PRODUCT_PACKAGES += xxx

进行系统签名

具体可参考:Android签名 .

将app安装在system/app目录下

解压apk文件,将解压后的lib/armeabi下面的.so文件拷贝到/system/lib下面,没有lib则直接下一步拷贝apk
chmod 644 xxxxx.so
将apk文件拷贝到/system/app系统应用文件夹
chmod 644 xxxxx.apk
也可以通过adb:

adb shell
mount
mount -o remount /dev/block/nandd /system #改为可读写
mount

通过第三方应用

发送带 FLAG_INCLUDE_STOPPED_PACKAGES 的广播给Stop状态的自己
新安装的apk会被置于”stopped”状态,并且只有在至少手动启动这个程序一次后该程序才会改变状态,能够正常接收到指定的广播消息。Android主要是出于安全考虑,防止广播无意或者不必要地开启未启动的APP后台服务,消耗系统资源。
但Android提供了一种借助其它应用发送指定Flag广播的方式,达到应用在未启动的情况下仍然能够收到消息的效果。从Android3.1开始,系统给Intent定义了两个新的Flag,分别为FLAG_INCLUDE_STOPPED_PACKAGES(表示包含未启动的App)和FLAG_EXCLUDE_STOPPED_PACKAGES(表示不包含未启动的App),用来控制Intent是否要对处于停止状态的App起作用,具体的操作方式如下:

在需要接收广播的应用中静态注册广播,并定义好action,并且需要指定android:exported="true"

<receiver android:name=".receiver.UpdateWidgetReceiver"
   android:exported="true">
   <intent-filter>
        <action android:name="com.uperone.widget.action"/>
   </intent-filter>
</receiver>

在发送广播的应用中添加如下代码段:

Intent intent = new Intent();
intent.setAction("com.uperone.widget.action");
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
sendBroadcast(intent);