解决android3.0版本号以上应用接收不到开机广播问题

如今是2014-07-16 下午15:27.

好久没写过东西,突然间灵感喷发想写点东西(事实上是刚刚弄好了一个棘手的问题,自豪中。。呵呵呵呵 我牛掰)。废话不多说,进入正题。

不知道你们又没有碰到这问题,本身做的一个应用,可以监听开机广播的。但非常奇怪,在android3.0下面的版本号 你怎么跑都没问题。可是在android3.0以上的版本号就恐怕情况不一样了。你会发现往往非常多时候接收不到开机广播。这是为什么呢?嘿 不告诉你! 说笑的 事实上这方面百度非常多人给出为什么了。我在这就不多废话了,今天我们要说的是解决方法。

好了,既然说到解决方法,网上给出的有两种:

1.加入权限<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

2.把你写的app升级成为系统app

先说第一种吧,这样的呢我试过 在android系统4.0下面的貌似实用。但假设你用android版本号4.0以上的机子你就会发现还是老样子,广播接收不到。

那好吧,看来也就仅仅剩下另外一种方法咯,呵呵呵 正好 我今天要说的也是另外一种方法。开工!!!!

前提准备:

1.一台已经ROOT成功的机子。什么?不知道怎么root? 别问我 市面上有什么工具。

2.哦 没有2了 你仅仅要准备一台已经root成功的机子即可。硬要说点什么的话,java环境吧 eclipse android环境吧。

基本思路:我本来安装的app是具有接收开机广播的权限的,可是系统却不发送给我们自己写的应用,可是细心的你会发现,每次开机或者关机 我们的android手机都是会发送开机广播的(android.intent.action.BOOT_COMPLETED),仅仅是我们做的app接收不到而已。可是,手机的系统级别的app是一定会接受到的。好了,那么假设我们有方法把我们做的应用提升级别成为系统级的app,是否意味着一样能够接收开机广播了呢?好,我们来尝试一下。怎样?

首先,如果我如今写了一个Test02.apk

让我们来看看Test02.apk这项目里面都做了什么 先来看一下它的AndroidManifest.xml文件

<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

package="com.example.test02"

android:versionCode="1"

android:versionName="1.0" >

<uses-sdk

android:minSdkVersion="8"

android:targetSdkVersion="19"

android:sharedUserId="android.uid.system"/>

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>

<application

android:allowBackup="true"

android:icon="@drawable/ic_launcher"

android:label="@string/app_name"

android:theme="@style/AppTheme" >

<activity

android:name="com.example.test02.MainActivity"

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.test02.BrocatTest">

<intent-filter>

<action android:name="android.intent.action.BOOT_COMPLETED"/>

<category android:name="android.intent.category.HOME"/>

</intent-filter>

</receiver>

</application>

</manifest>

声明了一个Receiver,用于接收开机广播,好 那我们来看看这个BrocatTest又做了什么

public class BrocatTest extends BroadcastReceiver{

@Override

public void onReceive(Context arg0, Intent arg1) {

// TODO Auto-generated method stub

Log.i("BrocatTest", "run here.....");

}

}

嘿嘿。。仅仅是打印一句话而已。。。。。。。。。。。

接下来我们拿到Test02.apk 我们把它放到电脑D盘文件夹下

打开cmd 进入adb shell 输入命令 adb push D:\Test02.apk /sdcard/ 把D盘文件夹下的Test02.apk拷贝到手机的sdcard卡文件夹下

adb shell

su

mount

看一下你们手机system目录是否处于可写入的状态(rw),默认是仅仅读(ro)

假设处于仅仅读的状态(ro) 那么就要把状态改为可写的状态

mount -o remount,rw -t -yaffs2 /dev/block/mtdblock3 /system

mount  再次使用这命令,看状态是否改变了

假设状态已经改变了 运行

cat /sdcard/Test02.apk > /system/app/Test02.apk

运行完后Test02.apk已经成功的写入/system/app目录了,这个目录就是专门存放系统app的地方,放心。手机会自己主动帮你安装的,假设你想确认的话

cd /system/app

ls

看有没有Test02.apk这个apk包

最后别忘了运行mount -o -remount,ro -t -yaffs2 /dev/block/mtdblock3 /system 把状态值改回来

exit

exit

接着重新启动一下手机看看。。你会得到以外的惊喜。

好了到这里 上面的都是要通过adb shell操作完毕的 那么有没有说 我写在代码里的 我直接运行就能够了呢?

呵呵呵呵 有 立即来。

我们在Eclipse新建一个项目Test06 文件夹例如以下

首先我们把我们要提升为系统app的apk包放到assets目录下

接着我们先来看一下 SDCardUtil这个类,这个类的工作就是把位于assets文件夹下的Test02.apk文件以流的方式写入手机的sdcard

/**

* 对于SD卡的操作类

* @author YangMo*/

public class SDCardUtil {

private Context context;

private boolean hasCard = false; //推断是否存在SD卡

private String sdPath  = null;

private String filePath = null;

/**

* 构造函数*/

public SDCardUtil(Context context){

this.context = context;

hasCard      = Environment.getExternalStorageState().equals( android.os.Environment.MEDIA_MOUNTED );

try {

sdPath        = Environment.getExternalStorageDirectory().getCanonicalPath();

filePath   = this.context.getFilesDir().getPath();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

System.out.println("sdPath = "+sdPath);

System.out.println("filePath = "+filePath);

}

public boolean isOk(){

return hasCard;

}

/**

* 将文件写入SD卡内*/

public int readStreamToSDCard(InputStream is, String fileName){

int state = -1;

try{

FileOutputStream fos = new FileOutputStream(sdPath +"/" +fileName);

byte[] buffer = new byte[8192];

int count = 0;

while( (count = is.read(buffer)) != -1 ){

fos.write(buffer, 0, count);

}

fos.close();

is.close();

state = 0;

return state;

}catch(Exception e){

e.printStackTrace();

return -1;

}

}

}

我们再来看看RootCmd这个类,这个类基本的工作就是取代我们的adb shell

public final class RootCmd {

// 运行linux命令而且输出结果

protected static String execRootCmd(String paramString) {

String result = "result : ";

try {

Process localProcess = Runtime.getRuntime().exec("su ");

// 经过Root处理的android系统即有su命令

OutputStream localOutputStream = localProcess.getOutputStream();

DataOutputStream localDataOutputStream = new DataOutputStream(localOutputStream);

InputStream localInputStream = localProcess.getInputStream();

DataInputStream localDataInputStream = new DataInputStream(localInputStream);

String str1 = String.valueOf(paramString);

String str2 = str1 + "\n";

localDataOutputStream.writeBytes(str2);

localDataOutputStream.flush();

String str3 = null;

//            while ((str3 = localDataInputStream.readLine()) != null) {

//                Log.d("result", str3);

//            }

localDataOutputStream.writeBytes("exit\n");

localDataOutputStream.flush();

localProcess.waitFor();

return result;

} catch (Exception localException) {

localException.printStackTrace();

return result;

}

}

// 运行linux命令但不关注结果输出

protected static int execRootCmdSilent(String paramString) {

try {

Process localProcess = Runtime.getRuntime().exec("su");

Object localObject = localProcess.getOutputStream();

DataOutputStream localDataOutputStream = new DataOutputStream((OutputStream) localObject);

String str = String.valueOf(paramString);

localObject = str + "\n";

localDataOutputStream.writeBytes((String) localObject);

localDataOutputStream.flush();

localDataOutputStream.writeBytes("exit\n");

localDataOutputStream.flush();

localProcess.waitFor();

int result = localProcess.exitValue();

return (Integer) result;

} catch (Exception localException) {

localException.printStackTrace();

return -1;

}

}

// 推断机器Android是否已经root,即是否获取root权限

protected static boolean haveRoot() {

int i = execRootCmdSilent("echo test");

// 通过运行測试命令来检測

if (i != -1) {

return true;

}

return false;

}

}

接着 我们来看看我们的主Activity大人里面做了什么工作

public class MainActivity extends ActionBarActivity{

private static String FILENAME = "Test02.apk";

private int state = -1;

//adb shell命令

String paramString= "adb shell" +"\n"+

"su" +"\n"+

"mount -o remount,rw -t yaffs2 /dev/block/mtdblock3 /system" +"\n"+

"cat /sdcard/Test02.apk > /system/app/Test02.apk" +"\n"+

"mount -o remount,ro -t yaffs2 /dev/block/mtdblock3 /system" +"\n"+

"exit" +"\n"+

"exit";

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

SDCardUtil sdUtil = new SDCardUtil(this);

try {

if(sdUtil.isOk()){

InputStream is = getApplicationContext().getAssets().open(FILENAME);

state = sdUtil.readStreamToSDCard(is, FILENAME);

}else

Toast.makeText(this, getApplicationContext().getString(R.string.sd_title), Toast.LENGTH_SHORT).show();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

if(state == 0){//一切准备就绪,进行将应用提升为系统级别应用的操作

if(RootCmd.haveRoot()){

if(RootCmd.execRootCmdSilent(paramString)==-1){

Toast.makeText(this, getApplicationContext().getString(R.string.initialiseOk), Toast.LENGTH_LONG).show();

}else{

Toast.makeText(this, getApplicationContext().getString(R.string.initialiseFail), Toast.LENGTH_LONG).show();

}

}else{

Toast.makeText(this, getApplicationContext().getString(R.string.noRoot), Toast.LENGTH_LONG).show();

}

}

}

}

先看这里

try {

if(sdUtil.isOk()){

InputStream is = getApplicationContext().getAssets().open(FILENAME);

state = sdUtil.readStreamToSDCard(is, FILENAME);

}else

Toast.makeText(this, getApplicationContext().getString(R.string.sd_title), Toast.LENGTH_SHORT).show();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

这部分的代码先把apk写到我们的sd卡里面

if(state == 0){//一切准备就绪,进行将应用提升为系统级别应用的操作

if(RootCmd.haveRoot()){

if(RootCmd.execRootCmdSilent(paramString)==-1){

Toast.makeText(this, getApplicationContext().getString(R.string.initialiseOk), Toast.LENGTH_LONG).show();

}else{

Toast.makeText(this, getApplicationContext().getString(R.string.initialiseFail), Toast.LENGTH_LONG).show();

}

}else{

Toast.makeText(this, getApplicationContext().getString(R.string.noRoot), Toast.LENGTH_LONG).show();

}

}

而这部分就是取代我们手工的adb shell操作了

注意paramString这个属性的声明

//adb shell命令

String paramString= "adb shell" +"\n"+

"su" +"\n"+

"mount -o remount,rw -t yaffs2 /dev/block/mtdblock3 /system" +"\n"+

"cat /sdcard/Test02.apk > /system/app/Test02.apk" +"\n"+

"mount -o remount,ro -t yaffs2 /dev/block/mtdblock3 /system" +"\n"+

"exit" +"\n"+

"exit";

恩恩,好了,连接上你的手机 run一下Test06这个项目看看。。。。嘿嘿~~

时间: 2024-11-08 14:51:53

解决android3.0版本号以上应用接收不到开机广播问题的相关文章

解决android3.0版本以上应用接收不到开机广播问题

现在是2014-07-16 下午15:27. 好久没写过东西,突然间灵感喷发想写点东西(其实是刚刚弄好了一个棘手的问题,自豪中..呵呵呵呵 我牛掰).废话不多说,进入正题. 不知道你们又没有碰到这问题,本身做的一个应用,能够监听开机广播的.但很奇怪,在android3.0以下的版本 你怎么跑都没问题.但是在android3.0以上的版本就恐怕情况不一样了.你会发现往往很多时候接收不到开机广播.这是为什么呢?嘿 不告诉你! 说笑的 其实这方面百度很多人给出为什么了.我在这就不多废话了,今天我们要说

解决Android3.0之后不能在主线程中进行HTTP请求

在Android3.0以后,会发现,只要是写在主线程(就是Activity)中的HTTP请求,运行时都会报错,这是因为Android在3.0以后为了防止应用的ANR(aplication Not Response)异常. 针对此问题有两种解决的方法: 1.可以再Activity的onCreate()方法中加入这样一段代码,如下: 1 if (Build.VERSION.SDK_INT >= 11) { 2 StrictMode.setThreadPolicy(new StrictMode.Thr

开机广播事件无法接收以及替代方案

在android中,谷歌工程师为了加固android系统,使其更安全,限制了开机广播的发送顺序.系统启动->系统应用启动->发送开机广播->普通app启动.由此一来,普通的app是接收不到开机广播的,据网上的答案说是要把app移动到system目录下..可是太繁琐了(反正我不会弄)...于是我苦苦的寻找解决方案.我发现可以用SCREEN_ON或者SCREEN_OFF来代替.但是还有一个问题,SCREEN的广播不能静态注册..这让我很纳闷..据说是谷歌工程师为了优化系统才这么做的..静态注

iOS 9 平台上 AFNetworking 框架 3.0 版本号解决的问题和问题解决

太阳火神的漂亮人生 (http://blog.csdn.net/opengl_es) 本文遵循"署名-非商业用途-保持一致"创作公用协议 转载请保留此句:太阳火神的漂亮人生 -  本博客专注于 敏捷开发及移动和物联设备研究:iOS.Android.Html5.Arduino.pcDuino,否则,出自本博客的文章拒绝转载或再转载,谢谢合作. 再补充 此有一篇比較全面的适配 iOS 9 的文章: http://www.cnblogs.com/dsxniubility/p/4821184.

VoltDB公布4.0版本号,大步提高内存实时分析速度,进军操作数据库市场

号称世界上最快的关系数据库的VoltDB与2014年1月29号(美国东部时间)公布下一代数据库4.0版本号.新的版本号有非常多地方的改进,大步挺高系统性能.在过去的13年,VoltdDB号称自己公司较12年,年收入增长298%,预定额增长368%,客户数量增长94%. 当中有几个重要的亮点: 1. 提高内存实时分析数据的能力, 实时地接受大量(tons of thousands)client链接,并实时訪问数据和做各种分析计算.速度提升至多10倍左右. 2. VoltDB4.0加入了尖端的分布式

解决:长按一条接收到的彩信,快捷菜单“选择性复制”功能错误

[测试步骤]长按一条接收到的彩信,快捷菜单--"选择性复制" [测试结果]功能错误,未实现选择性复制,实际是播放彩信内容 [预期结果]应该选择复制彩信内容 通过分析代码我们定位到以下代码: private final class MsgListMenuClickListener implements MenuItem.OnMenuItemClickListener { private MessageItem mMsgItem; public MsgListMenuClickListen

android圆角View实现及不同版本这间的兼容(android3.0过后的版本)

http://blog.csdn.net/lovecluo/article/details/8710174 在做我们自己的APP的时候,为了让APP看起来更加的好看,我们就需要将我们的自己的View做成圆角的,毕竟主流也是将很多东西做成圆角,和苹果的外观看起来差不多,看起来也还不错.要将一个View做成圆角的也很容易,只需要建立一个自定义的Drawable就可以了.我们在res/drawable下面建立一个shape的drawable,代码如下: <?xml version="1.0&qu

明晚8点,捷微团队QQ群公开课,解说jeewx2.0版本号maven环境的搭建入门!

2014-08-13号晚8点,捷微团队QQ群公开课,解说jeewx2.0版本号maven环境的搭建入门! 讲师:刘强(团队成员) QQ群:287090836 (JAVA版本号微信开源项目) http://www.oschina.net/news/54344/jeewx-2-0 明晚8点,捷微团队QQ群公开课,解说jeewx2.0版本号maven环境的搭建入门!,布布扣,bubuko.com

如何解决VC6.0++ 与 win8&amp;8.1兼容问题

今天电子班的梦婷同学抱着电脑来我实验室问我怎么解决在Win8系统安装VC6.0的问题, 一开始我也很头痛,因为我也没弄过这个,然后抱着死马当作活马医的态度在网上搜搜试了下. 如何解决VC6.0++ 与 win8&8.1兼容问题 另附:VC6.0的下载地址 1/4 2/4 将MSDEV.EXE重命名为MSDEV1.EXE. 你将看到一个名为MSDEV.exe的程序,没错就是它,首先对他重命名,(如MSDEV1.exe看你喜好),然后右键属性→兼容性,将其改为以兼容模式运行此程序,选择windows