关于Android 8.0开启热点(HotSpot)

关于Android 8.0开启热点(HotSpot)

  • 开启热点(Android 8.0)
  • 关闭热点(Android 8.0)
    • 第一种方法:
    • 第二种方法:
  • 注意事项:
    • 问题1:
    • 解决:
    • 问题2:
    • 解决:
  • 致谢

最近写了一个局域网文件传输的小app,涉及到开关wifi的有关知识,在这里分享一下关于Android8.0热点管理的一些小知识点!!相信看到这篇文章的应该都能很好地解决Android8.0以前版本的热点管理,这里就不一一讲述了,下面进入关键。

开启热点(Android 8.0)

/*
 * 适配于Android_O上创建HotSpot的方法
*/
public void setWifiApEnabledForAndroidO(){
            WifiManager wifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
            wifiManager.startLocalOnlyHotspot(new WifiManager.LocalOnlyHotspotCallback() {
				/*
				*这里是成功开启wifi后回调的方法,此处的reservation中可以通过.getWifiConfiguration().获取
				*到WifiConfiguration,同样的,在WifiConfiguration中可以获取到开启热点的SSID和preSharedKey,
				*此方法开启的热点的名称和密码是系统随机生产的,无法自定义名称和密码,至少我到目前为止
				没有找到可用于设置8.0名称和密码的方法哈哈哈。
				*/
                @Override
                public void onStarted(WifiManager.LocalOnlyHotspotReservation reservation) {
                    super.onStarted(reservation);
                    String SSID = reservation.getWifiConfiguration().SSID;
                    String preSharedKey = reservation.getWifiConfiguration().preSharedKey;
                }

                @Override
                public void onStopped() {
                    super.onStopped();
                }

                @Override
                public void onFailed(int reason) {
                    super.onFailed(reason);
                }
            }, null);
        }

关闭热点(Android 8.0)

第一种方法:

保存开启热点方法中的回调参数reservation,可以通过reservation.close();关闭上述所开启的热点,不过个人觉得如果要关闭用户本身的自己开的热点的话,此方法应该不可行,不过第二种方法亲测可以关闭用户自己本身开启的热点。???

第二种方法:

/*
 * 适配于Android_O上关闭HotSpot的方法
*/
public void closeHotSpotForAndroid_O(){
            ConnectivityManager connManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
            Field iConnMgrField;
            try {
                iConnMgrField = connManager.getClass().getDeclaredField("mService");
                iConnMgrField.setAccessible(true);
                Object iConnMgr = iConnMgrField.get(connManager);
                Class<?> iConnMgrClass = Class.forName(iConnMgr.getClass().getName());
                Method stopTethering = iConnMgrClass.getMethod("stopTethering", int.class);
                stopTethering.invoke(iConnMgr, 0);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

到目前为止,上述的开启和关闭热点应该可以实现了,不过我发现有一些问题还是需要解决的。

注意事项:

问题1:

  • 当开启热点后,应用进入后台运行状态,大约6s之前所开启的热点就会自动关闭。

解决:

  • 将开启和关闭热点的方法放置在远程服务中开启,另其在单独线程中开启,可以解决问题1,如下:
    (以Android Studio工具为例子创建远程服务)

1.在如下图工作文件夹中找到与"java"文件夹同级任意文件夹,右键–>New–>AIDL–>AILD File后输入名字Finish,会自动生产aidl文件夹和所创建的aidl文件。

关于Android 8.0开启热点(HotSpot)_第1张图片
2.随后在创建的AIDL文件中声明开启关闭的方法。

// IMyAidlInterface.aidl
package com.example.zzzzzzzzzzzzzzz.networktransmission;
// Declare any non-default types here with import statements
interface IMyAidlInterface {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    void setWifiApEnabledForAndroidO();

    void closeHotSpotForAndroid_O();
}

3.Clean或ReBuild项目,随后创建一个继承于Service的类,在其中编写远程服务中的本地Binder。

@RequiresApi(api = Build.VERSION_CODES.O)
    private final IMyAidlInterface.Stub mBuilder = new IMyAidlInterface.Stub() {
        @Override
        public void setWifiApEnabledForAndroidO(){
            //开启热点的方法代码段
        }

        @Override
        public void closeHotSpotForAndroid_O(){
             //关闭热点的方法代码段
    };

4.在创建继承于Service的类中,重写onBind()方法,返回builder对象。

@Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        System.out.println("onBind service");
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            return mBuilder;
        }else{
            return null;
        }
    }

5.在AndroidManifest.xml配置文件中注册该远程服务。

		<service
            android:name=".service.AndroidOApServer"
            android:process=":ap">
            <intent-filter>
                <action android:name=".service.AIDL_SERVICE"/>
            </intent-filter>
        </service>

这里的android:process很关键,关系到其是否是单独进程运行
android:process:是否需要在单独的进程中运行,当设置为android:process=”:remote”时,代表Service在单独的进程中运行。注意“:”很重要,它的意思是指要在当前进程名称前面附加上当前的包名,所以“remote”和”:remote”不是同一个意思,前者的进程名称为:remote,而后者的进程名称为:App-packageName:remote。
6.在要开启wifi的activity中声明定义ServiceConnection和编写初始化Service方法。

  • 声明定义ServiceConnection和AIDL
private IMyAidlInterface apService;
private ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            apService = IMyAidlInterface.Stub.asInterface(service);
        }
        @Override
        public void onServiceDisconnected(ComponentName name) {
            apService = null;
        }
    };
  • 绑定服务
private void initApService(){
        Intent intent = new Intent();
        intent.setAction(".service.AIDL_SERVICE");
        bindService(new Intent(MainActivity.getExplicitIntent(SendActivity.this,intent)),serviceConnection, Service.BIND_AUTO_CREATE);
    }
  • 调用远程服务中开启/关闭热点方法
apService.setWifiApEnabledForAndroidO();//开启
apService.closeHotSpotForAndroid_O();//关闭

到这里为止,远程服务基本上可以正常开启了,但是Android 8.0对后台服务有限制,这里又需要用到前台服务的相关知识了,即转为前台服务保活,具体前台服务参考这里,转为前台服务后,基于Android 8.0 的app开启热点后切换到后台也不会出现6s热点断开的情况了

问题2:

开启热点后,所产生的SSID和preSharedKey如何传回UI线程。

解决:

通过BoradCastReciver机制,把要传的数据放入Intent中传送即可。

致谢

感谢广大csdn博主们发表的有关android8.0热点文章!关于这方面有不懂的问题可以在评论区留言,如果我有看到也第一时间回复你哈!

启发我过河的文章(感谢感谢!!):
https://blog.csdn.net/qq_35986042/article/details/83658581

你可能感兴趣的:(Android)