用过360的面对面快传,快牙的朋友应该都知道,它们在两台设备间实现文件传输都是通过WiFi热点实现的,下面我们就来探讨一下如何设置热点名和密码,并自动创建一个wifi热点吧,以及如何监听热点的打开与关闭。


一、创建WiFi热点

其实创建热点很简单,先获取到wifi的服务,再配置热点名称、密码等等,然后再通过反射打开它就OK了,需要注意的是手机的WiFi连接与热点是不可同时打开的,也就是说如果手机连上了一个现有WiFi,就无法打开自身热点,反之亦然。所以在打开热点是先判断WiFi是否打开,如果打开则先关闭WiFi,然后再根据设定的热点名和密码创建热点。废话少说,直接上代码:


package com.wjj.wifihotmanager;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import android.content.Context;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
  
/**
 * @ClassName:  WifiHotUtil   
 * @Description:  打印日志信息WiFi热点工具
 * @author: jajuan.wang  
 * @date:   2015-05-28 15:12  
 * version:1.0.0
 */   
public class WifiHotUtil {  
    public static final String TAG = "WifiApAdmin";  
      
    private WifiManager mWifiManager = null;  
    
    private Context mContext = null;  
    public WifiHotUtil(Context context) {  
        mContext = context;  
        mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
    }  
    
    public void startWifiAp(String ssid, String passwd) 
    {  
        //wifi和热点不能同时打开,所以打开热点的时候需要关闭wifi
        if (mWifiManager.isWifiEnabled()) {  
            mWifiManager.setWifiEnabled(false);  
        }   

        if (!isWifiApEnabled()) {
            stratWifiAp(ssid, passwd); 
        } 
    }  
  
    /**
     * 设置热点名称及密码,并创建热点
     * @param mSSID
     * @param mPasswd
     */
    private void stratWifiAp(String mSSID, String mPasswd) {  
        Method method1 = null;  
        try {  
        	//通过反射机制打开热点
            method1 = mWifiManager.getClass().getMethod("setWifiApEnabled", WifiConfiguration.class, boolean.class);  
            WifiConfiguration netConfig = new WifiConfiguration();  
  
            netConfig.SSID = mSSID;  
            netConfig.preSharedKey = mPasswd;  
  
            netConfig.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);  
            netConfig.allowedProtocols.set(WifiConfiguration.Protocol.RSN);  
            netConfig.allowedProtocols.set(WifiConfiguration.Protocol.WPA);  
            netConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);  
            netConfig.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);  
            netConfig.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP);  
            netConfig.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);  
            netConfig.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);  
            method1.invoke(mWifiManager, netConfig, true);  
  
        } catch (IllegalArgumentException e) {  
            e.printStackTrace();  
        } catch (IllegalAccessException e) {  
            e.printStackTrace();  
        } catch (InvocationTargetException e) {  
            e.printStackTrace();  
        } catch (SecurityException e) {  
            e.printStackTrace();  
        } catch (NoSuchMethodException e) {  
            e.printStackTrace();  
        }
    }  
  
  
    /**
     * 热点开关是否打开
     * @return
     */
    public boolean isWifiApEnabled() {  
        try {  
            Method method = mWifiManager.getClass().getMethod("isWifiApEnabled");  
            method.setAccessible(true);  
            return (Boolean) method.invoke(mWifiManager);  
        } catch (NoSuchMethodException e) {  
            e.printStackTrace();  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
        return false;  
    }  
    
    /**
     * 关闭WiFi热点
     */
    public void closeWifiAp() {  
        WifiManager wifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);   
        if (isWifiApEnabled()) {  
            try {  
                Method method = wifiManager.getClass().getMethod("getWifiApConfiguration");  
                method.setAccessible(true);  
                WifiConfiguration config = (WifiConfiguration) method.invoke(wifiManager);  
                Method method2 = wifiManager.getClass().getMethod("setWifiApEnabled", WifiConfiguration.class, boolean.class);  
                method2.invoke(wifiManager, config, false);  
            } catch (NoSuchMethodException e) {  
                e.printStackTrace();  
            } catch (IllegalArgumentException e) {  
                e.printStackTrace();  
            } catch (IllegalAccessException e) {  
                e.printStackTrace();  
            } catch (InvocationTargetException e) {  
                e.printStackTrace();  
            }  
        } 
    }
  
}




调用方式:在activity中:


//实例化WiFi热点工具类
wifiHotUtil = new WifiHotUtil(this);
//创建热点
wifiHotUtil.startWifiAp(defaultHotName, defaultHotPwd);
//关闭热点
wifiHotUtil.closeWifiAp();



二、监听热点的打开与关闭

经过查找资料发现,android的便携式热点打开与关闭都会发出 android.net.wifi.WIFI_AP_STATE_CHANGED 的广播,但是便携式热点相关的信息在WiFimanage中是隐藏的,这个广播是隐藏的。那我们怎么监听呢?好不容易在stackoverflow上找到了解决办法,连接地址:Monitoring the Hotspot state in Android,实现代码如下:


private BroadcastReceiver wifiReceiver = new BroadcastReceiver(){
        public void onReceive(Context context, Intent intent) {
        	String action = intent.getAction();
            if ("android.net.wifi.WIFI_AP_STATE_CHANGED".equals(action)) {
            	//便携式热点的状态为:10---正在关闭;11---已关闭;12---正在开启;13---已开启
                int state = intent.getIntExtra("wifi_state",  0);
                Log.i(TAG, "state= "+state);
                wiFiAPObserver.stateChanged(state);
            }
        }
};

注册这个广播监听器,就可以监听热点的打开与关闭状态了。



我使用的是服务+观察者模式,应用启动时启动热点监听服务,用于监听热点打开与关闭的状态。activity或其他需要获取热点状态的地方可以通过服务注册监听器,当热点状态改变时会遍历通知每个注册的实例。上代码:


package com.wjj.wifihotmanager;

import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.IBinder;
import android.util.Log;

/**
 * @ClassName:  WiFiAPService   
 * @Description:  wifi hot manage service
 * @author: jajuan.wang  
 * @date:   2015-06-09 00:43  
 * version:1.0.0
 */
public class WiFiAPService extends Service {
	
	private static String TAG = "WiFiAPService";
	
	public static String ACTION_START_SERVICE = "action_start_service";
	public static String ACTION_STOP_SERVICE = "action_stop_service";
	private static WiFiAPObserver wiFiAPObserver = new WiFiAPObserver();
	
	
	/**
	 * static method to start service
	 * @param context
	 */
	public static void startService(Context context) {
		Intent intent = new Intent(context, WiFiAPService.class);
		intent.setAction(ACTION_START_SERVICE);
		context.startService(intent);
	}
	
	/**
	 * static method to stop service
	 * @param context
	 */
	public static void stopService(Context context) {
		Intent intent = new Intent(context, WiFiAPService.class);
		intent.setAction(ACTION_STOP_SERVICE);
		context.startService(intent);
	}
	
	
	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		super.onStartCommand(intent, flags, startId);
		Log.i(TAG, "intent.getAction()="+intent.getAction());
		// option based on action
		if (intent.getAction().equals(ACTION_START_SERVICE) == true) {
			//startService();
		} else if (intent.getAction().equals(ACTION_STOP_SERVICE) == true) {
			stopSelf();
		} 
		//重传Intent。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统会自动重启该服务,并将Intent的值传入。
		return Service.START_REDELIVER_INTENT;
	}
	
	@Override
	public void onCreate() {
		registerReceiver(wifiReceiver,new IntentFilter("android.net.wifi.WIFI_AP_STATE_CHANGED"));
		super.onCreate();
	}
	
	
	
	@Override
	public void onDestroy() {
		unregisterReceiver(wifiReceiver);
		wiFiAPObserver.clearWiFiAPListener();
		super.onDestroy();
	}
	
	/**
	 * register wiFiAPListener
	 * @param wiFiAPListener
	 */
	public static void addWiFiAPListener(WiFiAPListener wiFiAPListener) {
		wiFiAPObserver.addWiFiAPListener(wiFiAPListener);
	}
	
	/**
	 * remove wiFiAPListener
	 * @param wiFiAPListener
	 */
	public static void removeWiFiAPListener(WiFiAPListener wiFiAPListener) {
		wiFiAPObserver.removeWiFiAPListener(wiFiAPListener);
	}


	private BroadcastReceiver wifiReceiver = new BroadcastReceiver(){
        public void onReceive(Context context, Intent intent) {
        	String action = intent.getAction();
            if ("android.net.wifi.WIFI_AP_STATE_CHANGED".equals(action)) {
            	//便携式热点的状态为:10---正在关闭;11---已关闭;12---正在开启;13---已开启
                int state = intent.getIntExtra("wifi_state",  0);
                Log.i(TAG, "state= "+state);
                wiFiAPObserver.stateChanged(state);
            }
        }
	};

	@Override
	public IBinder onBind(Intent intent) {
		// TODO Auto-generated method stub
		return null;
	}

}

热点监听器:

package com.wjj.wifihotmanager;

/**
 * @ClassName:  WiFiAPListener   
 * @Description:  Listenning the state of wifi hot
 * @author: jajuan.wang  
 * @date:   2015-06-09 00:52  
 * version:1.0.0
 */
public interface WiFiAPListener {
	
    public static final int WIFI_AP_CLOSEING 		= 10;  //wifi hot is closeing
    public static final int WIFI_AP_CLOSE_SUCCESS 	= 11;  //wifi hot close success
    public static final int WIFI_AP_OPENING 		= 12;  //WiFi hot is opening 
    public static final int WIFI_AP_OPEN_SUCCESS 	= 13;  //WiFi hot open success

	/**
	 * the state of wifi hot changed
	 * @param state
	 */
	public void stateChanged(int state) ;
}

热点状态观察者:

package com.wjj.wifihotmanager;

import java.util.HashSet;

/**
 * @ClassName:  WiFiAPObserver   
 * @Description:  Listenning the state of wifi hot
 * @author: jajuan.wang  
 * @date:   2015-06-09 00:58  
 * version:1.0.0
 */
public class WiFiAPObserver implements WiFiAPListener {
	
	/**
	 * the set to save all registed listener
	 */
	private HashSet<WiFiAPListener> listenerSet = new HashSet<WiFiAPListener>();
	
	/**
	 * add wiFiAPListener
	 * @param wiFiAPListener
	 */
	public void addWiFiAPListener(WiFiAPListener wiFiAPListener) {
		if (!listenerSet.contains(wiFiAPListener)) {
			listenerSet.add(wiFiAPListener);
		}
	}
	
	/**
	 * remove the wiFiAPListener
	 * @param wiFiAPListener
	 */
	public void removeWiFiAPListener(WiFiAPListener wiFiAPListener) {
		if (listenerSet.contains(wiFiAPListener)) {
			listenerSet.remove(wiFiAPListener);
		}
	}
	
	/**
	 * remove all WiFiAPListener
	 */
	public void clearWiFiAPListener() {
		listenerSet.clear();
	}

	@Override
	public void stateChanged(int state) {
		//notify all Listener the state changed 
		for (WiFiAPListener wiFiAPListener : listenerSet) {
			wiFiAPListener.stateChanged(state);
		}
	}

}