使用 wifi 直接在 Android 设备之间传输数据?
Posted
技术标签:
【中文标题】使用 wifi 直接在 Android 设备之间传输数据?【英文标题】:Transfer Data between Android devices using wifi direct? 【发布时间】:2013-07-18 05:36:37 【问题描述】:我最近在我的项目中实现了 wifi direct,我的目标是当我的一些应用程序条件满足时,在两个 wifidirect 连接的设备之间传递字符串值。现在我已经列出了所有对等点,并在选定的对等点之间建立了连接。我的想法是在设备之间传递一个 json 文件。所以在尝试执行该想法之前,我尝试在两个设备之间传递一个图像文件。我遵循了 android wifidirect 教程中的步骤。列出对等点,对等点之间的连接是成功的但我无法在设备之间传递数据。以下是我的代码。 FileTransferService.java
package jing.app.directwifi;
import android.app.IntentService;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.util.Log;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
/**
* A service that process each file transfer request i.e Intent by opening a
* socket connection with the WiFi Direct Group Owner and writing the file
*/
public class FileTransferService extends IntentService
private static final int SOCKET_TIMEOUT = 5000;
public static final String ACTION_SEND_FILE = "jing.app.directwifi.SEND_FILE";
public static final String EXTRAS_FILE_PATH = "file_url";
public static final String EXTRAS_GROUP_OWNER_ADDRESS = "go_host";
public static final String EXTRAS_GROUP_OWNER_PORT = "go_port";
public FileTransferService(String name)
super(name);
public FileTransferService()
super("FileTransferService");
/*
* (non-Javadoc)
* @see android.app.IntentService#onHandleIntent(android.content.Intent)
*/
@Override
protected void onHandleIntent(Intent intent)
Context context = getApplicationContext();
if (intent.getAction().equals(ACTION_SEND_FILE))
String fileUri = intent.getExtras().getString(EXTRAS_FILE_PATH);
String host = intent.getExtras().getString(EXTRAS_GROUP_OWNER_ADDRESS);
Socket socket = new Socket();
int port = intent.getExtras().getInt(EXTRAS_GROUP_OWNER_PORT);
try
// Log.d(WiFiDirectActivity.TAG, "Opening client socket - ");
socket.bind(null);
socket.connect((new InetSocketAddress(host, port)), SOCKET_TIMEOUT);
Log.d("connected", "Client socket - " + socket.isConnected());
OutputStream stream = socket.getOutputStream();
ContentResolver cr = context.getContentResolver();
InputStream is = null;
try
is = cr.openInputStream(Uri.parse(fileUri));
catch (FileNotFoundException e)
Log.d("exp", e.toString());
MainActivity.copyFile(is, stream);
Log.d("exp" ,"Client: Data written");
catch (IOException e)
Log.e("exp", e.getMessage());
finally
if (socket != null)
if (socket.isConnected())
try
socket.close();
catch (IOException e)
// Give up
e.printStackTrace();
主Activity.java
package jing.app.directwifi;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Collection;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.Uri;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.net.wifi.p2p.WifiP2pConfig;
import android.net.wifi.p2p.WifiP2pDevice;
import android.net.wifi.p2p.WifiP2pDeviceList;
import android.net.wifi.p2p.WifiP2pInfo;
import android.net.wifi.p2p.WifiP2pManager;
import android.net.wifi.p2p.WifiP2pManager.ActionListener;
import android.net.wifi.p2p.WifiP2pManager.Channel;
import android.net.wifi.p2p.WifiP2pManager.ConnectionInfoListener;
import android.net.wifi.p2p.WifiP2pManager.PeerListListener;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.provider.Settings;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends Activity implements OnClickListener, android.content.DialogInterface.OnClickListener, ConnectionInfoListener
private WifiP2pManager mManager;
private Channel mChannel;
private BroadcastReceiver mReceiver;
private IntentFilter mIntentFilter;
private Button mDiscover;
private TextView mDevices;
public ArrayAdapter mAdapter;
private ArrayList<WifiP2pDevice> mDeviceList = new ArrayList<WifiP2pDevice>();
protected static final int CHOOSE_FILE_RESULT_CODE = 20;
int flag=0;
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mDiscover = (Button) findViewById(R.id.discover);
mDiscover.setOnClickListener(this);
mDevices = (TextView) findViewById(R.id.peers);
mManager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
mChannel = mManager.initialize(this, getMainLooper(), null);
mReceiver = new WiFiDirectReceiver(mManager, mChannel, this);
mIntentFilter = new IntentFilter();
mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
@Override
protected void onResume()
super.onResume();
registerReceiver(mReceiver, mIntentFilter);
@Override
protected void onPause()
super.onPause();
unregisterReceiver(mReceiver);
@Override
public boolean onCreateOptionsMenu(Menu menu)
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
private class WiFiDirectReceiver extends BroadcastReceiver
private WifiP2pManager mManager;
private Channel mChannel;
private MainActivity mActivity;
public WiFiDirectReceiver(WifiP2pManager manager, Channel channel, MainActivity activity)
super();
mManager = manager;
mChannel = channel;
mActivity = activity;
@Override
public void onReceive(Context context, Intent intent)
String action = intent.getAction();
if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action))
int state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1);
if (state == WifiP2pManager.WIFI_P2P_STATE_ENABLED)
String title = "ANDROID_ID[" + getAndroid_ID() + "]";
title += " MAC[" + getMACAddress() + "]";
Toast.makeText(mActivity, "Wi-Fi Direct is enabled."+title, Toast.LENGTH_SHORT).show();
else
Toast.makeText(mActivity, "Wi-Fi Direct is disabled.", Toast.LENGTH_SHORT).show();
else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action))
if (mManager != null)
mManager.requestPeers(mChannel, new PeerListListener()
@Override
public void onPeersAvailable(WifiP2pDeviceList peers)
if (peers != null)
mDeviceList.addAll(peers.getDeviceList());
ArrayList<String> deviceNames = new ArrayList<String>();
for (WifiP2pDevice device : mDeviceList)
deviceNames.add(device.deviceName);
if (deviceNames.size() > 0)
mAdapter = new ArrayAdapter<String>(mActivity, android.R.layout.simple_list_item_1, deviceNames);
if(flag==0)
flag=1;
showDeviceListDialog();
else
Toast.makeText(mActivity, "Device list is empty.", Toast.LENGTH_SHORT).show();
);
else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action))
else if (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION.equals(action))
@Override
public void onClick(View v)
switch (v.getId())
case R.id.discover:
onDiscover();
break;
private void onDiscover()
mManager.discoverPeers(mChannel, new ActionListener()
@Override
public void onSuccess()
Toast.makeText(MainActivity.this, "Discover peers successfully.", Toast.LENGTH_SHORT).show();
@Override
public void onFailure(int reason)
Toast.makeText(MainActivity.this, "Discover peers failed.", Toast.LENGTH_SHORT).show();
);
private void showDeviceListDialog()
DeviceListDialog deviceListDialog = new DeviceListDialog();
deviceListDialog.show(getFragmentManager(), "devices");
private class DeviceListDialog extends DialogFragment
@Override
public Dialog onCreateDialog(Bundle savedInstanceState)
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle("Select a device")
.setSingleChoiceItems(mAdapter, 0, MainActivity.this)
.setNegativeButton("Cancel", new DialogInterface.OnClickListener()
@Override
public void onClick(DialogInterface dialog, int which)
dialog.dismiss();
);
return builder.create();
@Override
public void onClick(DialogInterface dialog, int which)
onDeviceSelected(which);
dialog.dismiss();
private void onDeviceSelected(int which)
WifiP2pDevice device = mDeviceList.get(which);
if (device == null)
return;
WifiP2pConfig config = new WifiP2pConfig();
config.deviceAddress = device.deviceAddress;
mManager.connect(mChannel, config, new ActionListener()
@Override
public void onSuccess()
Toast.makeText(MainActivity.this, "Connected", Toast.LENGTH_SHORT).show();
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
startActivityForResult(intent, CHOOSE_FILE_RESULT_CODE);
@Override
public void onFailure(int reason)
Toast.makeText(MainActivity.this, "Failed to connect", Toast.LENGTH_SHORT).show();
);
/**
* ANDROID_ID
*/
private String getAndroid_ID()
return Settings.Secure.getString(getContentResolver(), Settings.Secure.ANDROID_ID);
/**
* Wi-Fi MAC
*/
private String getMACAddress()
WifiManager manager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
WifiInfo wifiInfo = manager.getConnectionInfo();
String mac = wifiInfo.getMacAddress();
// After the group negotiation, we assign the group owner as the file
// server. The file server is single threaded, single connection server
// socket.
new FileServerAsyncTask(getApplicationContext())
.execute();
return mac;
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data)
// User has picked an image. Transfer it to group owner i.e peer using
// FileTransferService.
Uri uri = data.getData();
Log.d("intent", "Intent----------- " + uri);
Intent serviceIntent = new Intent(MainActivity.this, FileTransferService.class);
serviceIntent.setAction(FileTransferService.ACTION_SEND_FILE);
serviceIntent.putExtra(FileTransferService.EXTRAS_FILE_PATH, uri.toString());
serviceIntent.putExtra(FileTransferService.EXTRAS_GROUP_OWNER_ADDRESS,
getMACAddress());
serviceIntent.putExtra(FileTransferService.EXTRAS_GROUP_OWNER_PORT, 8988);
startService(serviceIntent);
/**
* A simple server socket that accepts connection and writes some data on
* the stream.
*/
public static class FileServerAsyncTask extends AsyncTask<Void, Void, String>
private Context context;
/**
* @param context
* @param statusText
*/
public FileServerAsyncTask(Context context)
this.context = context;
@Override
protected String doInBackground(Void... params)
try
System.out.println("insideeeeeeeeeeeeeeeeeeeeeeee");
ServerSocket serverSocket = new ServerSocket(8988);
Log.d("Server: Socket opened", "Server: Socket opened");
Socket client = serverSocket.accept();
Log.d("Server: connection done", "Server: connection done");
final File f = new File(Environment.getExternalStorageDirectory() + "/"
+ context.getPackageName() + "/wifip2pshared-" + System.currentTimeMillis()
+ ".jpg");
File dirs = new File(f.getParent());
if (!dirs.exists())
dirs.mkdirs();
f.createNewFile();
Log.d("server: copying files ", "server: copying files " + f.toString());
InputStream inputstream = client.getInputStream();
copyFile(inputstream, new FileOutputStream(f));
serverSocket.close();
return f.getAbsolutePath();
catch (IOException e)
Log.e("exp", e.getMessage());
System.out.println(":iooo:"+e);
return null;
/*
* (non-Javadoc)
* @see android.os.AsyncTask#onPostExecute(java.lang.Object)
*/
@Override
protected void onPostExecute(String result)
if (result != null)
Intent intent = new Intent();
intent.setAction(android.content.Intent.ACTION_VIEW);
intent.setDataAndType(Uri.parse("file://" + result), "image/*");
context.startActivity(intent);
/*
* (non-Javadoc)
* @see android.os.AsyncTask#onPreExecute()
*/
@Override
protected void onPreExecute()
public static boolean copyFile(InputStream inputStream, OutputStream out)
byte buf[] = new byte[1024];
int len;
long startTime=System.currentTimeMillis();
try
while ((len = inputStream.read(buf)) != -1)
out.write(buf, 0, len);
out.close();
inputStream.close();
long endTime=System.currentTimeMillis()-startTime;
Log.v("","Time taken to transfer all bytes is : "+endTime);
catch (IOException e)
Log.d("exp", e.toString());
return false;
return true;
@Override
public void onConnectionInfoAvailable(WifiP2pInfo info)
// TODO Auto-generated method stub
Toast.makeText(getApplicationContext(), "connectioninfoo", 3000).show();
清单
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="jing.app.directwifi"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="14"
android:targetSdkVersion="16" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- Market filtering -->
<uses-feature
android:name="android.hardware.wifi.direct"
android:required="true" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="jing.app.directwifi.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- Used for transferring files after a successful connection -->
<service
android:name=".FileTransferService"
android:enabled="true" />
</application>
</manifest>
这些是我的代码中使用的文件。形成我发现的教程
新的 FileServerAsyncTask(getApplicationContext()) .execute();
传入数据开始接受的地方,所以当我需要执行这个异步线程时,任何人都可以帮助我在哪个部分犯了错误。如何在设备之间传输文件。
【问题讨论】:
如果您在 wi-fi direct 示例中使用完全相同的代码,则整个程序的任何过程都不会有任何问题。不过,我想说你最好调试你的代码,特别是你的 copyFile 方法。 【参考方案1】:演示 wifi direct 项目中的 android 代码能够传递文件是单向的。 IE。您只能将文件从客户端发送到服务器。您需要进一步修改以使其双向工作。
编辑 2:
为此,您需要知道两个已连接对等方的 IP 地址。在适当的地方使用我根据各种来源所做的修改并使用以下功能。
public static String getIpAddress()
try
List<NetworkInterface> interfaces = Collections
.list(NetworkInterface.getNetworkInterfaces());
/*
* for (NetworkInterface networkInterface : interfaces) Log.v(TAG,
* "interface name " + networkInterface.getName() + "mac = " +
* getMACAddress(networkInterface.getName()));
*/
for (NetworkInterface intf : interfaces)
if (!getMACAddress(intf.getName()).equalsIgnoreCase(
Globals.thisDeviceAddress))
// Log.v(TAG, "ignore the interface " + intf.getName());
// continue;
if (!intf.getName().contains("p2p"))
continue;
Log.v(TAG,
intf.getName() + " " + getMACAddress(intf.getName()));
List<InetAddress> addrs = Collections.list(intf
.getInetAddresses());
for (InetAddress addr : addrs)
// Log.v(TAG, "inside");
if (!addr.isLoopbackAddress())
// Log.v(TAG, "isnt loopback");
String sAddr = addr.getHostAddress().toUpperCase();
Log.v(TAG, "ip=" + sAddr);
boolean isIPv4 = InetAddressUtils.isIPv4Address(sAddr);
if (isIPv4)
if (sAddr.contains("192.168.49."))
Log.v(TAG, "ip = " + sAddr);
return sAddr;
catch (Exception ex)
Log.v(TAG, "error in parsing");
// for now eat exceptions
Log.v(TAG, "returning empty ip address");
return "";
public static String getMACAddress(String interfaceName)
try
List<NetworkInterface> interfaces = Collections
.list(NetworkInterface.getNetworkInterfaces());
for (NetworkInterface intf : interfaces)
if (interfaceName != null)
if (!intf.getName().equalsIgnoreCase(interfaceName))
continue;
byte[] mac = intf.getHardwareAddress();
if (mac == null)
return "";
StringBuilder buf = new StringBuilder();
for (int idx = 0; idx < mac.length; idx++)
buf.append(String.format("%02X:", mac[idx]));
if (buf.length() > 0)
buf.deleteCharAt(buf.length() - 1);
return buf.toString();
catch (Exception ex)
// for now eat exceptions
return "";
/*
* try // this is so Linux hack return
* loadFileAsString("/sys/class/net/" +interfaceName +
* "/address").toUpperCase().trim(); catch (IOException ex) return
* null;
*/
【讨论】:
我无法双向发送图像。实际上,我无法获取客户端的 IP 地址,即非 groupownder peer。 哪里有一个名为 getMACAddress..?? 的方法 什么是 Globals.thisDeviceAddress ?我收到一条错误消息,无法将全局变量解析为变量。为什么你把它设为 Globals ?为什么不使用 device.deviceAddress? 你也可以使用它。当前函数没有设备作为参数,因此我使用了它。【参考方案2】:我认为您初始化客户端的方式会导致问题。
你需要调用它
new FileServerAsyncTask(getApplicationContext()).execute();
连接建立后检查是否是客户端。
现在,只有当它是服务器(组所有者)并且总是在您调用以获取 MAC 地址时,您才创建客户端套接字。
所以在客户端,您没有初始化套接字,因此无法接收文件。
查看 SDK 中提供的 WifiDirect 示例演示后,您可能会有所了解。
【讨论】:
以上是关于使用 wifi 直接在 Android 设备之间传输数据?的主要内容,如果未能解决你的问题,请参考以下文章
如何通过 Android 设备创建的 WiFi 直接网络在 iOS 中使用 ZeroMQ 发送/接收消息