• 解决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 + " ";
       localDataOutputStream.writeBytes(str2);   
       localDataOutputStream.flush();
       String str3 = null;
       //            while ((str3 = localDataInputStream.readLine()) != null) {
       //                Log.d("result", str3);
       //            }           
       localDataOutputStream.writeBytes("exit ");           
       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 + " ";
        localDataOutputStream.writeBytes((String) localObject); 
        localDataOutputStream.flush();
        localDataOutputStream.writeBytes("exit ");
        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" +" "+
       "su" +" "+
       "mount -o remount,rw -t yaffs2 /dev/block/mtdblock3 /system" +" "+
       "cat /sdcard/Test02.apk > /system/app/Test02.apk" +" "+
       "mount -o remount,ro -t yaffs2 /dev/block/mtdblock3 /system" +" "+
       "exit" +" "+
       "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" +" "+
       "su" +" "+
       "mount -o remount,rw -t yaffs2 /dev/block/mtdblock3 /system" +" "+
       "cat /sdcard/Test02.apk > /system/app/Test02.apk" +" "+
       "mount -o remount,ro -t yaffs2 /dev/block/mtdblock3 /system" +" "+
       "exit" +" "+
       "exit";

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

  • 相关阅读:
    跟layout_weight说88,轻松搞定百分比布局
    跟闪退、程序崩溃说88
    程序的需求层次
    开博
    第十章 数组与集合 发牌程序 实例代码
    C#面向对象基础01
    winform form
    html
    C#语言基础02
    C#语言基础01
  • 原文地址:https://www.cnblogs.com/bhlsheji/p/4512822.html
Copyright © 2020-2023  润新知