android 熱點開發、WiFi熱點通訊
阿新 • • 發佈:2019-02-17
對於熱點。我們需要能夠開啟和關閉,自己設定熱點名和密碼以及鎖的型別。然後呢,還要能夠獲取連線此熱點的裝置資訊。關於熱點,沒有找到相應的操作類,查閱資料後得知要用method反射機制來實現。反射機制不瞭解的自行百度。下面直接貼上相關程式碼及解析
關於監聽熱點狀態,它是有一個廣播的,通過這個廣播就可以監聽到了熱點開關的實時狀態public class Mywifiap { private static final int NO_PASS=0; private static final int WPA_PSK=1; private static final int WPA2_PSK=2; private WifiManager wifiManager; private WifiConfiguration apconfig; public Mywifiap(Context context) { wifiManager= (WifiManager) context.getSystemService(Context.WIFI_SERVICE); } //開啟熱點 public void openwifiap(String name,String password,int type){ if(wifiManager.isWifiEnabled()) wifiManager.setWifiEnabled(false);//如果WiFi是開啟的就關閉WiFi。 apconfig=new WifiConfiguration(); apconfig.SSID=name;//設定WiFi名字 //熱點相關設定 switch (type){ case NO_PASS: apconfig.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN); apconfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); apconfig.wepKeys[0]=""; apconfig.wepTxKeyIndex=0; break; case WPA_PSK: apconfig.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN); apconfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK); apconfig.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP); apconfig.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP); apconfig.allowedProtocols.set(WifiConfiguration.Protocol.WPA); apconfig.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP); apconfig.preSharedKey=password; break; case WPA2_PSK: //由於wpa2是不能直接訪問的,但是KeyMgmt中卻有。所以我們這樣寫 for(int i=0;i<WifiConfiguration.KeyMgmt.strings.length;i++){ if("WPA2_PSK".equals(WifiConfiguration.KeyMgmt.strings[i])) { apconfig.allowedKeyManagement.set(i);//直接給它賦索引的值 Log.e("wpa2索引", String.valueOf(i));//不同手機索引不同 } } apconfig.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN); apconfig.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP); apconfig.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP); apconfig.allowedProtocols.set(WifiConfiguration.Protocol.WPA); apconfig.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP); apconfig.preSharedKey=password; break; } try { Method method=wifiManager.getClass().getMethod("setWifiApEnabled",WifiConfiguration.class,boolean.class); method.invoke(wifiManager,apconfig,true); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } //關閉熱點 public void closewifiap(){ try { // Method method1=wifiManager.getClass().getMethod("getWifiApConfiguration"); // method1.setAccessible(true); // WifiConfiguration nowconfig= (WifiConfiguration) method1.invoke(wifiManager);//獲取當前熱點 Method method=wifiManager.getClass().getMethod("setWifiApEnabled",WifiConfiguration.class,boolean.class); method.invoke(wifiManager,apconfig,false); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } } //獲取連線列表 public StringBuffer getconnectlist(){ /* 連線裝置的資訊都存在一個檔案裡面,讀這個檔案獲取資訊 讀取檔案後每為這樣的格式,每連線一個裝置增加一行,沒有連線時只有一行 IP address HW type Flags HW address Mask Device 192.168.43.115 0x1 0x2 c4:0b:cb:8a:4c:f1 * ap0 192.168.43.115 0x1 0x2 c4:0b:cb:8a:4c:f1 * ap0 */ StringBuffer sb=new StringBuffer(); try { BufferedReader br=new BufferedReader(new FileReader("/proc/net/arp")); String line; while((line=br.readLine())!=null){ Log.e("連線列表",line); sb.append(line+"\n"); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return sb; } }
然後來說說WiFi、熱點通訊,其實WiFi連線熱點後,他們就在一個區域網中了,也就是說,他們可以通過socket來通訊。然後就要在原來的基礎上加上聯網許可權。public class ApReceiver extends BroadcastReceiver{ @Override public void onReceive(Context context, Intent intent) { String action=intent.getAction(); if("android.net.wifi.WIFI_AP_STATE_CHANGED".equals(action)){ //"android.net.wifi.WIFI_AP_STATE_CHANGED"這個是熱點狀態改變的廣播 int state=intent.getIntExtra("wifi_state",0); Log.e("熱點狀態", String.valueOf(state)); /* state: 12:正在開啟熱點 13:已開啟熱點 10:正在關閉熱點 11:已關閉熱點 */ } } }
既然用socket,埠可以自己設但是客戶端必須要知道服務端的IP地址才能通訊,所以,在之前WiFi開發的類上加上獲取服務端IP的方法。<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"></uses-permission> <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"></uses-permission> <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"></uses-permission> <uses-permission android:name="android.permission.INTERNET"></uses-permission>
//獲取連線熱點的IP地址
public static String getserverip(Context context){
WifiManager manager= (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
DhcpInfo dhcpInfo=manager.getDhcpInfo();
int ip=dhcpInfo.serverAddress;
//整形轉化為IP地址
String sip=(ip&0xff)+"."+((ip>>8)&0xff)+"."+((ip>>16)&0xff)+"."+((ip>>24)&0xff);
Log.e("伺服器IP",sip);
return sip;
}
客戶(WiFi)端的socket程式碼
public class WifiSocket extends AppCompatActivity{
private EditText msg;
private Button putmsg;
private OutputStream out;
Handler handler=new Handler(){
@Override
public void handleMessage(Message msg) {
if(msg.what==1){
Toast.makeText(WifiSocket.this, (String) msg.obj,Toast.LENGTH_SHORT).show();
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.wifisocket);
msg= (EditText) findViewById(R.id.msg);
putmsg= (Button) findViewById(R.id.putmsg);
putmsg.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
//傳送訊息
out.write(msg.getText().toString().getBytes());
} catch (IOException e) {
e.printStackTrace();
}
}
});
thread();
}
public void thread(){
final String ip=Mywifi.getserverip(WifiSocket.this);
final int port=1234;
new Thread(){
@Override
public void run() {
try {
Socket socket=new Socket(ip,port);
Log.e("wifisocket","建立連線");
InputStream in=socket.getInputStream();
out=socket.getOutputStream();
//接收訊息
while (true){
byte[] buffer=new byte[1024];
int len=0;
if((len=in.read(buffer))!=-1){
byte[] data=new byte[len];
for(int i=0;i<data.length;i++)
data[i]=buffer[i];
String msg=new String(data);
Log.e("收到訊息",msg);
Message message=new Message();
message.what=1;
message.obj=msg;
handler.sendMessage(message);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}.start();
}
}
服務(熱點)端的socket程式碼
public class Server extends Thread{
public ServerSocket serverSocket;
public Socket socket;
public static final int PORT=1234;
public Context context;
public Handler handler;
public Server(Context context,Handler handler){
this.context=context;
this.handler=handler;
}
@Override
public void run() {
try {
serverSocket=new ServerSocket(PORT);
Log.e("wifi伺服器","已開啟");
socket=serverSocket.accept();
Log.e("wifi伺服器","裝置已連線");
InputStream in=socket.getInputStream();
OutputStream out=socket.getOutputStream();
//接收到訊息後,馬上傳送一條訊息
while(true){
byte[] buffer=new byte[1024];
int len=0;
if((len=in.read(buffer))!=-1){
byte[] data=new byte[len];
for(int i=0;i<data.length;i++)
data[i]=buffer[i];
String msg=new String(data);
Log.e("收到訊息",msg);
//通過handle來彈出Toast。
Message message=new Message();
message.obj=msg;
message.what=1;
handler.sendMessage(message);
//傳送訊息
out.write("對方已接收訊息".getBytes());
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
注意:這個專案在6.0以下裝置有限,在6.0及以上裝置,會丟擲一個沒有授權讀寫系統設定的異常,因為6.0是裝置,隱私許可權必須動態獲取,開關熱點等屬於隱私許可權必須在程式碼裡動態獲取。如果是6.0及以上裝置,那就自己加幾行動態獲取許可權的程式碼