我有一个可在2部手机上运行的应用程序,并允许用户使用WifiP2p(WiFi Direct)从一个连接到另一个。在大多数手机上,它都能正常工作。两部电话进入对等发现,它们发现对方,一个发起连接,另一个接受。但是,当我尝试连接到运行Android 4.1.2的Sony LT25i时,配对失败。
用于启动连接的代码如下:
WifiP2pConfig wifiP2pConfig = new WifiP2pConfig();
wifiP2pConfig.deviceAddress = device.deviceAddress;
// Try to make a device that supports WifiDirect the group owner,
// so that a legacy device can connect to it as an access point.
wifiP2pConfig.groupOwnerIntent = 10;
// Wifi Protected Setup: Push Button Configuration. The other main option is PIN configuration.
wifiP2pConfig.wps.setup = WpsInfo.PBC;
mWifiP2pManager.connect(mChannel, wifiP2pConfig, new WifiP2pManager.ActionListener() {...
意外的组创建,删除网络
发生问题时,当启动设备运行以上代码以尝试连接时,Sony在Logcat中显示此有趣的花絮:
02-02 05:22:55.494 669-781/? E/WifiP2pService: Unexpected group creation,
remove network: DIRECT-aq-LG Phoenix 2
isGO: false
GO: Device:
deviceAddress: de:0b:34:f0:11:78
primary type: null
secondary type: null
wps: 0
grpcapab: 0
devcapab: 0
status: 4
interface: p2p0
其中“LG Phoenix 2”是启动配对的电话的名称。
由于某些原因,WifiP2pService 不喜欢正在创建组的事实,因此将其删除。为什么?
我查找了错误消息“WifiP2pService:意外的组创建,删除”
并在
WifiP2pService.DefaultState.processMessage()
中找到this code: /* unexpected group created, remove */
case WifiMonitor.P2P_GROUP_STARTED_EVENT:
mGroup = (WifiP2pGroup) message.obj;
loge("Unexpected group creation, remove " + mGroup);
mWifiNative.p2pGroupRemove(mGroup.getInterface());
break;
那么显然发生这种情况是因为WifiP2pService在
DefaultState
中吗?相比之下,WifiP2pService.P2pEnabledState.processMessage()
没有针对case
的P2P_GROUP_STARTED_EVENT
。因此,如果WifiP2pService处于电话上的P2pEnabledState中,那么我就不会遇到该组删除问题。但是根据日志,WifiP2p已启用:我正在捕获
WIFI_P2P_STATE_CHANGED_ACTION
广播并记录EXTRA_WIFI_STATE
的值。那么,为什么WifiP2pService显然在DefaultState
中?顺便说一下,配对曾经可以在Sony上使用,但是昨天我将设备连接到了我的家用Wifi路由器,此后似乎就没有用过,即使我从路由器上断开了连接。
我试过关闭Wifi,重新打开Wifi,删除(“忘记”)我的家用Wifi路由器,重新启动电话,以及通过LG以外的其他电话进行连接。什么都不能解决问题。
最佳答案
您拥有的该代码非常不完整,需要完成。请注意为您的代码示例。
import android.app.Activity;
import android.app.Fragment;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.IntentFilter;
import android.net.wifi.WpsInfo;
import android.net.wifi.p2p.WifiP2pConfig;
import android.net.wifi.p2p.WifiP2pDevice;
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.DnsSdServiceResponseListener;
import android.net.wifi.p2p.WifiP2pManager.DnsSdTxtRecordListener;
import android.net.wifi.p2p.nsd.WifiP2pDnsSdServiceInfo;
import android.net.wifi.p2p.nsd.WifiP2pDnsSdServiceRequest;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import com.example.android.wifidirect.discovery.WiFiChatFragment.MessageTarget;
import com.example.android.wifidirect.discovery.WiFiDirectServicesList.DeviceClickListener;
import com.example.android.wifidirect.discovery.WiFiDirectServicesList.WiFiDevicesAdapter;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
public class WiFiServiceDiscoveryActivity extends Activity implements
DeviceClickListener, Handler.Callback, MessageTarget,
ConnectionInfoListener {
public static final String TAG = "wifidirectdemo";
// TXT RECORD properties
public static final String TXTRECORD_PROP_AVAILABLE = "available";
public static final String SERVICE_INSTANCE = "_wifidemotest";
public static final String SERVICE_REG_TYPE = "_presence._tcp";
public static final int MESSAGE_READ = 0x400 + 1;
public static final int MY_HANDLE = 0x400 + 2;
private WifiP2pManager manager;
static final int SERVER_PORT = 4545;
private final IntentFilter intentFilter = new IntentFilter();
private Channel channel;
private BroadcastReceiver receiver = null;
private WifiP2pDnsSdServiceRequest serviceRequest;
private Handler handler = new Handler(this);
private WiFiChatFragment chatFragment;
private WiFiDirectServicesList servicesList;
private TextView statusTxtView;
public Handler getHandler() {
return handler;
}
public void setHandler(Handler handler) {
this.handler = handler;
}
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
statusTxtView = (TextView) findViewById(R.id.status_text);
intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
intentFilter
.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
intentFilter
.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
manager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
channel = manager.initialize(this, getMainLooper(), null);
startRegistrationAndDiscovery();
servicesList = new WiFiDirectServicesList();
getFragmentManager().beginTransaction()
.add(R.id.container_root, servicesList, "services").commit();
}
@Override
protected void onRestart() {
Fragment frag = getFragmentManager().findFragmentByTag("services");
if (frag != null) {
getFragmentManager().beginTransaction().remove(frag).commit();
}
super.onRestart();
}
@Override
protected void onStop() {
if (manager != null && channel != null) {
manager.removeGroup(channel, new ActionListener() {
@Override
public void onFailure(int reasonCode) {
Log.d(TAG, "Disconnect failed. Reason :" + reasonCode);
}
@Override
public void onSuccess() {
}
});
}
super.onStop();
}
/**
* Registers a local service and then initiates a service discovery
*/
private void startRegistrationAndDiscovery() {
Map<String, String> record = new HashMap<String, String>();
record.put(TXTRECORD_PROP_AVAILABLE, "visible");
WifiP2pDnsSdServiceInfo service = WifiP2pDnsSdServiceInfo.newInstance(
SERVICE_INSTANCE, SERVICE_REG_TYPE, record);
manager.addLocalService(channel, service, new ActionListener() {
@Override
public void onSuccess() {
appendStatus("Added Local Service");
}
@Override
public void onFailure(int error) {
appendStatus("Failed to add a service");
}
});
discoverService();
}
private void discoverService() {
/*
* Register listeners for DNS-SD services. These are callbacks invoked
* by the system when a service is actually discovered.
*/
manager.setDnsSdResponseListeners(channel,
new DnsSdServiceResponseListener() {
@Override
public void onDnsSdServiceAvailable(String instanceName,
String registrationType, WifiP2pDevice srcDevice) {
// A service has been discovered. Is this our app?
if (instanceName.equalsIgnoreCase(SERVICE_INSTANCE)) {
// update the UI and add the item the discovered
// device.
WiFiDirectServicesList fragment = (WiFiDirectServicesList) getFragmentManager()
.findFragmentByTag("services");
if (fragment != null) {
WiFiDevicesAdapter adapter = ((WiFiDevicesAdapter) fragment
.getListAdapter());
WiFiP2pService service = new WiFiP2pService();
service.device = srcDevice;
service.instanceName = instanceName;
service.serviceRegistrationType = registrationType;
adapter.add(service);
adapter.notifyDataSetChanged();
Log.d(TAG, "onBonjourServiceAvailable "
+ instanceName);
}
}
}
}, new DnsSdTxtRecordListener() {
/**
* A new TXT record is available. Pick up the advertised
* buddy name.
*/
@Override
public void onDnsSdTxtRecordAvailable(
String fullDomainName, Map<String, String> record,
WifiP2pDevice device) {
Log.d(TAG,
device.deviceName + " is "
+ record.get(TXTRECORD_PROP_AVAILABLE));
}
});
// After attaching listeners, create a service request and initiate
// discovery.
serviceRequest = WifiP2pDnsSdServiceRequest.newInstance();
manager.addServiceRequest(channel, serviceRequest,
new ActionListener() {
@Override
public void onSuccess() {
appendStatus("Added service discovery request");
}
@Override
public void onFailure(int arg0) {
appendStatus("Failed adding service discovery request");
}
});
manager.discoverServices(channel, new ActionListener() {
@Override
public void onSuccess() {
appendStatus("Service discovery initiated");
}
@Override
public void onFailure(int arg0) {
appendStatus("Service discovery failed");
}
});
}
@Override
public void connectP2p(WiFiP2pService service) {
WifiP2pConfig config = new WifiP2pConfig();
config.deviceAddress = service.device.deviceAddress;
config.wps.setup = WpsInfo.PBC;
if (serviceRequest != null)
manager.removeServiceRequest(channel, serviceRequest,
new ActionListener() {
@Override
public void onSuccess() {
}
@Override
public void onFailure(int arg0) {
}
});
manager.connect(channel, config, new ActionListener() {
@Override
public void onSuccess() {
appendStatus("Connecting to service");
}
@Override
public void onFailure(int errorCode) {
appendStatus("Failed connecting to service");
}
});
}
@Override
public boolean handleMessage(Message msg) {
switch (msg.what) {
case MESSAGE_READ:
byte[] readBuf = (byte[]) msg.obj;
// construct a string from the valid bytes in the buffer
String readMessage = new String(readBuf, 0, msg.arg1);
Log.d(TAG, readMessage);
(chatFragment).pushMessage("Buddy: " + readMessage);
break;
case MY_HANDLE:
Object obj = msg.obj;
(chatFragment).setChatManager((ChatManager) obj);
}
return true;
}
@Override
public void onResume() {
super.onResume();
receiver = new WiFiDirectBroadcastReceiver(manager, channel, this);
registerReceiver(receiver, intentFilter);
}
@Override
public void onPause() {
super.onPause();
unregisterReceiver(receiver);
}
@Override
public void onConnectionInfoAvailable(WifiP2pInfo p2pInfo) {
Thread handler = null;
/*
* The group owner accepts connections using a server socket and then spawns a
* client socket for every client. This is handled by {@code
* GroupOwnerSocketHandler}
*/
if (p2pInfo.isGroupOwner) {
Log.d(TAG, "Connected as group owner");
try {
handler = new GroupOwnerSocketHandler(
((MessageTarget) this).getHandler());
handler.start();
} catch (IOException e) {
Log.d(TAG,
"Failed to create a server thread - " + e.getMessage());
return;
}
} else {
Log.d(TAG, "Connected as peer");
handler = new ClientSocketHandler(
((MessageTarget) this).getHandler(),
p2pInfo.groupOwnerAddress);
handler.start();
}
chatFragment = new WiFiChatFragment();
getFragmentManager().beginTransaction()
.replace(R.id.container_root, chatFragment).commit();
statusTxtView.setVisibility(View.GONE);
}
public void appendStatus(String status) {
String current = statusTxtView.getText().toString();
statusTxtView.setText(current + "\n" + status);
}
}
并且AndroidManifast.xml的文件应该相同,并提供这些访问权限
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="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" />
<!-- Google Play filtering -->
<uses-feature android:name="android.hardware.wifi.direct" android:required="true"/>
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<activity
android:name=".WiFiServiceDiscoveryActivity"
android:label="@string/app_name"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
如有任何疑问,请让我尽快回复
来源
WiFiDirectServiceDiscovery