简体   繁体   中英

Send a string through WiFi-Direct between two android devices

It is now over a month that I'm trying to send a string using WiFi-Direct between two android devices, but I'm still struggling hard to understand what I'm doing wrong.

I've looked around forums but they often don't give much detail on how to achieve what I want.

I also went through those two guides from the android developer's website:

I'm using one activity - ActivityConnection - where I toggle the visibility of views depending on whether the user previously chose to send or to receive the string.

  • Immediatly, on the client side, discoverPeers() looks for any device with WiFi-Direct turned on and displays them on a ListView . Once the user chooses a device and presses the send button, the connection makes itself and the string is sent.

  • On the server side, the server is immediatly launched using my AsyncServerTask class. There, it waits for a client to connect and to retrieve its sent string.

My main problem is that, after choosing the device and tapping on the send button, the server side isn't receiving anything. My second problem is that, sometimes, devices aren't being discovered and the listview stays empty.

Am I missing something? Or maybe doing something wrong?

Here's my current code. I took the liberty to get rid of any line I thought to be out of context to make it easier to read.

ActivityConnection

public class ActivityConnection extends AppCompatActivity implements NewPeersListener {

    public static final String CONNECTION_ACTOR = "actor";
    public static final String SEND_INFO = "send";
    public static final String RECEIVE_INFO = "receive";

    ListView listViewDevices;

    private IntentFilter intentFilter;
    private WifiP2pManager manager;
    private WifiP2pManager.Channel channel;
    private WiFiDirectBroadcastReceiver receiver;

    public List <WifiP2pDevice> listDevices;
    private WifiP2pDevice selectedDevice;



    @Override
    public void onCreate (Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        confirm.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                connectToSelectedDevice();
            }
        });

        Intent intent = this.getIntent();
        String actor = intent.getStringExtra(CONNECTION_ACTOR);

        this.intentFilter = new IntentFilter();
        this.intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
        this.intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
        this.intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
        this.intentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);

        this.manager = (WifiP2pManager) this.getSystemService(Context.WIFI_P2P_SERVICE);
        this.channel = this.manager.initialize(this, this.getMainLooper(), null);
        this.receiver = new WiFiDirectBroadcastReceiver(this.manager, this.channel, this);

        this.listDevices = new ArrayList <> ();

        if (actor.equals(SEND_INFO)) {
            DeviceAdapter adapter = new DeviceAdapter(ActivityConnection.this, R.layout.device_item, this.listDevices);
            this.listViewDevices.setAdapter(adapter);

            this.listViewDevices.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                    selectedDevice = listDevices.get(position);
                }
            });

            this.discoverPeers();
        }
        else if (actor.equals(RECEIVE_INFO)) {
            new ServerAsyncTask(this).execute();
        }
    }



    @Override
    protected void onResume() {
        super.onResume();
        this.receiver = new WiFiDirectBroadcastReceiver(this.manager, this.channel, this);
        this.registerReceiver(this.receiver, this.intentFilter);
    }

    @Override
    protected void onPause() {
        super.onPause();
        this.unregisterReceiver(this.receiver);
    }



    public void resultReceived (String result) {
        Toast.makeText(ActivityConnection.this, "Received! :)", Toast.LENGTH_SHORT).show();
    }



    private void discoverPeers () {
        manager.discoverPeers(channel, new WifiP2pManager.ActionListener() {
            @Override
            public void onSuccess() {
                // The discovery process succeeded
            }

            @Override
            public void onFailure(int reason) {
                // The discovery process DID NOT succeed
                Toast.makeText(ActivityConnection.this, "Discovery process DID NOT succeed. Please verify that WiFi-Direct is active.", Toast.LENGTH_LONG).show();
            }
        });
    }



    private void connectToSelectedDevice () {
        WifiP2pConfig config = new WifiP2pConfig();
        config.deviceAddress = this.selectedDevice.deviceAddress;
        this.manager.connect(this.channel, config, new WifiP2pManager.ActionListener() {
            @Override
            public void onSuccess() {
                // Send string
                Intent serviceIntent = new Intent(ActivityConnection.this, TransferService.class);
                serviceIntent.setAction(TransferService.ACTION_SEND_STRING);
                serviceIntent.putExtra(TransferService.EXTRAS_GROUP_OWNER_ADDRESS, getMacAddress());
                serviceIntent.putExtra(TransferService.EXTRAS_GROUP_OWNER_PORT, 8090);
                startService(serviceIntent);
                onBackPressed();
            }

            @Override
            public void onFailure(int reason) {
                Toast.makeText(ActivityConnection.this, "Connection failed. Try again.", Toast.LENGTH_SHORT).show();
            }
        });
    }



    @NonNull
    private String getMacAddress () {
        try {
            List <NetworkInterface> all = Collections.list(NetworkInterface.getNetworkInterfaces());
            for (NetworkInterface nif : all) {
                if (!nif.getName().equalsIgnoreCase("wlan0")) continue;

                byte[] macBytes = nif.getHardwareAddress();
                if (macBytes == null) {
                    return "";
                }

                StringBuilder result = new StringBuilder();
                for (byte b : macBytes) {
                    result.append(String.format("%02X:",b));
                }

                if (result.length() > 0) {
                    result.deleteCharAt(result.length() - 1);
                }
                return result.toString();
            }
        } catch (Exception e) {
        }
        return "02:00:00:00:00:00";
    }



    @Override
    public void newPeers (WifiP2pDeviceList wifiP2pDeviceList) {
        this.listDevices = new ArrayList <> (wifiP2pDeviceList.getDeviceList());
        DeviceAdapter adapter = new DeviceAdapter(ActivityConnection.this, R.layout.device_item, this.listDevices);
        this.listViewDevices.setAdapter(adapter);
    }
}

WiFiDirectBroadcastReceiver

public class WiFiDirectBroadcastReceiver extends BroadcastReceiver {

    private WifiP2pManager manager;
    private WifiP2pManager.Channel channel;
    private ActivityConnection activity;

    private List <NewPeersListener> listeners;



    public WiFiDirectBroadcastReceiver(WifiP2pManager manager, WifiP2pManager.Channel channel, ActivityConnection activity) {
        super();
        this.manager = manager;
        this.channel = channel;
        this.activity = activity;

        this.listeners = new ArrayList <> ();
        this.listeners.add(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) {
                // Wi-Fi P2P is enabled
            } else {
                // Wi-Fi P2P is not enabled
                Toast.makeText(this.activity, "Please turn on WiFi-Direct (or WiFi-P2P).", Toast.LENGTH_SHORT).show();
            }

        } else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {
            // Request available peers from the wifi p2p manager.
            if (this.manager != null) {
                this.manager.requestPeers(this.channel, new WifiP2pManager.PeerListListener() {
                    @Override
                    public void onPeersAvailable(WifiP2pDeviceList peers) {
                        for (NewPeersListener listener : listeners) {
                            listener.newPeers(peers);
                        }
                    }
                });
            }
        } else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) {
            // Respond to new connection or disconnections
        } else if (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION.equals(action)) {
            // Respond to this device's wifi state changing
        }
    }

}

ServerAsyncTask (server)

public class ServerAsyncTask extends AsyncTask<Void, Void, String> {

    private ServerSocket serverSocket;
    private Socket clientSocket;
    private DataInputStream stream;

    private WeakReference <Context> contextWeakReference;



    ServerAsyncTask (Context context) {
        this.contextWeakReference = new WeakReference <> (context);
    }



    @Override
    protected String doInBackground (Void... params) {
        try {
            this.serverSocket = new ServerSocket(8090);
            this.clientSocket = this.serverSocket.accept();

            this.stream = new DataInputStream(this.clientSocket.getInputStream());
            String received = this.stream.readUTF();
            this.serverSocket.close();
            return received;
        } catch (IOException e) {
            Log.e(TransferService.TAG, Objects.requireNonNull(e.getMessage()));
            return null;
        } finally {
            if (this.stream != null) {
                try {
                    this.stream.close();
                } catch (IOException e) {
                    Log.e(TransferService.TAG, Objects.requireNonNull(e.getMessage()));
                }
            }
            if (this.clientSocket != null) {
                try {
                    this.clientSocket.close();
                } catch (IOException e) {
                    Log.e(TransferService.TAG, Objects.requireNonNull(e.getMessage()));
                }
            }
            if (this.serverSocket != null) {
                try {
                    this.serverSocket.close();
                } catch (IOException e) {
                    Log.e(TransferService.TAG, Objects.requireNonNull(e.getMessage()));
                }
            }
        }
    }

    /*
     * (non-Javadoc)
     * @see android.os.AsyncTask#onPostExecute(java.lang.Object)
     */
    @Override
    protected void onPostExecute (String result) {
        super.onPostExecute(result);
        ((ActivityConnection) this.contextWeakReference.get()).resultReceived(result);
    }

}

TransferService (client)

public class TransferService extends IntentService {

    public static final String TAG = "WIFI_DIRECT";

    private static final int SOCKET_TIMEOUT = 5000;
    public static final String ACTION_SEND_STRING = "sendString";
    public static final String EXTRAS_GROUP_OWNER_ADDRESS = "go_host";
    public static final String EXTRAS_GROUP_OWNER_PORT = "go_port";



    public TransferService (String name) {
        super(name);
    }

    public TransferService () {
        super("TransferService");
    }



    @Override
    protected void onHandleIntent (Intent intent) {
        Context context = getApplicationContext();
        if (intent.getAction().equals(ACTION_SEND_STRING)) {
            String toSend = "string to send";

            String host = intent.getExtras().getString(EXTRAS_GROUP_OWNER_ADDRESS);
            int port = intent.getExtras().getInt(EXTRAS_GROUP_OWNER_PORT);
            Socket socket = null;
            DataOutputStream stream = null;
            try {
                // Create a client socket with the host, port, and timeout information.
                socket = new Socket();
                socket.bind(null);
                socket.connect((new InetSocketAddress(host, port)), SOCKET_TIMEOUT);
                Log.d(TAG, "Client connected socket - " + socket.isConnected());

                // Send string
                stream = new DataOutputStream(socket.getOutputStream());
                stream.writeUTF(toSend);
                stream.close();
                Toast.makeText(context, "Sent! :)", Toast.LENGTH_SHORT).show();
            } catch (IOException e) {
                Log.e(TAG, Objects.requireNonNull(e.getMessage()));
            } finally {
                if (stream != null) {
                    try {
                        stream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (socket != null) {
                    if (socket.isConnected()) {
                        try {
                            socket.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }
}

In the ActivityConnetion class, I was giving a MAC address instead of an IP address. I don't know why I didn't see this, nor why I did it in the first place. So I looked around this forum and found out how to get the IP address of the WiFi-Direct's group owner: Wifi Direct Group Owner Address .

To get the code running, I went into the ActivityConnetion class, delete the getMacAddress() method and replaced this line:

serviceIntent.putExtra(TransferService.EXTRAS_GROUP_OWNER_ADDRESS, getMacAddress());

with this line:

serviceIntent.putExtra(TransferService.EXTRAS_GROUP_OWNER_ADDRESS, "192.168.49.1");

As the group owner's IP is always the same, one can write it down directly. As doing so can stop working if the IP changes, I would recommend looking for the group owner's IP instead. The link above show's how to do it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM