Nearby Service: Nearby Connection - Huawei Developers
1 Service Process
{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
The process can be divided into four phases.
1. Broadcast and scanning phase: The broadcaster starts broadcasting, and the discoverer starts scanning to discover the broadcaster.
2. Connection setup phase: The discoverer initiates a connection and starts a symmetric authentication process, and the two endpoints independently accept or reject the connection request.
3. Data transmission phase: After the connection is set up, the two endpoints start data exchange.
4. Disconnection phase: Either endpoint initiates a disconnection request to notify the remote endpoint of the disconnection.
Broadcast and scanning:
a. The broadcaster calls startBroadcasting() to start broadcasting.
b. The discoverer calls startScan() to start scanning for nearby devices.
c. The onFound() method notifies the scanning result.
Connection setup:
a. The discoverer calls requestConnect() to initiate a connection request to the broadcaster.
b. After onEstablish() notifies the two endpoints of the connection startup, the two endpoints can call acceptConnect() to accept the connection or call rejectConnect() to reject the connection.
c. The onResult() method notifies the two endpoints of the connection result. A connection can be set up only when both endpoints accept the connection.
Data transmission:
a. After the connection is set up, both endpoints can call sendData() to send data to the remote endpoint.
b. The data subscriber is notified by onReceived() that the data is received. Both endpoints are notified by onTransferUpdate() of the current transmission status.
Disconnection:
The endpoint that actively disconnects from the remote endpoint calls disconnect() to disconnect from the remote endpoint. The remote endpoint is notified by onDisconnected() of the disconnection.
2 Procedure
2.1 Declaring System Permissions
To use Nearby Discovery and Nearby Transfer APIs in Nearby Connection development scenarios, your app must declare the appropriate permissions based on the policies used. For more policy information, see Selecting a Policy. For example, to use the POLICY_STAR policy to develop a file transfer app, you need to add specific permissions to the AndroidManifest.xml file.
Code:
<!-- Required for Nearby Discovery and Nearby Transfer -->
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!-- Required for FILE payloads -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
The ACCESS_FINE_LOCATION, WRITE_EXTERNAL_STORAGE, and READ_EXTERNAL_STORAGE are dangerous system permissions, so you must dynamically apply for these permissions. If your app does not have the permissions, Nearby Service will reject your app to enable broadcast or discovery.
2.2 Selecting a Policy
Nearby Discovery supports three connection policies: POLICY_MESH, POLICY_STAR, and POLICY_P2P. Select a policy based on your application scenario.
Note:
To use a policy, your app must declare the following permissions:
BLUETOOTH
BLUETOOTH_ADMIN
ACCESS_WIFI_STATE
CHANGE_WIFI_STATE
ACCESS_COARSE_LOCATION
In addition, ACCESS_COARSE_LOCATION needs to be replaced with ACCESS_FINE_LOCATION on the device running Android Q or later.
The sample code for selecting a policy and creating the BroadcastOption object is as follows:
Code:
Policy policy = Policy.POLICY_STAR;
BroadcastOption broadcastOption = new BroadcastOption.Builder().setPolicy (policy).build();
2.2.1 POLICY_MESH
POLICY_MESH is a point-to-point connection policy that supports an M-to-N or cluster-shaped connection topology and is used by default. This enables the connection of clusters of devices within a radio range, in which each device can both initiate outgoing connections to M other devices and accept incoming connections from N other devices.
This policy is more flexible than POLICY_STAR in terms of topology constraints, but brings lower connection bandwidth. However, it is well suited for scenarios that require smaller bandwidth and a more mesh-like experience such as multiplayer gaming.
2.2.2 POLICY_STAR
POLICY_STAR is a point-to-point connection policy that supports a 1-to-N or star-shaped connection topology. This enables the connection of devices within a radio range in a star shape, where each device can, at any given time, play the role of either a hub (where it can accept incoming connections from other devices), or a branch (where it can initiate an outgoing connection to a single hub). However, a device cannot play the two roles at the same time.
This policy has stricter topology constraints than POLICY_MESH, but provides higher connection bandwidth. It is well suited for scenarios that require high bandwidth, for example, sharing a video with friends.
2.2.3 POLICY_P2P
POLICY_P2P is a point-to-point connection policy that supports a 1-to-1 connection topology. With this policy, devices within a radio range are connected to reach the greatest possible throughput. Only a single connection is allowed at a time.
This policy has stricter topology constraints than POLICY_STAR, but provides higher connection bandwidth. It is well suited for scenarios that require high bandwidth, for example, sharing a large video to another device.
2.3 Broadcast and Scanning
Once you grant the permissions required by the app and select a policy for your app, you can start broadcasting and scanning to discover nearby devices.
2.3.1 Starting Broadcasting
The broadcaster uses the selected policy and serviceId parameters to call startBroadcasting() to start broadcasting. The serviceId parameter uniquely identifies your app. You are advised to use the package name of your app as the value of serviceId, for example, com.huawei.example.myapp.
The sample code is as follows:
Code:
private void doStartBroadcasting() {
Policy policy = Policy.POLICY_STAR;
BroadcastOption broadcastOption = new BroadcastOption.Builder().setPolicy(policy).build();
Nearby.getDiscoveryEngine(getApplicationContext())
.startBroadcasting(name, serviceId, connectCallback, broadcastOption)
.addOnSuccessListener(
new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void aVoid) {
/* We are broadcasting. */
}
})
.addOnFailureListener(
new OnFailureListener() {
@Override
public void onFailure(Exception e) {
/* Fail to start broadcasting. */
}
});
}
In the preceding information, connectCallback is a connection listening callback class instance that notifies you of the connection status. For details about the connectCallback class and sample code, please refer to Confirming the Connection.
2.3.2 Starting Scanning
The discoverer uses the selected policy and serviceId parameters to call startScan() to start scanning to discover nearby devices.
The sample code is as follows:
Code:
private void doStartScan() {
Policy policy = Policy.POLICY_STAR;
ScanOption scanOption = new ScanOption.Builder().setPolicy(policy).build();
Nearby.getDiscoveryEngine(getApplicationContext())
.startScan(serviceId, scanEndpointCallback, scanOption)
.addOnSuccessListener(
new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void aVoid) {
/* Start scan success. */
}
})
.addOnFailureListener(
new OnFailureListener() {
@Override
public void onFailure(Exception e) {
/* Fail to start scan. */
}
});
}
In the preceding information, scanEndpointCallback is a scanning listening callback class instance that notifies the discoverer of the scanning result, for example, a device is discovered or a device is lost.
Code:
private ScanEndpointCallback scanEndpointCallback =
new ScanEndpointCallback() {
@Override
public void onFound(String endpointId, ScanEndpointInfo discoveryEndpointInfo) {
mEndpointId = endpointId;
mDiscoveryEngine.requestConnect(myNameStr, mEndpointId, mConnCb);
}
@Override
public void onLost(String endpointId) {
Log.d(TAG, "Nearby Connection Demo app: Lost endpoint: " + endpointId);
}
};
2.3.3 Stopping Broadcasting
To stop broadcasting, you can call stopBroadcasting(). The broadcaster can not receive a connection request from the discoverer afterward.
2.3.4 Stopping Scanning
To stop scanning, you can call stopScan(). The discoverer can still request a connection to a discovered device afterward. Generally, once you find the device you want to connect to, call stopScan() to stop scanning.
2.4 Connection Setup
2.4.1 Initiating a Connection
When nearby devices are found, the discoverer can call requestConnect() to initiate connections.
The sample code is as follows:
Code:
private void doStartConnect(String name, String endpointId) throws RemoteException {
Nearby.getDiscoveryEngine(getApplicationContext())
.requestConnect(name, endpointId, connectCallback)
.addOnSuccessListener(
new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void aVoid) {
/* Request success. */
}
})
.addOnFailureListener(
new OnFailureListener() {
@Override
public void onFailure(Exception e) {
/* Fail to request connect. */
}
});
}
You can show the list of discovered devices to users and allow them to choose which devices to connect to based on your requirements.
2.4.2 Confirming the Connection
After the discoverer requests to set up a connection with the broadcaster, the discoverer notifies the two parties of the connection setup by calling back the onEstablish() method of connectCallback. Both parties must accept the connection by calling acceptConnect() or reject the connection by calling rejectConnect(). The connection can be set up only when both parties accept the connection. If one or both of them choose to reject the connection, the connection fails. In either mode, the connection result is notified through the onResult() method.
The sample code is as follows:
Code:
private final ConnectCallback connectCallback =
new ConnectCallback() {
@Override
public void onEstablish(String endpointId, ConnectInfo connectInfo) {
/* Accept the connection request without notifying user. */
Nearby.getDiscoveryEngine(getApplicationContext()).acceptConnect(endpointId, dataCallback);
}
@Override
public void onResult(String endpointId, ConnectResult result) {
switch (result.getStatus().getStatusCode()) {
case StatusCode.STATUS_SUCCESS:
/* The connection was established successfully, we can exchange data. */
break;
case StatusCode.STATUS_CONNECT_REJECTED:
/* The Connection was rejected. */
break;
default:
/* other unknown status code. */
}
}
@Override
public void onDisconnected(String endpointId) {
/* The connection was disconneted. */
}
};
This example shows a way for both parties to accept the connection automatically. You can use other methods to confirm the connection as required.
2.4.3 Authenticating the Connection
Your app can provide a way for users to confirm the connection to a specified device. For example, you can use an authentication token, which may be a short random character string or digit. Typically, this involves displaying the token on two devices and requiring the user to enter or confirm the token manually, similar to a Bluetooth pairing dialog box. The following describes how to authenticate the connection by confirming the pairing code in a dialog box:
The sample code is as follows:
Code:
@Override
public void onEstablish(String endpointId, ConnectInfo connectInfo) {
AlertDialog.Builder builder = new AlertDialog.Builder(getApplicationContext());
builder.setTitle(connectInfo.getEndpointName() + " request connection")
.setMessage("Please confirm the match code is: " + connectInfo.getAuthCode())
.setPositiveButton(
"Accept",
(DialogInterface dialog, int which) ->
/* Accept the connection. */
Nearby.getDiscoveryEngine(getApplicationContext())
.acceptConnect(endpointId, dataCallback))
.setNegativeButton(
"Reject",
(DialogInterface dialog, int which) ->
/* Reject the connection. */
Nearby.getDiscoveryEngine(getApplicationContext())
.rejectConnect(endpointId))
.setIcon(android.R.drawable.ic_dialog_alert);
AlertDialog alert = builder.create();
alert.show();
}
2.5 Data Transmission
After devices are connected, data objects can be transmitted through the connection. Data objects are classified into byte arrays, files, and streams. You can call sendData() to send data and call onReceived() of DataCallback to receive data.
2.5.1 Data Type
BYTES
You can call Data.fromBytes() to create a data object of the Data.Type.BYTES type.
The following is the sample code for sending data of the BYTES type:
Code:
Data bytesData = Data.fromBytes(new byte[] {0xA, 0xA, 0xA, 0xA, 0xA});
Nearby.getTransferEngine(getApplicationContext()).sendData(toEndpointId, bytesData);
The following is the sample code for receiving data of the BYTES type:
Code:
static class BytesDataReceiver extends DataCallback {
@Override
public void onReceived(String endpointId, Data data) {
/* BYTES data is sent as a single block, so we can get complete data. */
if (data.getType() == Data.Type.BYTES) {
byte[] receivedBytes = data.asBytes();
}
}
@Override
public void onTransferUpdate(String endpointId, TransferStateUpdate update) {
/* We will receive TRANSFER_STATE_SUCCESS update after onReceived() called. */
}
}
FILE
You can call Data.fromFile() to create a data object of the Data.Type.FILE type.
The following is the sample code for sending data of the FILE type:
Code:
File fileToSend = new File(getApplicationContext().getFilesDir(), "fileSample.txt");
try {
Data fileData = Data.fromFile(fileToSend);
Nearby.getTransferEngine(getApplicationContext()).sendData(endpointList, fileData);
} catch (FileNotFoundException e) {
/* Exception handle. */
}
To be more efficient, you can create a FILE type using ParcelFileDescriptor, which minimizes file replication.
The sample code is as follows:
Code:
ParcelFileDescriptor pfd = getContentResolver().openFileDescriptor(uri, "r");
Data fileData = Data.fromFile(pfd);
When a file is received, it is saved in the Download directory, and it will be named after a string converted from fileData.getId(). After the transmission is complete, you can obtain the FILE object.
The sample code is as follows:
Code:
/* We can get the received file in the Download folder. */
File payloadFile = fileData.asFile().asJavaFile();
STREAM
You can call Data.fromStream() to create a data object of the Data.Type.STREAM type.
The following is the sample code for sending streams:
Code:
URL url = new URL("https://developers.huawei.com");
Data streamData = Data.fromStream(url.openStream());
Nearby.getTransferEngine(getApplicationContext()).sendData(toEndpointId, streamData);
When the onTransferUpdate() callback is successful, the subscriber can call streamData.asStream().asInputStream() or streamData.asStream().asParcelFileDescriptor() to obtain the stream object.
The sample code is as follows:
Code:
static class StreamDataReceiver extends DataCallback {
private final HashMap<Long, Data> incomingData = new HashMap<>();
@Override
public void onTransferUpdate(String endpointId, TransferStateUpdate update) {
if (update.getStatus() == TransferStateUpdate.Status.TRANSFER_STATE_SUCCESS) {
Data data = incomingData.get(update.getDataId());
InputStream inputStream = data.asStream().asInputStream();
/* Further processing... */
}
}
@Override
public void onReceived(String endpointId, Data data) {
incomingData.put(data.getId(), data);
}
}
2.5.2 Updating the Progress
The onTransferUpdate() method in the DataCallBack callback class provides the data sending or receiving progress update. Both parties can display the transmission progress to users in forms like a progress bar.
2.5.3 Canceling Transmission
To cancel the transmission during data receiving or sending, you can call the cancelDataTransfer() method of the TransferEngine class.
2.6 Disconnection
To disconnect from the remote endpoint, you can call the disconnect() method of the DiscoveryEngine class. Once this API is called, this endpoint cannot send or receive data.
Related
How to get public ip instead of private ip on tether or wifi
I was wondering if there was a way to have a public ip through wifi hotspot or usb hotspot instead of it assigning a private ip. Instead of getting a 192 ip be able to utilize the public ip ? Thanks,
USB-tether (cell phone to router).Trying to Port-Forward 554 from phone to router
I have a static ip cell phone, LTE service with public address: 25.25.25.25 USB-Tethered to an asus router Router has WAN address of: 192.168.42.134, Gateway and DNS is:192.168.43.129, I Port-Forward 80,8080,554,etc... to Desktop Computer Desktop Computer has HTTP Server and Darwin Streaming Server Listening on 80,8080,554 Lan address is:192.168.1.2 I got the http server working by using an app on the cellphone called PortForarder https://play.google.com/store/apps/details?id=at.bherbst.net&hl=en I forwarded port 8080 for incoming and 80 for target ...in settings I entered rmnet0 (25.25.25.25)for Public Interface (other choices were Lo(127.0.0.1),rndis0(192.168.42.129) ...for Target I entered router (192.168.42.134) From the Outside (on a different internet connection)I'm able to access my html server with this http://25.25.25.25:8080 My Problem: The app (portforwarder) is for non rooted phones, it will not let you forward ports lower than 1024,hence I cannot access my smtp stream on port 544 I'm trying to figure if the app uses iptables or routes traffic thru adb for forwarding there are other portforwading apps for rooted phones that do use iptables (can allow to portforward lower than 1024) but I cannot get them to work with usb-tethering, it just may be I'm not understanding the correct iptable to write. Can someone help me write an ip table that port forwards 544 from public interface(cell phone) to target host (router) ca
USB-tether (cell phone to router).Trying to Port-Forward 554 from phone to router
I have a static ip cell phone, LTE service with public address: 25.25.25.25 USB-Tethered to an asus router Router has WAN address of: 192.168.42.134, Gateway and DNS is:192.168.43.129, I Port-Forward 80,8080,554,etc... to Desktop Computer Desktop Computer has HTTP Server and Darwin Streaming Server Listening on 80,8080,554 Lan address is:192.168.1.2 I got the http server working by using an app on the cellphone called PortForarder https://play.google.com/store/apps/details?id=at.bherbst.net&hl=en I forwarded port 8080 for incoming and 80 for target ...in settings I entered rmnet0 (25.25.25.25)for Public Interface (other choices were Lo(127.0.0.1),rndis0(192.168.42.129) ...for Target I entered router (192.168.42.134) From the Outside (on a different internet connection)I'm able to access my html server with this http://25.25.25.25:8080 My Problem: The app (portforwarder) is for non rooted phones, it will not let you forward ports lower than 1024,hence I cannot access my smtp stream on port 544 I'm trying to figure if the app uses iptables or routes traffic thru adb for forwarding there are other portforwading apps for rooted phones that do use iptables (can allow to portforward lower than 1024) but I cannot get them to work with usb-tethering, it just may be I'm not understanding the correct iptable to write. Can someone help me write an ip table that port forwards 544 from public interface(cell phone) to target host (router) ca
Local IP addresses (IPv4 and IPv6)
Hi. I have Wifi disconnections frequently on my phone (Xiaomi Redmi 5) and my researches lend me to focus on IPv6. When my phone is connected to my home Wifi, I can see in the connections parameters that there are 2 local IP addresses : one IPv4 and another IPv6. I disabled in my router settings the IPv6 management but my phone still has an IPv6 address. What do I need to do (On the router or on the phone) to get rid of it? Thanks!
Dude, i was just coasting down the information highway, not actually looking for this, but found it nonetheless, and coincidentally i go thru the same rather annoying events. Did you ever solve it? Care to share?
Yep, it appears to me that while using a VPN disconnections didn't occur anymore. I don't understand why but if works. I use this workaround since.
I'll give that a try! Thanks
I don't think it's a problem with ipv4 or ipv6. precisely if you don't establish an IP address it can't be connected to WiFi. maybe you can try resetting the Router you are using. CMIIW
@Double Jo A Local IP address ( to be corect: Private IP address ) is an IP address that's reserved for internal use behind a router or other Network Address Translation (NAT) device, apart from the public. Private IP addresses are in contrast to public IP addresses, which are public and can't be used within a home or business network The Internet Assigned Numbers Authority (IANA) reserves the following IP address blocks for use as private IP addresses: 10.0.0.0 to 10.255.255.255 172.16.0.0 to 172.31.255.255 192.168.0.0 to 192.168.255.255 As one can see those all are IPv4 addresses.
How to Globally Monitor Network Status Changes?
HUAWEI Quick App provides the Network Status API, which can be used to monitor the network status of the current user's device, for example, whether the device is connected to the Internet and whether the device is connected to the Internet though Wi-Fi or mobile network. Developers can design their UIs differently based on the network type and traffic consumption of their apps. However, if the network status is monitored on each page, the same code needs to be provided for each page. The code amount will be large and coding may be missed for one or more pages. Is there any way to implement global monitoring? Yes, there is. You can call the Network Status API in the app.ux file of your app and call the Watch API on a specific page to obtain the current network status. Implementation Solution 1. Define a global object in app.ux. For details, please refer to the localeData object in the following sample code. The currentType attribute is defined in the object to store the result returned by the Network Status API. 2. Call the Network Status API in the lifecycle function onCreate() of the app.ux. 3. For a specific page, call the $watch() function to monitor currentType in step 1 and obtain the result in real time. More information, you can check https://forums.developer.huawei.com/forumPortal/en/topic/0204435497911800078?fid=0101246461018590361