解决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这个项目看看。。。。嘿嘿~~
解决android3.0版本号以上应用接收不到开机广播问题的更多相关文章
- 解决Android3.0之后不能在主线程中进行HTTP请求
感谢大佬:https://www.cnblogs.com/falzy/p/5763848.html 在Android3.0以后,会发现,只要是写在主线程(就是Activity)中的HTTP请求,运行时 ...
- iOS 9 平台上 AFNetworking 框架 3.0 版本号解决的问题和问题解决
iOS 9 平台上 AFNetworking 框架 3.0 版本号解决的问题和问题解决 太阳火神的漂亮人生 (http://blog.csdn.net/opengl_es) 本文遵循"署名- ...
- android圆角View实现及不同版本这间的兼容(android3.0过后的版本)
http://blog.csdn.net/lovecluo/article/details/8710174 在做我们自己的APP的时候,为了让APP看起来更加的好看,我们就需要将我们的自己的View做 ...
- VoltDB公布4.0版本号,大步提高内存实时分析速度,进军操作数据库市场
号称世界上最快的关系数据库的VoltDB与2014年1月29号(美国东部时间)公布下一代数据库4.0版本号.新的版本号有非常多地方的改进,大步挺高系统性能.在过去的13年,VoltdDB号称自己公司较 ...
- 【Android】Android 4.0 无法接收开机广播的问题
[Android]Android 4.0 无法接收开机广播的问题 前面的文章 Android 开机广播的使用 中 已经提到Android的开机启动,但是在Android 4.0 有时可以接收到开机 ...
- Mybatis分页插件2.0版本号公布
项目地址:http://git.oschina.net/free/Mybatis_PageHelper 软件介绍:http://www.oschina.net/p/mybatis_pagehelper ...
- cookie工具类,解决servlet3.0以前不能添加httpOnly属性的问题
最近在解决XSS注入的问题,由于使用的servlet版本是2.5,不支持httpOnly的属性,故做了个工具类来实现cookie的httpOnly的功能.全类如下: /** * cookie工具类,解 ...
- Android3.0中ActionBar的新特性
1. ActionBar(活动栏)替代了显示在屏幕顶端的标题栏.主要负责显示菜单,widget,导航等功能,主要包括:@ 显示选项菜单中的菜单项到活动栏:@ 添加可交互的视图到活动栏作为活动视图: ...
- Spark 1.0.0版本号公布
前言 今天Spark最终跨出了里程碑的一步,1.0.0版本号的公布标志着Spark已经进入1.0时代.1.0.0版本号不仅增加了非常多新特性,而且提供了更好的API支持.Spark SQL作为一个新的 ...
随机推荐
- 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 ...
- JAVA网络爬虫WebCollector深度解析——爬虫内核
WebCollector爬虫官网:https://github.com/CrawlScript/WebCollector 技术讨论群:250108697 怎样将爬虫内核导入自己的项目? 1.进入爬虫官 ...
- 虚拟机centOS中安装Redis,主机Redis Destop Manager不能访问虚拟机Redis server的解决方案
今天在学些redis的时候碰到个问题,发现主机Redis Destop Manager不能访问虚拟机Redis server的解决方案,找了一些网上的资料,原因可能有两个,整理记录下来: 1. Red ...
- ie浏览器提交参数和其它浏览器的区别
场景描述: 用户注册模块(ajax提交方式,post方法),在url后追加了一个参数,如:url+‘btnvalue=中文参数’,如此在非ie浏览器注册时,功能完好,但在ie下注册不成功.调式后发现在 ...
- 模块化手机project ara之我见
组装电脑,已被大部分人所熟知,只是像玩具一样组装手机,应该还仅仅是停留在想象.谷歌Project Ara将这一想象一步一步拉进现实,她希望提供一块框架,使用者能够自由地替换摄像头.显示屏.处理器.电池 ...
- 《Android系统开发》笔记
<Android系统开发>笔记1:Android系统概述 Android四层架构: 1. Linux Kernel&driver层 a.依赖于Linux 2.6内核,包含安全性.内 ...
- Swift实现OC中的单例模式
一.MySingle类 import Foundation class MySingle{ //定义单例的属性 var name:String? var age:Int? var height:Dou ...
- setChecked方法触发onCheckedChanged监听器问题
有时须要在程序初始化界面时,讲有些比如toggleButton等控件依照需求勾选,此时会发现,当我setChecked时会触发onCheckedChanged监听器,导致这部分代码被调用两次.解决方法 ...
- 理解Javascript的动态语言特性
原文:理解Javascript的动态语言特性 理解Javascript的动态语言特性 Javascript是一种解释性语言,而并非编译性,它不能编译成二进制文件. 理解动态执行与闭包的概念 动态执行: ...
- 在配置文件(.settings、.config)中存储自定义对象
原文:在配置文件(.settings..config)中存储自定义对象 引言 我前面曾写过一篇<使用配置文件(.settings..config)存储应用程序配置>,我在其中指出“sett ...