編輯:關於Android編程
現在是2014-07-16 下午15:27.
好久沒寫過東西,突然間靈感噴發想寫點東西(其實是剛剛弄好了一個棘手的問題,自豪中。。呵呵呵呵 我牛掰)。廢話不多說,進入正題。
不知道你們又沒有碰到這問題,本身做的一個應用,能夠監聽開機廣播的。但很奇怪,在android3.0以下的版本 你怎麼跑都沒問題。但是在android3.0以上的版本就恐怕情況不一樣了。你會發現往往很多時候接收不到開機廣播。這是為什麼呢?嘿 不告訴你! 說笑的 其實這方面百度很多人給出為什麼了。我在這就不多廢話了,今天我們要說的是解決方法。
好了,既然說到解決方法,網上給出的有兩種:
1.添加權限
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文件
android:versionCode="1"
android:versionName="1.0" >
android:targetSdkVersion="19"
android:sharedUserId="android.uid.system"/>
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
android:name="com.example.test02.MainActivity"
android:label="@string/app_name" >
聲明了一個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.Z喎?/kf/ware/vc/" target="_blank" class="keylink">vcy5FbnZpcm9ubWVudC5NRURJQV9NT1VOVEVEICk7PGJyPgogIHRyeSB7PGJyPgogICBzZFBhdGggICAgICAgID0gRW52aXJvbm1lbnQuZ2V0RXh0ZXJuYWxTdG9yYWdlRGlyZWN0b3J5KCkuZ2V0Q2Fub25pY2FsUGF0aCgpOzxicj4KICAgZmlsZVBhdGggICA9IHRoaXMuY29udGV4dC5nZXRGaWxlc0RpcigpLmdldFBhdGgoKTs8YnI+CiAgfSBjYXRjaCAoSU9FeGNlcHRpb24gZSkgezxicj4KICAgLy8gVE9ETyBBdXRvLWdlbmVyYXRlZCBjYXRjaCBibG9jazxicj4KICAgZS5wcmludFN0YWNrVHJhY2UoKTs8YnI+CiAgfTwvcD4KPHA+ICBTeXN0ZW0ub3V0LnByaW50bG4o"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這個項目看看。。。。嘿嘿~~
如題,在Android中按鈕的點擊事件有四種寫法,如下圖。界面為四個Button+一個TextView+一個ImageViewactivity_main布局文件如下:&n
很多Android手機隨機都預裝了很多無法卸載的第三方APP,這些APP既浪費資源還有偷跑流量的隱患。那麼,在不Root系統的前提下如何將它們“
0、在認識HTTP前先認識URL 在我們認識HTTP之前,有必要先弄清楚URL的組成,例如: http://www.******.com/china/index.htm
其實我一直准備寫一篇關於Android事件分發機制的文章,從我的第一篇博客開始,就零零散散在好多地方使用到了Android事件分發的知識。也有好多朋友問過我各種問題,比如