MainActivity.java:
package itant.com.wificlient;
import android.content.Context;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
import android.os.AsyncTask;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.List;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private TextView tv_status;
private TextView tv_content;
// 10秒扫描一次
private static final int WAIT_FOR_SCAN_RESULT = 5 * 1000;
// 20秒之内没有得到扫描结果就不要再扫描了
private static final int WIFI_SCAN_TIMEOUT = 200 * 1000;
private static final int CONNECT_SERVER_SUC = 1;
private static final int RECEIVED_MSG = 2;
private Socket mClientSocket;
private WifiManager mWifiManager;
private Handler mConnectHotSpotHandler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
switch (msg.what) {
case CONNECT_SERVER_SUC:
//Toast.makeText(MainActivity.this, "连接成功", Toast.LENGTH_SHORT).show();
tv_status.setText("连接成功");
// WiFi连接成功,开socket客户端去连接服务器以接收文件
final String serverIP = HttpTools.getSenderIP(mWifiManager);
new Thread(new Runnable() {
@Override
public void run() {
connectTCPServer(serverIP);
}
}).start();
break;
case RECEIVED_MSG:
tv_content.setText(msg.obj.toString());
break;
default:
//Toast.makeText(MainActivity.this, "连接失败", Toast.LENGTH_SHORT).show();
break;
}
return true;
}
});
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv_status = (TextView) findViewById(R.id.tv_status);
tv_content = (TextView) findViewById(R.id.tv_content);
findViewById(R.id.btn_connect).setOnClickListener(this);
findViewById(R.id.btn_send).setOnClickListener(this);
mWifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.btn_connect:
// 搜索并连接我们APP创建的热点
if (mWifiManager != null) {
mWifiManager.setWifiEnabled(false);
}
new ConnectTask().execute();
break;
case R.id.btn_send:
if (mClientSocket != null) {
/*try {
String str = "I am client";
PrintWriter out = new PrintWriter(new BufferedWriter(
new OutputStreamWriter(mClientSocket.getOutputStream())),
true);
out.println(str);
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}*/
// 发送信息
/*String str = "hello server --客户端";
try {
DataOutputStream mOutputStream = new DataOutputStream(mClientSocket.getOutputStream());
// 把文件名告诉服务端
//mOutputStream.writeUTF(app.getAppName() + ".apk");
//mOutputStream.flush();
// 把长度诉服务端,否则不知道一个文件结尾在哪
mOutputStream.writeLong(str.length());
mOutputStream.flush();
DataInputStream inputStream = new DataInputStream(
new ByteArrayInputStream(str.getBytes("UTF-8")));
byte buf[] = new byte[1024];
int len = -1;
while ((len = inputStream.read(buf)) != -1) {
mOutputStream.write(buf, 0, len);
}
mOutputStream.flush();
inputStream.close();
// 发送结束了
} catch (IOException e1) {
e1.printStackTrace();
}*/
String str = "hello server --客户端";
try {
DataOutputStream mOutputStream = new DataOutputStream(mClientSocket.getOutputStream());
// 把文件名告诉服务端
//mOutputStream.writeUTF(app.getAppName() + ".apk");
//mOutputStream.flush();
byte[] strBytes = str.getBytes("UTF-8");
// 把长度诉服务端,否则不知道一个文件结尾在哪。千万不要直接传str.length()!!!因为我们采用的
// 是UTF-8编码,其长度是有所区别的,如果直接传str.length()很可能会导致传递的数据不完整!
//mOutputStream.writeLong(str.length());
mOutputStream.writeLong(strBytes.length);
mOutputStream.flush();
DataInputStream inputStream = new DataInputStream(
new ByteArrayInputStream(strBytes));
byte buf[] = new byte[1024];
int len = -1;
while ((len = inputStream.read(buf)) != -1) {
mOutputStream.write(buf, 0, len);
}
mOutputStream.flush();
inputStream.close();
// 发送结束了
} catch (IOException e1) {
e1.printStackTrace();
}
Toast.makeText(this, "发送完毕", Toast.LENGTH_SHORT).show();
}
break;
}
}
/**
* 连接特定热点
* @param passwd 密码
*/
private void connectToHotSpot(String passwd, int type) {
// 关闭热点
HttpTools.setWifiApEnabled(mWifiManager, null, false);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 打开WiFi
mWifiManager.setWifiEnabled(true);
List<ScanResult> scanResults = mWifiManager.getScanResults();
if (scanResults == null) {
// 如果没有可用的扫描结果,激活扫描
mWifiManager.startScan();
boolean isScanResultIsAvailable = false;
long startTime = System.currentTimeMillis();
while (!isScanResultIsAvailable) {
if ((System.currentTimeMillis() - startTime) > WIFI_SCAN_TIMEOUT) {
// 20秒之内还没搜到可用热点就不要再搜了
return;
}
// 等待扫描结果,等5秒之后查看结果
synchronized (this) {
try {
this.wait(WAIT_FOR_SCAN_RESULT);
} catch (InterruptedException e) {
e.printStackTrace();
}
if ((mWifiManager.getScanResults() == null) || (mWifiManager.getScanResults().size() <= 0)) {
continue;
}
isScanResultIsAvailable = true;
}
}
}
// 获取扫描结果(代码能走到这里一定有结果了)
scanResults = mWifiManager.getScanResults();
for (ScanResult scanResult : scanResults) {
// 如果当前这个热点是我们想要连接的热点,那么就连接它
if (scanResult.SSID.startsWith("backup")) {
final String ssid = "\"" + scanResult.SSID + "\"";
WifiConfiguration wifiConfiguration = HttpTools.createWifiInfo(ssid, passwd, type);
int networkId = mWifiManager.addNetwork(wifiConfiguration);
// 连接特定热点,并断开其他连接
mWifiManager.enableNetwork(networkId, true);
mWifiManager.saveConfiguration();
//mWifiManager.disconnect();
mWifiManager.reconnect();
// 开一个线程去轮询连接情况
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
if (HttpTools.isWiFiConnected(MainActivity.this)) {
// 已经连接上的热点真的是我们想要连接的热点
if (TextUtils.equals(ssid, HttpTools.getConnectedWifiSsid(mWifiManager))) {
mConnectHotSpotHandler.sendEmptyMessage(CONNECT_SERVER_SUC);
break;
}
} else {
// 当前连接的WiFi不是我们想要的,重新连接
connectToHotSpot("away6899", HttpTools.TYPE_WPA);
}
// 割两秒去查一下是否已经连上了WiFi
try {
Thread.sleep(2000);
} catch (Exception e) {
// TODO: handle exception
}
}
}
}).start();
break;
} else {
// 不是我们的热点就断开连接
//mWifiManager.disconnect();
}
}
}
/**
* 后台搜索并连接热点
* @author 詹子聪
*/
private class ConnectTask extends AsyncTask<Void, Void, Void> {
@Override
protected Void doInBackground(Void... params) {
// TODO Auto-generated method stub
connectToHotSpot("away6899", HttpTools.TYPE_WPA);
return null;
}
@Override
protected void onPostExecute(Void result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
}
}
/**
* 连接服务器,从服务器接收应用
*
* @param serverIP
*/
private void connectTCPServer(String serverIP) {
Socket socket = null;
while (socket == null) {
try {
socket = new Socket(serverIP, 8688);
mClientSocket = socket;
} catch (IOException e) {
SystemClock.sleep(1000);
System.out.println("connect tcp server failed, retry...");
}
}
try {
// 接收服务器端的消息和文件
DataInputStream inputStream = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
// 不断地监听,看服务器是否有东西过来
while (!MainActivity.this.isFinishing()) {
//String fileName = inputStream.readUTF();
long fileSize = inputStream.readLong();
ByteArrayOutputStream out = new ByteArrayOutputStream();
DataOutputStream outputStream = new DataOutputStream(
new BufferedOutputStream(out));
byte[] buffer = new byte[(int) fileSize];
int nIdx = 0;
int nTotalLen = buffer.length;
int nReadLen = 0;
while (nIdx < nTotalLen) {
// 从nIdx开始,想读nTotalLen - nIdx那么多,实际上这次读了nReadLen
nReadLen = inputStream.read(buffer, nIdx, nTotalLen - nIdx);
if (nReadLen > 0) {
outputStream.write(buffer, nIdx, nReadLen);
nIdx = nIdx + nReadLen;
} else {
break;
}
}
outputStream.close();
String str = out.toString();
Message message = Message.obtain();
message.obj = str;
message.what = RECEIVED_MSG;
mConnectHotSpotHandler.sendMessage(message);
}
System.out.println("quit...");
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mClientSocket != null) {
try {
mClientSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/tv_status"
android:text="未连接"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/tv_content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/btn_connect"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="连接服务器"/>
<Button
android:id="@+id/btn_send"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="发送"
android:layout_marginTop="16dp"/>
</LinearLayout>
清单文件:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="itant.com.wificlient">
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<!-- 文件存储 -->
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
HttpTools.java:
package itant.com.wificlient;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
import android.text.format.Formatter;
import java.lang.reflect.Method;
/**
* 网络请求相关辅助类
* @author jason.zhan
*
*/
public class HttpTools {
/**
* 判断是否有网络
* @param context
* @return
*/
public static boolean isNetworkConnected(Context context) {
if (context != null) {
ConnectivityManager mConnectivityManager = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo mNetworkInfo = mConnectivityManager.getActiveNetworkInfo();
if (mNetworkInfo != null) {
return mNetworkInfo.isAvailable();
}
}
return false;
}
public static boolean setWifiApEnabled(WifiManager wifiManager, WifiConfiguration wifiConfiguration, boolean enable) {
boolean invokeStatus = true;
try {
Method setupHotSpot = wifiManager.getClass().getMethod("setWifiApEnabled", WifiConfiguration.class, boolean.class);
setupHotSpot.invoke(wifiManager, wifiConfiguration, enable);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
invokeStatus = false;
}
return invokeStatus;
}
/**
* 判断WiFi是否连接上了
* @param context
* @return
*/
public static boolean isWiFiConnected(Context context) {
if (context != null) {
ConnectivityManager mConnectivityManager = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo mNetworkInfo = mConnectivityManager.getActiveNetworkInfo();
if (mNetworkInfo != null) {
return (mNetworkInfo.getType() == ConnectivityManager.TYPE_WIFI);
}
}
return false;
}
/**
* 获取所连接的WiFi名称
* @param wifiManager
* @return
*/
public static String getConnectedWifiSsid(WifiManager wifiManager) {
return wifiManager.getConnectionInfo().getSSID();
}
/**
* @return (发送端)服务器IP地址,转换IP输出格式
*/
public static String getSenderIP(WifiManager wifiManager) {
//WifiInfo wifiInfo = wifiManager.getConnectionInfo();
//int ipAddress = wifiInfo.getIpAddress();
int ipAddress = wifiManager.getDhcpInfo().serverAddress;
return Formatter.formatIpAddress(ipAddress);
}
/*****************************供接收者使用***************************************/
// 加密类型,分为三种情况:1.没有密码 2.用WEP加密 3.用WPA加密,我们这里只用到了第3种
public static final int TYPE_NO_PASSWD = 1;
public static final int TYPE_WEP = 2;
public static final int TYPE_WPA = 3;
/**
* 连接信息生成配置对象
*/
public static WifiConfiguration createWifiInfo(String SSID, String password, int type) {
WifiConfiguration config = new WifiConfiguration();
config.SSID = SSID;
// 清除热点记录clearAll(SSID);
if (type == TYPE_NO_PASSWD) {
config.hiddenSSID = false;
config.status = WifiConfiguration.Status.ENABLED;
config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
config.allowedProtocols.set(WifiConfiguration.Protocol.WPA);
config.allowedProtocols.set(WifiConfiguration.Protocol.RSN);
config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP);
config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP40);
config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP104);
config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
config.preSharedKey = null;
} else if (type == TYPE_WEP) {
config.hiddenSSID = true;
config.wepKeys[0] = "\"" + password + "\"";
config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.SHARED);
config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP40);
config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP104);
config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
config.wepTxKeyIndex = 0;
} else if (type == TYPE_WPA) {
config.preSharedKey = "\"" + password + "\"";
config.hiddenSSID = false;
config.priority = 10000;
config.status = WifiConfiguration.Status.ENABLED;
config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
config.allowedProtocols.set(WifiConfiguration.Protocol.RSN);
config.allowedProtocols.set(WifiConfiguration.Protocol.WPA);
config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP);
config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
}
return config;
}
/*****************************供接收者使用***************************************/
}