1 问题

在Android8.0版本以后,开启热点我们采用的下面这种方式,但是跳转页面后热点会断开,手机不能互相传文件了

权限说明:Android8.0需要位置权限和GPS权限,同时手机热点还不能是开启状态。

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
try {
mWifiManager.startLocalOnlyHotspot(new WifiManager.LocalOnlyHotspotCallback() {
@Override
public void onFailed(int reason) {
super.onFailed(reason);
Log.i(TAG, "onFailed start");
}
@Override
public void onStarted(WifiManager.LocalOnlyHotspotReservation reservation) {
super.onStarted(reservation);
Log.i(TAG, "onStarted start");
mReservation = reservation;
WifiConfiguration wifiConfiguration = reservation.getWifiConfiguration();
String ssid = wifiConfiguration.SSID;
String pwd = wifiConfiguration.preSharedKey;
Log.i(TAG, "ssid is:" + ssid);
Log.i(TAG, "pwd is:" + pwd);
}
@Override
public void onStopped() {
super.onStopped();
sendBroadcast(STOP_STATE, "", "");
}
}, new Handler());
} catch (Exception e) {
e.printStackTrace();
Log.e(TAG, "startLocalOnlyHotspot error");
}
}

2 思考

1)全局静态保存mReservation变量,跳页面的时候不执行close方法。

我们看到上面的代码

mReservation = reservation;

我们关闭,是这样关闭的

if (mReservation != null) {
mReservation.close();
mReservation = null;
}

为了防止热点关闭,我们一开始对mReservation变量做了全局静态的保存,但是依然存在开启热点后,热点会断的问题。

2)反编译"茄子快传"代码,分析别人的产品

"茄子快传" 这个app也是热点生成后多个手机连接,然后进行文件的发送,我们反编译“茄子快传”代码

搜索关键字startLocalOnlyHotspot,如下图

android 热点开发设置可见性 安卓热点开启_android 热点开发设置可见性

android 热点开发设置可见性 安卓热点开启_android 热点开发设置可见性_02

这里看起来像用了反射,我们点击进去看这个函数

android 热点开发设置可见性 安卓热点开启_反编译_03

的确用了反射,明明有API为啥用反射呢?现在也搞不懂,到底有没有蹊跷现在也不知,然后我再看下在哪里调用这个函数

android 热点开发设置可见性 安卓热点开启_android热点打不开网页_04

很明显这里开启了一个服务,然后在onStartCommand函数里面传递了一个携带参数的intent过来,如果是0就是执行关闭函数,如果是1的话就执行开启热点函数,然后它也重写了这个回调LocalOnlyHotspotCallback

android 热点开发设置可见性 安卓热点开启_android_05

把LOHSService作为构造函数参数传递进去,然后开启热点成功后,执行this.a.a(1, str, wifiConfiguration.preSharedKey);

这个函数,也就是发送携带用户名和密码的广播到其它页面

android 热点开发设置可见性 安卓热点开启_反编译_06

然后我也这样模仿开启一个服务,在服务里面开启热点去测试,配置如下

发现依然不稳定,只不过我开启的时候是用API来开启的,不是用的反射,然后我就采用它的代码,用反射进行开启,效果依然不稳定,说明这里没区别,由于第一次开启热点,非常稳定,第二次开启热点会很不稳定,所以思考是不是由于关闭热点出了问题

if (mReservation != null) {
mReservation.close();
mReservation = null;
}

然后我尝试,不采用中间变量mReservation保存,用反射进行关闭

@TargetApi(Build.VERSION_CODES.M)
public void stopHotPoint(Context context) {
try {
ConnectivityManager manager = (ConnectivityManager) context.getApplicationContext().getSystemService(ConnectivityManager.class);
Method method = manager.getClass().getDeclaredMethod("stopTethering", int.class);
if (method == null) {
} else {
method.invoke(manager, 0);
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (Exception e){
e.printStackTrace();
}
}

这样掉,还需要申请一个修改系统设置的权限,需要通过startActivity去申请,当然

android.permission.WRITE_SETTINGS

当然在AndroidManifest.xml里面也要配置好

android:name="android.permission.WRITE_SETTINGS"
tools:ignore="ProtectedPermissions" />

这样程序才不会奔溃

android 热点开发设置可见性 安卓热点开启_ide_07

然后我们再分析下源码,这里系统会调用finalize方法,内存不够就可能执行,然后里面回调用close方法,然后close里面会调用stopLocalOnlyHotspot()方法,这里就会关闭热点

可能由于内存不够导致不稳定,然后既然开启了热点服务,我们为什么不能在开辟一个进程呢?

然后把服务放在另外一个进程里面,另外一个进程没有太多其它操作,内存一般不会执行Java垃圾回收

然后在单独一个进程开启服务,测试这个热点就非常稳定了,问题也解决了

3 解决办法

再开辟一个新的进程里面开启热点服务

android:process=":aptest">