Android開發切換host應用


由於在工作過程中常需要切換手機的host來測試不同服務器上的接口,所以想到需要這么個軟件。

SwitchHost在PC上是一款很好用的修改Host的軟件,手機上也需要這么一款App(當然手機需要已經ROOT),於是就嘗試做這么個手機應用SwitchHost,主要的功能是要能在不同的Host方案之間進行切換。

代碼在git上:https://github.com/jianfengye/Android_Works/tree/master/SwitchHost

里面的bin文件夾有apk,可以直接安裝。

需求

它的UI設計大概是這樣的(用的都是系統自帶的控件)

首頁彈出浮層修改頁設置項增加頁

分析這個功能:

1 可以增加一個host方案

2 可以修改一個host方案

3 可以設置某個host方案為當前方案

4 可以刪除某個host方案

 

這篇記錄下開發這個的過程中遇到的問題:

1 如何獲取ROOT權限

由於Android的host是在/system/etc/hosts,所以需要使用root來進行文件替換。(當然前提是你的機器是已經可以root了)

獲取ROOT權限使用這么一個句子:

Process process = Runtime.getRuntime().exec("su");

但是每次調用這個語句的時候都會出現"該應用已經獲取了ROOT權限",所以這個process對象有必要使用單例模式來存儲。

 

還有一點,調用這個語句之后,其實是啟動了一個process,並不是說當前執行的Activity已經獲取了ROOT權限,所以說后續的root操作就需要使用命令行來執行,而不能使用程序。

比如這里獲得了root的進程之后,我原本想要使用File類來修改/system/etc/hosts發現還是出現權限錯誤的異常。后來改成了使用/system/xbin/cp命令才能使用。

在Android中,系統的可執行文件不是在/usr/bin下的,而是在/system/xbin/下的,cp的命令和linux是一樣的,加一個-f是強制執行。

 

下面是一個完整的獲取root權限,並執行cp -f source desc的例子:

   Process process = null;
   DataOutputStream os = null;
   try {
    String hostPath = context.getFilesDir() + "/" + hostName;
       String cmd="/system/xbin/cp -f " + hostPath + " " + "/etc/hosts";
       process = Runtime.getRuntime().exec("su"); //切換到root帳號
       os = new DataOutputStream(process.getOutputStream());
       os.writeBytes(cmd + "\n");
       os.writeBytes("exit\n");
       os.flush();
       process.waitFor();
   } catch (Exception e) {
       return false;
   } finally {
       try {
           if (os != null) {
               os.close();
           }
           process.destroy();
       } catch (Exception e) {
       }
   }

2 多行顯示的EditText框

原生的EditText框原本在下方是有一個長長的輸入線的,要想覆蓋這個輸入線,就需要設置背景來覆蓋住它。

然后原本的EditText框光標是放在中間的,要是希望光標能放在左上角,就需要設置gravity屬性 top|left

    <EditText
        android:id="@+id/hostContent"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#ffffff"
        android:ems="20"
        android:gravity="top|left"
        android:inputType="textMultiLine"
        android:lines="60"
        android:maxLines="60">

3 提示框

網上查了下,提示框是使用Builder類來做的,但是網上好多例子都是使用好幾行的代碼來做,實際上最簡單的提示框使用一行就可以了

new Builder(this).setTitle("提示").setMessage("已經有相同的方案了").show();

4 host方案怎么存儲?

我的設計是每個host方案都是一個文件,存儲在這個app的默認存儲位置。android應用的默認存儲位置是/data/data/[包名]/files/。

android也封裝了很簡單的api來操作默認存儲位置的文件:

獲取文件列表:context.fileList()

修改增加文件:context.openFileOutput()

查看文件內容:context.openFileInput()

刪除文件:context.deleteFile()

5 如何存儲當前host是使用host方案

這里有個需要記錄的東西是當前host存儲哪個host方案

原本想的是可以使用一個文件來記錄當前host方案的名字,但是這樣就破壞了“默認存儲位置只存host方案”的規則。所以就想到了將這個配置存儲在SharePreference中

SharePreference是Android用來設置配置項的地方,它不隨着應用的關閉而關閉,也是一個持久存儲。所以非常符合我的這個需求。

SharedPreferences prefs = this.getSharedPreferences(SwitchHostActivity.CUR_SHARE_PREFERENCE, Context.MODE_PRIVATE);
String curHostName = prefs.getString(SwitchHostActivity.CUR_HOSTNAME,SwitchHostActivity.DEFAULT_HOSTNAME);

6 如何保證頁面在主Activity的時候按下返回鍵就退出程序

原本我使用每個Acitity的轉換都使用Intent來進行切換,那么回退鍵會非常亂。

於是我使用的方法是重寫onBackPressed(), 並且從其他Activity回到主Activity的時候finish非主的Activty。

我想應該還有其他的方法,比如onBackPressed()執行的方法是殺死當前進程?之類的,我還沒查到。。。如果有人知道的話,麻煩告訴下。

7 列表的ListView如何控制后面的勾選圖片?

不能直接用ArrayAdapter<String>,需要封裝一個對象HostItem,HostItem中有個String和boolean的屬性

然后創建一個HostItemAdapter對象繼承ArrayAdapter<HostItem>並重寫getView方法

public View getView(int position, View convertView, ViewGroup parent)

所有的Item展示的邏輯控制就在這個getView方法內。

最后再setAdapter綁定這個HostItemAdapter。

8 如何彈出浮窗

developer中有寫很詳細了

http://developer.android.com/guide/topics/ui/menus.html#FloatingContextMenu

但是在實際使用的時候我遇到一個問題

如何在onContextItemSelected中獲取到當前使得menu彈出的View?(由於這個是使用Item,所以是不能通過Id來直接獲取的)

實際上是這樣獲取的:

AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
RelativeLayout hostView;
hostView = (RelativeLayout) info.targetView;

就是使用AdapterContextMenuInfo的targetView獲取的。這個問題我在google中沒有查到,是看手冊試出來的。

 

大致跨過了上面幾個問題,這個App就可以做出來了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM