【问题标题】:How to turn on/off wifi hotspot programmatically in Android 8.0 (Oreo)如何在 Android 8.0 (Oreo) 中以编程方式打开/关闭 wifi 热点
【发布时间】:2018-02-09 13:56:07
【问题描述】:

我知道如何使用以下方法在 android 中使用反射打开/关闭 wifi 热点。

private static boolean changeWifiHotspotState(Context context,boolean enable) {
        try {
            WifiManager manager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
            Method method = manager.getClass().getDeclaredMethod("setWifiApEnabled", WifiConfiguration.class,
                    Boolean.TYPE);
            method.setAccessible(true);
            WifiConfiguration configuration = enable ? getWifiApConfiguration(manager) : null;
            boolean isSuccess = (Boolean) method.invoke(manager, configuration, enable);
            return isSuccess;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

但上述方法不适用于 Android 8.0(Oreo)。

当我在 Android 8.0 中执行上述方法时,我在 logcat 中得到以下语句。

com.gck.dummy W/WifiManager: com.gck.dummy attempted call to setWifiApEnabled: enabled = true

在android 8.0上有没有其他方法可以打开/关闭热点

【问题讨论】:

  • 你要关闭wifi还是热点
  • 我想打开/关闭热点...不是wifi...
  • 他们是否有可能在 Android O 中删除了这种做法?打开 wifi 热点不是 Android sdk 的一部分。所以这种一直在使用反射的方式有点hacky

标签: android android-wifi hotspot android-8.0-oreo


【解决方案1】:

我认为LocalOnlyHotspot 路线是通往的途径,但正如@edsappfactory.com 在 cmets 中所说的那样 - 它只提供封闭网络,无法访问互联网。

在 Oreo 中,热点/网络共享移至 ConnectionManager,其注释为 @SystemApi,因此(名义上)无法访问。

作为我正在做的其他事情的一部分,我制作了一个应用程序并将其放在github here 上。它使用反射来获取函数并使用DexMaker 生成ConnectionManager.OnStartTetheringCallback 的子类(这也是不可访问的)。

认为这一切都很好 - 边缘有点粗糙,所以请随时改进!

相关代码在:

我失去了耐心,试图让我的 DexMaker 生成的回调触发 MyOnStartTetheringCallback,因此所有代码都处于混乱状态并被注释掉。

【讨论】:

  • 嗨!我正在检查您的解决方案,非常棒,效果很好,做得很好。
  • @Jon 它正在工作....你知道如何更改奥利奥热点的名称和通行证吗?
  • @AnujJPandey 最近有人在 GitHub 上问过我这个问题。您必须找到他们将更改 Android 代码中这些设置的方法移动到哪里,并可能尝试使用反射。不要认为它在ConnectionManager。抱歉,帮不上忙。
  • @Jon 感谢您的回复,我找到了解决方案,再次感谢您做出如此出色的工作,经过反思……继续努力。
  • @anujjpandey 太好了。您是否有机会将您的解决方案放在某个地方 - 在 Gist 或 GitHub 中,以便下次被问到时我可以将 ppl 指向它?如果这样更容易,可以提交我原来的 gitgub 代码。
【解决方案2】:

我终于找到了解决方案。 Android 8.0,他们提供了公共 api 来打开/关闭热点。 WifiManager

下面是开启热点的代码

private WifiManager.LocalOnlyHotspotReservation mReservation;

@RequiresApi(api = Build.VERSION_CODES.O)
private void turnOnHotspot() {
    WifiManager manager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);

    manager.startLocalOnlyHotspot(new WifiManager.LocalOnlyHotspotCallback() {

        @Override
        public void onStarted(WifiManager.LocalOnlyHotspotReservation reservation) {
            super.onStarted(reservation);
            Log.d(TAG, "Wifi Hotspot is on now");
            mReservation = reservation;
        }

        @Override
        public void onStopped() {
            super.onStopped();
            Log.d(TAG, "onStopped: ");
        }

        @Override
        public void onFailed(int reason) {
            super.onFailed(reason);
            Log.d(TAG, "onFailed: ");
        }
    }, new Handler());
}

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

onStarted(WifiManager.LocalOnlyHotspotReservation reservation)方法会在热点开启时被调用。使用WifiManager.LocalOnlyHotspotReservation引用你调用close()方法来关闭热点

注意: 要打开热点,应在设备中启用Location(GPS)。否则会抛出SecurityException

【讨论】:

  • 虽然我在设备中启用了位置并在清单文件中添加了权限,但我收到了这个错误“java.lang.SecurityException:UID 10103 没有位置权限”。你添加了什么权限?
  • @JeanCreuzédesChâtelliers 根据文档,应用程序应具有 CHANGE_WIFI_STATE 和 ACCESS_COARSE_LOCATION 权限。在打开热点之前,GPS(位置)应该是打开的。确保已授予上述 2 个权限。
  • 如何使用此方法设置SSID名称?现在我得到类似“AndroidShare_xxxx”
  • 当你想创建一个封闭的网络时这很好。您的热点将无法访问互联网。见 [developer.android.com/reference/android/net/wifi/…, android.os.Handler)]
  • 好的,但是如何通过互联网打开 WiFi 热点?
【解决方案3】:

根据 Jon 的建议,我找到了另一种在 Android Oreo 及更高版本中启用 WifiHotSpot 的方法。

public boolean enableTetheringNew(MyTetheringCallback callback) {
    File outputDir = mContext.getCodeCacheDir();
    try {
        proxy = ProxyBuilder.forClass(classOnStartTetheringCallback())
                .dexCache(outputDir).handler(new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                       switch (method.getName()) {
                            case "onTetheringStarted":
                                callback.onTetheringStarted();
                                break;
                            case "onTetheringFailed":
                                callback.onTetheringFailed();
                                break;
                            default:
                                ProxyBuilder.callSuper(proxy, method, args);
                        }
                        return null;
                    }

                }).build();
    } catch (IOException e) {
        e.printStackTrace();
    }
    ConnectivityManager manager = (ConnectivityManager) mContext.getApplicationContext().getSystemService(ConnectivityManager.class);

    Method method = null;
    try {
        method = manager.getClass().getDeclaredMethod("startTethering", int.class, boolean.class, classOnStartTetheringCallback(), Handler.class);
        if (method == null) {
            Log.e(TAG, "startTetheringMethod is null");
        } else {
            method.invoke(manager, TETHERING_WIFI, false, proxy, null);

        }
        return true;
    } catch (NoSuchMethodException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    } catch (InvocationTargetException e) {
        e.printStackTrace();
    }
    return false;
}

private Class classOnStartTetheringCallback() {
    try {
        return Class.forName("android.net.ConnectivityManager$OnStartTetheringCallback");
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }
    return null;
}

【讨论】:

  • 什么是ProxyBuilder?你的常量声明在哪里?
  • ProxyBuilder 类似于 java.lang.reflect.Proxy 类,但这适用于类而不是接口(java.lang.reflect.Proxy 有效)。
  • 嗨@VishalSharma,这是在奥利奥上工作,在 Tether 之后共享互联网吗?
  • @KanakSony 是的,它可以在几乎所有具有互联网共享功能的奥利奥设备上运行,除了 LGE 设备。
  • 那太好了!请问我能以某种方式获得工作的sn-p吗?
猜你喜欢
  • 2011-09-17
  • 2018-04-01
  • 1970-01-01
  • 2014-11-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多