編輯:關於Android編程
估計搞安卓開發的小伙伴們都放棄了eclipse的開發轉戰android studio了吧,現在gradle都3.0 buiild都24.0.2了以後 都不再支持2.2及以下的版本了。eclipse的同學快上車。
上面的都不是重點,每當你大清早起來去公司上班,然後打開電腦發現你的usb線沒有帶,作為一個安卓程序員的你有點尴尬了。
然後你果斷的給android studio裝上ADB WIFI插件,哈哈,事實證明你還是相當的機智,然後你會面臨另外一個尴尬(蛋疼)。你使用時會出現如圖:
你會蛋微涼微涼的,這特麼不是說好的可以用wifi連接adb嗎?寶寶心裡苦但是不能哭,問題來了你該找誰借usb線呢?特麼安卓程序員都要自己用,所以你果斷放棄找他們了,然後去找測試妹子嗎感覺也有點不好。<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxibG9ja3F1b3RlPg0KCTxwPtfuuvPE2MTjv8nE3Lvh0aHU8c/CuPZXaXJlbGVzc0FEQizIu7rzzai5/WNtZMP8we7AtMGsvdPK1rv6o6zIt8q10Ke5+7u5ysexyL3Pw/fP1KOsv8nS1MuzwPu1xM3qs8nIzs7xo6zH88jLsrvI58fzvLq21LDJoaM8L3A+DQo8L2Jsb2NrcXVvdGU+DQo8cD48aW1nIGFsdD0="這裡寫圖片描述" src="/uploadfile/Collfiles/20160822/20160822094245930.jpg" title="\" />
這樣手機就連接起來了,寶寶再也不再擔心手機忘記帶數據線連接不起wifi了。但是用別人的還是不爽,今天寶寶就自己來實現這個功能(記住這功能要操作adb那麼你的手機必須是root的,手機沒有root你還做個毛的安卓程序員)。
就不用gif來展示了,搞2個圖來展示下效果圖算了:
代碼獲取局域網ip地址
判斷手機是否獲取root權限(su),沒有自行root(不會的話jj剁了)
su文件寫入adb 命令執行相關的操作
cmd執行連接命令,win可以寫個bat文件
所有的步驟就上面這些了,開始果斷撸碼吧。
然後具體的就是先判斷是否有root,畢竟adb是需要root的,然後也就是把命令寫入su文件執行。(也可以通過Android Runtime來弄,更加輕松)
Android Runtime使得直接調用底層Linux下的可執行程序或腳本成為可能
比如Linux下寫個測試工具,直接編譯後apk中通過Runtime來調用
或者寫個腳本,apk中直接調用,省去中間層或者JNI
需要注意:
exec不等於console命令2.exec的輸入輸出流需要自己處理
3.exec執行時阻塞、非阻塞,返回結果問題
4.注意權限問題
/** * @return 獲取ip地址 */ public static String getIpAddress() { try { for (Enumerationen = NetworkInterface .getNetworkInterfaces(); en.hasMoreElements(); ) { NetworkInterface intf = en.nextElement(); for (Enumeration enumIpAddr = intf .getInetAddresses(); enumIpAddr.hasMoreElements(); ) { InetAddress inetAddress = enumIpAddr.nextElement(); if (!inetAddress.isLoopbackAddress() && inetAddress instanceof Inet4Address) { return inetAddress.getHostAddress().toString(); } } } } catch (Exception e) { e.printStackTrace(); } return null; }
我們先通過安卓裡面的WifiManager來獲取wifiInfo,接著通過wifiInfo使用aidl來獲取32位整形的ip地址,接著我們把它轉化為我們常見的ip地址形式
/** * @return 獲取局域網的ip地址形式(32位整型IP地址轉成本地ip) */ private static String getLocalIpAddress() { WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); WifiInfo wifiInfo = wifiManager.getConnectionInfo(); // 獲取32位整型IP地址 int ipAddress = wifiInfo.getIpAddress(); // 返回整型地址轉換成“*.*.*.*”地址 return String.format("%d.%d.%d.%d", (ipAddress & 0xff), (ipAddress >> 8 & 0xff), (ipAddress >> 16 & 0xff), (ipAddress >> 24 & 0xff)); }
准備工作已經做好了(適配獲取局域網ip)。
Runtime.getRuntime().exec("su");
一般我們使用adb得先去獲取root權限的,也就是檢驗是否有su文件。
// 判斷機器Android是否已經root,即是否獲取root權限 public boolean haveRoot() { if (!mHaveRoot) { int ret = execRootCmdCilent("echo test"); // 通過執行測試命令來檢測 if (ret != -1) { Toast.makeText(context, "已經root", Toast.LENGTH_LONG).show(); mHaveRoot = true; } else { Toast.makeText(context, "not root", Toast.LENGTH_LONG).show(); Log.i(TAG, "not root!"); } } else { Toast.makeText(context, "已經root", Toast.LENGTH_LONG).show(); Log.i(TAG, "mHaveRoot = true, have root!"); } return mHaveRoot; }
/** * 打開adb連接 * * @param tv */ public static void openAdb(TextView tv) { if (!isConn) { tv.setText(" adb connect" + getLocalIpAddress()); execShell("setprop service.adb.tcp.port 8888");// Runtime.getRuntime().exec(new String[]{"/system/bin/su","-c", "setprop service.adb.tcp.port 5555"}); try { Runtime.getRuntime().exec(new String[]{"/system/bin/su", "-c", "start adbd"}); // execShell("start adbd"); } catch (IOException e) { e.printStackTrace(); } isConn = true; } }
其實呢,看代碼我們也知道我們既可以使用用寫入su文件的方式也可以直接使用Runtime.getRuntime().exec()來執行,後文全部使用後者使用起來很簡單。
/** * 在su文件中寫入命令 * * @param str */ public static void execShell(String str) { try { // 權限設置 Process p = Runtime.getRuntime().exec("su"); // 獲取輸出流 OutputStream outputStream = p.getOutputStream(); DataOutputStream dataOutputStream = new DataOutputStream( outputStream); // 將命令寫入 dataOutputStream.writeBytes(str); // 提交命令 dataOutputStream.flush(); // 關閉流操作 dataOutputStream.close(); outputStream.close(); } catch (Throwable t) { t.printStackTrace(); } }
上面貼的代碼和Runtime.getRuntime().exec(cmdstr)的功能一樣。
連接的時候,你需要在cmd敲命令adb connect 你的ip地址,當然一般你是配置了adb的環境的,win下所以你只需要寫一個bat文件就好了,連接的時候點擊下。
裡面的內容,你只需要把cmd命令拷貝進去好了(ip不能經常變的前提,變了手動改)。
/** * 斷開adb連接 */ public static void closeAdb() { try { Runtime.getRuntime().exec(new String[]{"/system/bin/su", "-c", "stop adbd"}); } catch (IOException e) { e.printStackTrace(); } }
/** * 重啟adb */ public static void restartAdb() { try { Runtime.getRuntime().exec(new String[]{"/system/bin/su", "-c", "adb kill-server"}); Runtime.getRuntime().exec(new String[]{"/system/bin/su", "-c", "adb start-server"}); } catch (IOException e) { e.printStackTrace(); } }
/** * 卸載apk */ public static void uninstallApk(String packageName) { try { Process p= Runtime.getRuntime().exec(new String[]{"/system/bin/su", "-c", "pm uninstall " + packageName}); if (p == null) { Toast.makeText(context, "app 卸載失敗", Toast.LENGTH_LONG).show(); } else { Toast.makeText(context, "app 已成功卸載", Toast.LENGTH_LONG).show(); } } catch (IOException e) { e.printStackTrace(); } }
/** * 殺死app * * @param packageName 包名 */ public static void killApp(String packageName) { try { Process p=Runtime.getRuntime().exec(new String[]{"/system/bin/su", "-c", " am force-stop " + packageName}); if (p == null) { Toast.makeText(context, "app 關閉失敗", Toast.LENGTH_LONG).show(); } else { Toast.makeText(context, "app 關閉成功", Toast.LENGTH_LONG).show(); } } catch (IOException e) { e.printStackTrace(); } }
/** * 通過Android底層實現關閉當前進程 */ public static void killProcess() { int pid = android.os.Process.myPid(); if (pid != 0) { System.exit(0); android.os.Process.killProcess(pid); } }
/** * 打開apk * * @param packageName */ public static void startApk(String packageName) { try{ Intent intent = context.getPackageManager().getLaunchIntentForPackage(packageName); context.startActivity(intent); }catch(Exception e){ Toast.makeText(context, "沒有安裝", Toast.LENGTH_LONG).show(); } }
/** * 清除apk緩存 * * @param packageName */ public static void clearApp(String packageName) { try { Process p= Runtime.getRuntime().exec(new String[]{"/system/bin/su", "-c", "pm clear " + packageName + " HERE"}); if (p == null) { Toast.makeText(context, "app 緩存數據清空失敗", Toast.LENGTH_LONG).show(); } else { Toast.makeText(context, "app 緩存數據清空成功", Toast.LENGTH_LONG).show(); } } catch (IOException e) { e.printStackTrace(); } }
/** * 重啟手機 */ public static void rebootPhone() { try { Runtime.getRuntime().exec(new String[]{"/system/bin/su", "-c", "reboot"}); } catch (IOException e) { e.printStackTrace(); } }
adb 命令關機
/** * 關閉手機 */ public static void closePhone() { try { Runtime.getRuntime().exec(new String[]{"/system/bin/su", "-c", "reboot -p"}); } catch (IOException e) { e.printStackTrace(); } }
具體使用代碼很簡單:
package com.losileeya.wifiadb; import android.content.Intent; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.text.TextUtils; import android.view.View; import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; import butterknife.BindView; import butterknife.ButterKnife; import butterknife.OnClick; public class MainActivity extends AppCompatActivity { @BindView(R.id.tv_conn_adb) TextView tvConnAdb; @BindView(R.id.tv_conn_stop) TextView tvConnStop; @BindView(R.id.tv_adb_restart) TextView tvAdbRestart; @BindView(R.id.et_appinfo) EditText etAppinfo; @BindView(R.id.tv_uninstall_app) TextView tvUninstallApp; @BindView(R.id.tv_kill_app) TextView tvKillApp; @BindView(R.id.tv_start_app) TextView tvStartApp; @BindView(R.id.tv_clean_appdata) TextView tvCleanAppdata; @BindView(R.id.tv_close_phone) TextView tvClosePhone; @BindView(R.id.tv_rebot_phone) TextView tvRebotPhone; @BindView(R.id.tv_kill_currentapp) TextView tvKillCurrentapp; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ButterKnife.bind(this); } @OnClick({R.id.tv_conn_adb, R.id.tv_conn_stop, R.id.tv_adb_restart, R.id.tv_uninstall_app, R.id.tv_kill_app,R.id.tv_kill_currentapp, R.id.tv_start_app, R.id.tv_clean_appdata,R.id.tv_rebot_phone,R.id.tv_close_phone}) public void onClick(View view) { String packageName=etAppinfo.getText().toString().trim(); switch (view.getId()) { case R.id.tv_conn_adb: Intent intent= new Intent(MainActivity.this,ConnectActivity.class); intent.putExtra("isConn",true); startActivity(intent); break; case R.id.tv_conn_stop: Intent i= new Intent(MainActivity.this,ConnectActivity.class); i.putExtra("isConn",false); startActivity(i); break; case R.id.tv_adb_restart: new AdbUtil(this).restartAdb(); break; case R.id.tv_uninstall_app: if(TextUtils.isEmpty(packageName)){ Toast.makeText(this,"請輸入包名",Toast.LENGTH_SHORT).show(); }else{ new AdbUtil(this).uninstallApk(packageName); } break; case R.id.tv_kill_app: if(TextUtils.isEmpty(packageName)){ Toast.makeText(this,"請輸入包名",Toast.LENGTH_SHORT).show(); }else { new AdbUtil(this).killApp(packageName); } break; case R.id.tv_kill_currentapp: new AdbUtil(this).killProcess(); break; case R.id.tv_start_app: if(TextUtils.isEmpty(packageName)){ Toast.makeText(this,"請輸入包名",Toast.LENGTH_SHORT).show(); }else { new AdbUtil(this).startApk(packageName); } break; case R.id.tv_clean_appdata: if(TextUtils.isEmpty(packageName)){ Toast.makeText(this,"請輸入包名",Toast.LENGTH_SHORT).show(); }else { new AdbUtil(this).clearApp(packageName); } break; case R.id.tv_close_phone: new AdbUtil(this).closePhone(); break; case R.id.tv_rebot_phone: new AdbUtil(this).rebootPhone(); break; } } }
代碼不難,就是為了學習一下adb命令,裝在手機裡沒有帶數據線的時候,也可以拿來進行wifi連接adb調試安卓應用以後再也不用去下載什麼WirelessAdb了,至少關機重啟還是方便點吧,可能跟cmd命令有點點差別吧。
Android draw9patch 圖片制作與使用理解一下4句話: 上邊 決定左右拉升不變形 左邊 決定上下拉升不變形 右邊 設置內容高度區域 下邊 設置內容寬
一個類似於進度和打卡進度的自定義view如下圖:看GIF豈不是更好這個view在現在的app中挺常見的,基本都是這個套路,之前寫過一個可以雙向滑動的和這個view的類似,
《最近做一個小功能遇到這麼一個問題,listview 與 baseadapter結合使用,關於點贊的的時候 圖片重復問題,比如:我在第1個item 點贊然後 心型換成了紅
(一)概述Android 3.0後引入的一個UI控件——ViewPager(視圖滑動切換工具),實在想不到 如何來稱呼這個控件,他的大概功能:通過