Android如何通过程序控制开关WiFi热点?

75

有没有一种API可以在Android上通过程序来打开/关闭WiFi热点?

我应该调用哪些方法来打开/关闭WiFi热点?

更新:虽然有一种启用热点并只打开/关闭WiFi的选项,但这对我来说不是一个好的解决方案。


试试这个:http://stackoverflow.com/questions/13946607/android-how-to-turn-on-hotspot-in-android-programmatically - AutonomousApps
6
@mxg,你现在的情况怎样了?问题解决了吗? - gumuruh
@mxg 对于奥利奥操作系统,请参考以下链接 https://dev59.com/pFcO5IYBdhLWcg3wVAE0 - Zar E Ahmer
14个回答

61

警告:此方法在5.0版本之后将无法工作,因为它已经过时。

使用以下类来更改/检查 Wifi 热点设置:

import android.content.*;
import android.net.wifi.*;
import java.lang.reflect.*;

public class ApManager {

//check whether wifi hotspot on or off
public static boolean isApOn(Context context) {
    WifiManager wifimanager = (WifiManager) context.getSystemService(context.WIFI_SERVICE);     
    try {
        Method method = wifimanager.getClass().getDeclaredMethod("isWifiApEnabled");
        method.setAccessible(true);
        return (Boolean) method.invoke(wifimanager);
    }
    catch (Throwable ignored) {}
    return false;
}

// toggle wifi hotspot on or off
public static boolean configApState(Context context) {
    WifiManager wifimanager = (WifiManager) context.getSystemService(context.WIFI_SERVICE);
    WifiConfiguration wificonfiguration = null;
    try {  
        // if WiFi is on, turn it off
        if(isApOn(context)) {               
            wifimanager.setWifiEnabled(false);
        }               
        Method method = wifimanager.getClass().getMethod("setWifiApEnabled", WifiConfiguration.class, boolean.class);                   
        method.invoke(wifimanager, wificonfiguration, !isApOn(context));
        return true;
    } 
    catch (Exception e) {
        e.printStackTrace();
    }       
    return false;
}
} // end of class

你需要在AndroidMainfest中添加以下的权限:

<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />

可以随时在任何地方使用以下独立的ApManager类:

ApManager.isApOn(YourActivity.this); // check Ap state :boolean
ApManager.configApState(YourActivity.this); // change Ap state :boolean

希望这能帮助到某些人


1
你的回答很长,但问题的所有者似乎并不认为它是一个答案@AshishSahu? - gumuruh
2
谢谢。我必须添加以下权限以使其在Android 6上正常工作:<uses-permission android:name="android.permission.WRITE_SETTINGS" /> - Ilya
2
这在Android 6+中不再起作用。请参见此处:https://dev59.com/XJLea4cB1Zd3GeqPzTUm#35504709。请使用ACTION_PICK_WIFI_NETWORK而不是ACTION_SETTINGS。 - KenKenKen
2
@KenKenKen 这是错误的,我刚在 Nexus 5X 上测试了一下,它需要您授予 WRITE_SETTINGS 权限,这需要用户明确接受。 - meow
wificonfiguration这里始终为null,所以我得到了setWifiApEnabled的NoSuchMethodException...我该怎么办? - Jaydeep sinroja
显示剩余3条评论

10
以下是完整的解决方案,如果您想在您的Android应用程序中以编程方式实现wifi热点功能。
API < 26的解决方案:
对于API<26的设备。Android没有为此目的提供公共API。因此,为了使用这些API,您必须通过反射访问私有API。虽然不建议这样做,但如果您没有其他选择,那么这里有一个技巧。
首先,您需要在清单中具有此权限。
  <uses-permission  
  android:name="android.permission.WRITE_SETTINGS"  
  tools:ignore="ProtectedPermissions"/>

  <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
  <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
  <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>

以下是如何在运行时进行询问的方法:

 private boolean showWritePermissionSettings() {    
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M  
    && Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { 
  if (!Settings.System.canWrite(this)) {    
    Log.v("DANG", " " + !Settings.System.canWrite(this));   
    Intent intent = new Intent(android.provider.Settings.ACTION_MANAGE_WRITE_SETTINGS); 
    intent.setData(Uri.parse("package:" + this.getPackageName()));  
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 
    this.startActivity(intent); 
    return false;   
  } 
}   
return true; //Permission already given 
}

然后,您可以通过反射访问setWifiEnabled方法。如果您要求的操作(例如启用/禁用热点)正在正确处理,则此方法返回true。

     public boolean setWifiEnabled(WifiConfiguration wifiConfig, boolean enabled) { 
 WifiManager wifiManager;
try {   
  if (enabled) { //disables wifi hotspot if it's already enabled    
    wifiManager.setWifiEnabled(false);  
  } 

   Method method = wifiManager.getClass()   
      .getMethod("setWifiApEnabled", WifiConfiguration.class, boolean.class);   
  return (Boolean) method.invoke(wifiManager, wifiConfig, enabled); 
} catch (Exception e) { 
  Log.e(this.getClass().toString(), "", e); 
  return false; 
}   
}

您也可以通过反射获取热点的wifi配置。我已经在StackOverflow上回答了这个问题的方法answered
P.S:如果您不想以编程方式打开热点,您可以启动此intent并打开wifi设置屏幕,让用户手动打开它。
API >= 26的解决方案:
最后,安卓发布了一个官方的API,适用于版本>= Oreo。您只需使用Android公开的API即可startLocalOnlyHotspot
它会打开一个没有互联网访问权限的本地热点。因此可以用来托管服务器或传输文件。
它需要Manifest.permission.CHANGE_WIFI_STATE和ACCESS_FINE_LOCATION权限。
以下是如何使用此API打开热点的简单示例。
private WifiManager wifiManager;
WifiConfiguration currentConfig;
WifiManager.LocalOnlyHotspotReservation hotspotReservation;

打开热点的方法:

@RequiresApi(api = Build.VERSION_CODES.O)
public void turnOnHotspot() {

      wifiManager.startLocalOnlyHotspot(new WifiManager.LocalOnlyHotspotCallback() {

        @Override
        public void onStarted(WifiManager.LocalOnlyHotspotReservation reservation) {
          super.onStarted(reservation);
          hotspotReservation = reservation;
          currentConfig = hotspotReservation.getWifiConfiguration();

          Log.v("DANG", "THE PASSWORD IS: "
              + currentConfig.preSharedKey
              + " \n SSID is : "
              + currentConfig.SSID);

          hotspotDetailsDialog();

        }

        @Override
        public void onStopped() {
          super.onStopped();
          Log.v("DANG", "Local Hotspot Stopped");
        }

        @Override
        public void onFailed(int reason) {
          super.onFailed(reason);
          Log.v("DANG", "Local Hotspot failed to start");
        }
      }, new Handler());
    }
`

这里是如何获取本地创建的热点详细信息。
private void hotspotDetaisDialog()
{

    Log.v(TAG, context.getString(R.string.hotspot_details_message) + "\n" + context.getString(
              R.string.hotspot_ssid_label) + " " + currentConfig.SSID + "\n" + context.getString(
              R.string.hotspot_pass_label) + " " + currentConfig.preSharedKey);

}

如果即使您已授予所需权限,仍然抛出安全异常,则应尝试使用GPS启用位置。这里是solution
最近,我开发了一个名为Spotserve的演示应用程序。它可以为所有API> = 15的设备打开wifi热点,并在该热点上托管演示服务器。您可以查看此内容以获取更多详细信息。希望这有所帮助!

1
如何在应用程序内连接到本地热点,并设置特定的SSID和密码。 - Karan Malhotra
可以为特定设备关闭热点吗? - Dinith
API >= 26的方法可行,但我需要先初始化wifiManager:wifiManager = (WifiManager) this.getSystemService(this.WIFI_SERVICE); - Filip Kubicz
@AdeelZafar,使用startLocalOnlyHotspot方法,是否有办法配置SSID和密码? - undefined

4

警告:该方法在5.0以上版本不起作用,它已经过时。

您可以使用以下代码以编程方式启用、禁用和查询WiFi Direct状态。

package com.kusmezer.androidhelper.networking;

import java.lang.reflect.Method;
import com.google.common.base.Preconditions;
import android.content.Context;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
import android.util.Log;

public final class WifiApManager {
      private static final int WIFI_AP_STATE_FAILED = 4;
      private final WifiManager mWifiManager;
      private final String TAG = "Wifi Access Manager";
      private Method wifiControlMethod;
      private Method wifiApConfigurationMethod;
      private Method wifiApState;

      public WifiApManager(Context context) throws SecurityException, NoSuchMethodException {
       context = Preconditions.checkNotNull(context);
       mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
       wifiControlMethod = mWifiManager.getClass().getMethod("setWifiApEnabled", WifiConfiguration.class,boolean.class);
       wifiApConfigurationMethod = mWifiManager.getClass().getMethod("getWifiApConfiguration",null);
       wifiApState = mWifiManager.getClass().getMethod("getWifiApState");
      }   
      public boolean setWifiApState(WifiConfiguration config, boolean enabled) {
       config = Preconditions.checkNotNull(config);
       try {
        if (enabled) {
            mWifiManager.setWifiEnabled(!enabled);
        }
        return (Boolean) wifiControlMethod.invoke(mWifiManager, config, enabled);
       } catch (Exception e) {
        Log.e(TAG, "", e);
        return false;
       }
      }
      public WifiConfiguration getWifiApConfiguration()
      {
          try{
              return (WifiConfiguration)wifiApConfigurationMethod.invoke(mWifiManager, null);
          }
          catch(Exception e)
          {
              return null;
          }
      }
      public int getWifiApState() {
       try {
            return (Integer)wifiApState.invoke(mWifiManager);
       } catch (Exception e) {
        Log.e(TAG, "", e);
            return WIFI_AP_STATE_FAILED;
       }
      }
}

@ldce 反射不是一个API。此外,我在Nexus 5上使用Lollipop测试过它,仍然可以工作。 - Divers
@Divers 它在Nexus 5上使用Lollipop可以工作吗?但是在我的AT&T S6 Lollipop 5.1.1上无法工作。 - vman
可能是在新版本中将其删除了。 - Kerem Kusmezer
你为什么要发布一个使用第三方库com.google.common.base.Preconditions;的示例? - user924
这是一个相当陈旧的条目,基本上它将无法与新版本一起使用。 - Kerem Kusmezer

4

针对 Android 8.0,有一个新的 API 用于处理热点。据我所知,旧的使用反射的方法已经不再起作用。

请参考:

Android 开发者文档 https://developer.android.com/reference/android/net/wifi/WifiManager.html#startLocalOnlyHotspot(android.net.wifi.WifiManager.LocalOnlyHotspotCallback,%20android.os.Handler)

void startLocalOnlyHotspot (WifiManager.LocalOnlyHotspotCallback callback, 
                Handler handler)

请求创建一个本地热点,应用程序可以使用该热点在连接到的设备之间进行通信。此方法创建的网络将没有互联网访问权限。
Stack Overflow 如何在Android 8.0(Oreo)中以编程方式打开/关闭wifi热点 当热点被打开时,将调用onStarted(WifiManager.LocalOnlyHotspotReservation reservation)方法。使用WifiManager.LocalOnlyHotspotReservation引用,您可以调用close()方法关闭热点。

3

仅适用于Oreo+...

我使用反射和DexMaker编写了一个应用程序,代码在这里的GitHub上,该应用程序可以“获取”Oreo的网络共享功能,现在这个功能在ConnectionManager中,而不是WifiManager中。

WifiManager中的内容仅适用于封闭的wifi网络(这就解释了类名称中的Closed位!)。

更多解释请参见https://dev59.com/pFcO5IYBdhLWcg3wVAE0#49356255


2

这对我很有效:

WifiConfiguration apConfig = null;
Method method = wifimanager.getClass().getMethod("setWifiApEnabled", WifiConfiguration.class, Boolean.TYPE);
method.invoke(wifimanager, apConfig, true);

1
如果这是打开Wifi热点的方法,那么...如何关闭它呢? - gumuruh
1
这个功能只能在Android 4.4及以下版本中使用。从Android 5.0及以上版本开始,它无法连接到热点。 - Harish

2

APManager - Access Point Manager

allprojects {
    repositories {
        ...
        jcenter()
    }
}

dependencies {
    implementation 'com.vkpapps.wifimanager:APManager:1.0.0'
}

APManager apManager = APManager.getApManager(this);
apManager.turnOnHotspot(this, new APManager.OnSuccessListener() {

    @Override
    public void onSuccess(String ssid, String password) {
        //write your logic
    }

}, new APManager.OnFailureListener() {

    @Override
    public void onFailure(int failureCode, @Nullable Exception e) {
        //handle error like give access to location permission,write system setting permission,
        //disconnect wifi,turn off already created hotspot,enable GPS provider
        
        //or use DefaultFailureListener class to handle automatically
    }

});

查看源代码 https://github.com/vijaypatidar/AndroidWifiManager


1
这将创建热点,但不会共享移动数据的互联网连接。 - Krunal Shah
1
我喜欢这个答案 <3 - Abhinav Gupta
@KrunalShah 这个库在内部使用了适用于 Android 8.0+ 的 LocalHotspot API,但这个API不允许共享网络。 - Vijay Patidar

1

不打开/关闭WiFi,这是可能的吗? - mxg
可能仍需要使用WifiManager类。请参考此SO问题:https://dev59.com/g3A75IYBdhLWcg3w794Y(我认为这是你最好的选择。) - joshhendo
他谈论的是WiFi热点,而不仅仅是WiFi。 - user924

1
我已经发布了一些非官方的API,其中包含的不仅仅是热点开关on/off链接 有关API文档,请参阅链接

1
请注意,提供的 API 是用于设备作为客户端连接到 AP 的情况,而 OP 正在寻找控制内置 AP 的方法。 - jcaron

0
我们可以通过编程来开启和关闭。
setWifiApDisable.invoke(connectivityManager, TETHERING_WIFI);//Have to disable to enable
setwifiApEnabled.invoke(connectivityManager, TETHERING_WIFI, false, mSystemCallback,null);

使用回调类,在Pie(9.0)中以编程方式打开热点,您需要先以编程方式关闭,然后再打开开关。


请提供您在此处添加的代码的更多信息。 - Vishal Sharma

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接