Search code examples
fluttersocketsdartchatp2p

Testproject Messager with Flutter using Peer-to-Peer Technology


I'm working on a Testproject, where I want to exchange information via peer-to-peer from one Mobile device to another.

My goal is to make a little chat widget, where when you post a message, you can see it on all devices, which are connected, a bit like this: A simple textfield and send button. Below the received messages are displayed So if I have one Mobile device, where I send the message, it's seen by all devices.

The reason why I'm asking for help here, is because I've looked around and found two options for peer-to-peer in Flutter: A faulty example of a peer-to-peer connection in Flutter, with practically no documentation

A better-documented example of peer-to-peer connection in Flutter, which also doesn't seem to work.

According to some people, the first option doesn't even work anymore. I've tried both and neither of them managed to achieve what I wanted. It's possible that I don't understand the difference between them 100%.

With this I don't even know really, how to write the Dart/Flutter code, to test the connection between two devices.

I have experience with using Sockets and socketstreams on Java, where one device would send something into the socket stream and the other read it out of the socket stream, but there one device was server and one client.

It would really help me if you could write a simple model, where this peer-to-peer connection works. Because the "documentation" available isn't helping me at all.

Here is the non functioning code, which I have so far

import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:nearby_connections/nearby_connections.dart';
import 'package:permission_handler/permission_handler.dart';

final String userName = "1";
final Strategy strategy = Strategy.P2P_CLUSTER;

class peerwidget extends StatefulWidget {
  @override
  _peerwidgetState createState() => _peerwidgetState();
}

String mytext = "";

class _peerwidgetState extends State<peerwidget> {
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
          title: const Text("Somecrab", textDirection: TextDirection.ltr),
          actions: <Widget>[
            IconButton(
                icon: const Icon(Icons.settings),
                onPressed: () {
                  print("OPENING SETTINGS FOR BACKGROUND COLOR AND SUCH");
                }),
          ]),
      body: SingleChildScrollView(
        child: Column(children: <Widget>[
          Container(
            child: Text(mytext),
          ),
          ElevatedButton(
            style: ElevatedButton.styleFrom(
              minimumSize: const Size(140, 50),
            ),
            onPressed: () {
              print("location");
              //setstate oderso, nächsts Bild holle
              locationpermission();
            },
            child: Column(
              // Replace with a Row for horizontal icon + text
              children: const <Widget>[
                Icon(Icons.arrow_forward),
                Text("Ask location"),
              ],
            ),
          ),
          ElevatedButton(
            style: ElevatedButton.styleFrom(
              minimumSize: const Size(140, 50),
            ),
            onPressed: () {
              print("storage");
              //setstate oderso, nächsts Bild holle
              storagepermission();
            },
            child: Column(
              // Replace with a Row for horizontal icon + text
              children: const <Widget>[
                Icon(Icons.arrow_forward),
                Text("Ask storage"),
              ],
            ),
          ),
          ElevatedButton(
            style: ElevatedButton.styleFrom(
              minimumSize: const Size(140, 50),
            ),
            onPressed: () {
              print("Kill all");
              //setstate oderso, nächsts Bild holle
              closeall();
            },
            child: Column(
              // Replace with a Row for horizontal icon + text
              children: const <Widget>[
                Icon(Icons.arrow_forward),
                Text("Kill all"),
              ],
            ),
          ),
          ElevatedButton(
            style: ElevatedButton.styleFrom(
              minimumSize: const Size(140, 50),
            ),
            onPressed: () {
              print("CONNECT");
              //setstate oderso, nächsts Bild holle

              setState(() {
                connect();
              });
            },
            child: Column(
              // Replace with a Row for horizontal icon + text
              children: const <Widget>[
                Icon(Icons.arrow_forward),
                Text("CONNECT"),
              ],
            ),
          ),
          ElevatedButton(
            style: ElevatedButton.styleFrom(
              minimumSize: const Size(140, 50),
            ),
            onPressed: () {
              print("DISCOVER");
              //setstate oderso, nächsts Bild holle
              setState(() {
                discover();
              });
            },
            child: Column(
              // Replace with a Row for horizontal icon + text
              children: const <Widget>[
                Icon(Icons.arrow_forward),
                Text("DISCOVER"),
              ],
            ),
          ),
        ]),
      ),
    );
  }
}

onConnectionInitiated() {
  mytext = "onConnectionInitiated";
}

onConnectionResult() {
  mytext = "onConnectionResult";
}

onDisconnected() {
  mytext = "onConnectionDisconnected";
}

onEndpointFound() {
  mytext = "onEndpointFound";
}

onEndpointLost() {
  mytext = "onEndpointLost";
}

connect() async {
  print("connecting started...");
  mytext = "connection started";
  try {
    await Nearby().startAdvertising(
      userName,
      strategy,
      onConnectionInitiated: (String id, ConnectionInfo info) {
        print("connection initiated!" + id + info.toString());

        onConnectionInitiated();
        // Called whenever a discoverer requests connection

        Nearby().acceptConnection(id, onPayLoadRecieved: (endpointId, payload) {
          // called whenever a payload is recieved.
        }, onPayloadTransferUpdate: (endpointId, payloadTransferUpdate) {
          // gives status of a payload
          // e.g success/failure/in_progress
          // bytes transferred and total bytes etc
        });
      },
      onConnectionResult: (String id, Status status) {
        print("connected?");
        onConnectionResult();
        // Called when connection is accepted/rejected
      },
      onDisconnected: (String id) {
        print("disconnected?");
        // Callled whenever a discoverer disconnects from advertiser
        onDisconnected();
      },
      serviceId: "com.simon.fluttershit", // uniquely identifies your app
    );
  } catch (exception) {
    print("insufficient permissions or some error!");
    // platform exceptions like unable to start bluetooth or insufficient permissions
  }
}

discover() async {
  mytext = "discovery started";
  print("Discovery started!");
  try {
    await Nearby().startDiscovery(
      userName,
      strategy,
      onEndpointFound: (String id, String userName, String serviceId) {
        print("found something: " + id + userName + serviceId);
        onEndpointFound();

        // to be called by discover whenever an endpoint is found
// callbacks are similar to those in startAdvertising method
        try {
          Nearby().requestConnection(
            userName,
            id,
            onConnectionInitiated: (id, info) {},
            onConnectionResult: (id, status) {},
            onDisconnected: (id) {},
          );
        } catch (exception) {
          // called if request was invalid
        }
      },
      serviceId: "com.simon.fluttershit",
      onEndpointLost: (String? endpointId) {
        print("was lost" + endpointId.toString());
        onEndpointLost();
      }, // uniquely identifies your app
    );
  } catch (e) {
    print("insufficient permissions or some error!" + e.toString());
    // platform exceptions like unable to start bluetooth or insufficient permissions
  }
}

void locationpermission() {
  Nearby().askLocationPermission();
}

void storagepermission() {
  Nearby().askExternalStoragePermission();
}

void closeall() {
  Nearby().stopAdvertising();
  Nearby().stopDiscovery();
}



EDIT It seems to work with my Samsung tablet and my huawei mate 10 LTE, but not with my Huawei P40 pro!


Solution

  • There were multiple problems here:

    1. Not all permissions were given, as kindly pointed out by @TheFunk
    2. Huawei P40 Pro doesn't have google services, thus not communicating properly via Peer To Peer
    3. List item
    4. I was using the P2P strategy STAR, instead of cluster, which now seems to work.
    5. My focus on NFC was wrong, because it doesn't matter if the device has NFC or not.
    6. My assumption that both devices need the same userName seems to be wrong. They can be different, as long as they're declared to find each EndPointId.

    Note: This question is one of two, which are about the same nearby_connections library of Flutter.
    For me this question has been solved and if you have trouble finding a working code you should check out this question, where I've posted the entire connection code, which works but does not yet receive packages. Flutter using nearby_connections in Peer to Peer to send and Receive a Package