如今是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这个项目看看。。。。嘿嘿~~

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

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

    感谢大佬:https://www.cnblogs.com/falzy/p/5763848.html 在Android3.0以后,会发现,只要是写在主线程(就是Activity)中的HTTP请求,运行时 ...

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

    iOS 9 平台上 AFNetworking 框架 3.0 版本号解决的问题和问题解决 太阳火神的漂亮人生 (http://blog.csdn.net/opengl_es) 本文遵循"署名- ...

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

    http://blog.csdn.net/lovecluo/article/details/8710174 在做我们自己的APP的时候,为了让APP看起来更加的好看,我们就需要将我们的自己的View做 ...

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

    号称世界上最快的关系数据库的VoltDB与2014年1月29号(美国东部时间)公布下一代数据库4.0版本号.新的版本号有非常多地方的改进,大步挺高系统性能.在过去的13年,VoltdDB号称自己公司较 ...

  5. 【Android】Android 4.0 无法接收开机广播的问题

    [Android]Android 4.0 无法接收开机广播的问题   前面的文章 Android 开机广播的使用 中 已经提到Android的开机启动,但是在Android 4.0 有时可以接收到开机 ...

  6. Mybatis分页插件2.0版本号公布

    项目地址:http://git.oschina.net/free/Mybatis_PageHelper 软件介绍:http://www.oschina.net/p/mybatis_pagehelper ...

  7. cookie工具类,解决servlet3.0以前不能添加httpOnly属性的问题

    最近在解决XSS注入的问题,由于使用的servlet版本是2.5,不支持httpOnly的属性,故做了个工具类来实现cookie的httpOnly的功能.全类如下: /** * cookie工具类,解 ...

  8. Android3.0中ActionBar的新特性

    1. ActionBar(活动栏)替代了显示在屏幕顶端的标题栏.主要负责显示菜单,widget,导航等功能,主要包括:@  显示选项菜单中的菜单项到活动栏:@  添加可交互的视图到活动栏作为活动视图: ...

  9. Spark 1.0.0版本号公布

    前言 今天Spark最终跨出了里程碑的一步,1.0.0版本号的公布标志着Spark已经进入1.0时代.1.0.0版本号不仅增加了非常多新特性,而且提供了更好的API支持.Spark SQL作为一个新的 ...

随机推荐

  1. 14.4.7 Configuring the Number of Background InnoDB IO Threads 配置 后台InnoDB IO Threads的数量

    14.4.7 Configuring the Number of Background InnoDB IO Threads 配置 后台InnoDB IO Threads的数量 InnoDB 使用bac ...

  2. JAVA网络爬虫WebCollector深度解析——爬虫内核

    WebCollector爬虫官网:https://github.com/CrawlScript/WebCollector 技术讨论群:250108697 怎样将爬虫内核导入自己的项目? 1.进入爬虫官 ...

  3. 虚拟机centOS中安装Redis,主机Redis Destop Manager不能访问虚拟机Redis server的解决方案

    今天在学些redis的时候碰到个问题,发现主机Redis Destop Manager不能访问虚拟机Redis server的解决方案,找了一些网上的资料,原因可能有两个,整理记录下来: 1. Red ...

  4. ie浏览器提交参数和其它浏览器的区别

    场景描述: 用户注册模块(ajax提交方式,post方法),在url后追加了一个参数,如:url+‘btnvalue=中文参数’,如此在非ie浏览器注册时,功能完好,但在ie下注册不成功.调式后发现在 ...

  5. 模块化手机project ara之我见

    组装电脑,已被大部分人所熟知,只是像玩具一样组装手机,应该还仅仅是停留在想象.谷歌Project Ara将这一想象一步一步拉进现实,她希望提供一块框架,使用者能够自由地替换摄像头.显示屏.处理器.电池 ...

  6. 《Android系统开发》笔记

    <Android系统开发>笔记1:Android系统概述 Android四层架构: 1. Linux Kernel&driver层 a.依赖于Linux 2.6内核,包含安全性.内 ...

  7. Swift实现OC中的单例模式

    一.MySingle类 import Foundation class MySingle{ //定义单例的属性 var name:String? var age:Int? var height:Dou ...

  8. setChecked方法触发onCheckedChanged监听器问题

    有时须要在程序初始化界面时,讲有些比如toggleButton等控件依照需求勾选,此时会发现,当我setChecked时会触发onCheckedChanged监听器,导致这部分代码被调用两次.解决方法 ...

  9. 理解Javascript的动态语言特性

    原文:理解Javascript的动态语言特性 理解Javascript的动态语言特性 Javascript是一种解释性语言,而并非编译性,它不能编译成二进制文件. 理解动态执行与闭包的概念 动态执行: ...

  10. 在配置文件(.settings、.config)中存储自定义对象

    原文:在配置文件(.settings..config)中存储自定义对象 引言 我前面曾写过一篇<使用配置文件(.settings..config)存储应用程序配置>,我在其中指出“sett ...