解決android3.0版本號碼以上應用接收不到開機廣播問題

來源:互聯網
上載者:User

標籤:

如今是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版本號碼以上應用接收不到開機廣播問題

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.