自己动手做一个adb的wifi连接及adb命令的apk

Posted zy9011

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了自己动手做一个adb的wifi连接及adb命令的apk相关的知识,希望对你有一定的参考价值。

前言

估计搞安卓开发的小伙伴们都放弃了eclipse的开发转战android studio了吧,现在gradle都3.0 buiild都24.0.2了以后 都不再支持2.2及以下的版本了。eclipse的同学快上车。

上面的都不是重点,每当你大清早起来去公司上班,然后打开电脑发现你的usb线没有带,作为一个安卓程序员的你有点尴尬了。

然后你果断的给android studio装上ADB WIFI插件,哈哈,事实证明你还是相当的机智,然后你会面临另外一个尴尬(蛋疼)。你使用时会出现如图:

你会蛋微凉微凉的,这特么不是说好的可以用wifi连接adb吗?宝宝心里苦但是不能哭,问题来了你该找谁借usb线呢?特么安卓程序员都要自己用,所以你果断放弃找他们了,然后去找测试妹子吗感觉也有点不好。

最后呢你可能会选择下个WirelessADB,然后通过cmd命令来连接手机,确实效果还是比较明显,可以顺利的完成任务,求人不如求己对吧。

这样手机就连接起来了,宝宝再也不再担心手机忘记带数据线连接不起wifi了。但是用别人的还是不爽,今天宝宝就自己来实现这个功能(记住这功能要操作adb那么你的手机必须是root的,手机没有root你还做个毛的安卓程序员)。

实现效果

就不用gif来展示了,搞2个图来展示下效果图算了:


动手实现思路

  1. 代码获取局域网ip地址

  2. 判断手机是否获取root权限(su),没有自行root(不会的话jj剁了)

  3. su文件写入adb 命令执行相关的操作

  4. cmd执行连接命令,win可以写个bat文件


所有的步骤就上面这些了,开始果断撸码吧。


然后具体的就是先判断是否有root,毕竟adb是需要root的,然后也就是把命令写入su文件执行。(也可以通过Android Runtime来弄,更加轻松)

Android Runtime使得直接调用底层Linux下的可执行程序或脚本成为可能

比如Linux下写个测试工具,直接编译后apk中通过Runtime来调用

或者写个脚本,apk中直接调用,省去中间层或者JNI

需要注意:

  1. exec不等于console命令

2.exec的输入输出流需要自己处理

3.exec执行时阻塞、非阻塞,返回结果问题

4.注意权限问题

开始撸

获取ip地址(先得有一个局域网wifi)

 /**
     * @return 获取ip地址
     */
    public static String getIpAddress() 
        try 
            for (Enumeration<NetworkInterface> en = NetworkInterface
                    .getNetworkInterfaces(); en.hasMoreElements(); ) 
                NetworkInterface intf = en.nextElement();
                for (Enumeration<InetAddress> 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;
    

把32位整形的ip地址换成“...”地址

我们先通过安卓里面的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)。

获取判断root权限

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服务连接的ip和端口,并且开启adb

 /**
     * 打开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

/**
     * 断开adb连接
     */
    public static void closeAdb() 
        try 
            Runtime.getRuntime().exec(new String[]"/system/bin/su", "-c", "stop adbd");
         catch (IOException e) 
            e.printStackTrace();
        
    

重启adb

  /**
     * 重启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

  /**
     * 卸载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();
        
    

根据包名杀死apk(好像没有效果)

  /**
     * 杀死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);
        
    

开启指定app(须知道包名)

 /**
     * 打开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数据

 /**
     * 清除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();
        
    

adb命令重启

    /**
     * 重启手机
     */
    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;
        
    

demo 传送门:WifiAdb.zip

总结

代码不难,就是为了学习一下adb命令,装在手机里没有带数据线的时候,也可以拿来进行wifi连接adb调试安卓应用以后再也不用去下载什么WirelessAdb了,至少关机重启还是方便点吧,可能跟cmd命令有点点差别吧。

以上是关于自己动手做一个adb的wifi连接及adb命令的apk的主要内容,如果未能解决你的问题,请参考以下文章

哪位说说如何用androidadb连接手机

wifi万能钥显示adb无法连接手机怎么办

无法在家庭 WLAN 中通过 wifi 连接 ADB

ADB 无线连接设备

ADB+Python+Appium连接真机操作步骤说明及报错解决方案

adb wifi 测试(无需root)