为什么WifiP2pService会删除我的Wifi Direct组?

8

我有一个应用程序,可以在两台手机上运行,并允许用户使用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() {...

意外的群组创建,移除网络

当出现问题时,当启动设备运行上述代码尝试连接时,Logcat会显示Sony中这个有趣的信息:

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()中找到了这段代码:(链接)

              /* 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()”没有“P2P_GROUP_STARTED_EVENT”的“case”。所以也许如果手机上的WifiP2pService在P2pEnabledState中,我就不会遇到这个组删除问题。
但根据日志,WifiP2p已启用:我捕获了“WIFI_P2P_STATE_CHANGED_ACTION”广播并记录了“EXTRA_WIFI_STATE”的值。那么为什么WifiP2pService显然处于“DefaultState”状态呢?
顺便说一下,配对过去在Sony上工作,但昨天我连接了设备到家庭Wifi路由器,自那以后似乎就没有工作过,即使我从路由器断开连接。
我尝试关闭Wifi,重新打开它,删除(“忘记”)我的家庭Wifi路由器,重启手机,并从除LG以外的其他手机连接。没有任何方法可以解决这个问题。

1
如果在DefaultState中出现P2P_GROUP_STARTED_EVENT事件并移除连接的组,则意味着出现了问题。 我看到的是,在移除之前,您的组处于错误状态。状态:4为[/协议错误。/INVALID_PARAMETER]。 - snersesyan
@SergeyNersesyan 我不确定我是否理解了你所说的一切。但我也不认为 status: 4 完全指的是组。查看 WifiP2pGroup.toString() 的代码,status 部分来自于描述 GO 设备的 WifiP2pDevice.toString()。WifiP2pDevice.status = 4 表示 UNAVAILABLE。所以这有所帮助,但问题接下来就变成了:为什么在这种情况下设备状态是 UNAVAILABLE,而大多数手机大部分时间都不是这样?顺便说一句,显示的“设备地址”与任何一个手机的 WiFi MAC 地址都不匹配。我不确定哪个设备是“UNAVAILABLE”。 - LarsH
1
我以为状态是WifiP2pService.P2pStatus.INVALID_PARAMETER,但你是对的,很抱歉。状态= UNAVAILABLE是默认值,在WifiP2pDevice类构造函数中设置。如果您还没有完成,我可以建议两件事来检查: 1.在WifiP2pDevice.status更改时在Sony和其他设备上放置断点并进行调试,以查看差异 2.这很愚蠢,但也许在连接到您的wifi后,您会注意到设备日期/时间有所变化?我看到WifiP2pService上有与时间相关的检查。 - snersesyan
1个回答

1

您的代码非常不完整,需要完成。以下是为您提供的代码示例。

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);
    }
}

你的AndroidManifest.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

谢谢你的回答。我的清单中确实拥有这些权限(请记住,在大多数手机上,配对功能大部分时间都是正常的)。是的,我展示的代码并不完整……它只是一个大型应用程序的一部分。我想我可以尝试创建最小可重现实例。 - LarsH
顺便提一下,如果你从非你自己编写的源代码中复制了一大块代码,请注明出处。例如,https://github.com/Miserlou/Android-SDK-Samples/tree/master/WiFiDirectServiceDiscovery - LarsH
哦,对不起,非常抱歉。我想要源代码在我的系统中,但我不知道该怎么做。我已经修改了我的回复。@LarsH - Amirhf

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接