so recently my friends and i thought about creating an app that allows somewhat of realtime communication between the connected devices, without the need of a webserver. More explicitily, it should be an app, where a single device (master/host) create a game/session and multiple devices (slaves/clients) can join. after establishing all necessary connections (4-5 clients), the host should be able to broadcast data to the clients. Hence i researched a bit and if i understand it correctly the best guess for android are either the WiFi direct oder the google nearby connections api.
Q1. Is this the most simple approach to the desired goal ? or is this already too deep?
So i played a bit around with the connections api, i made a simple application and just used the code from the Nearby Documentation. Since im new to Kotlin, it could also be a rather simple mistake, however after a 2 hours, i swapped back to java with the same error. when the clients try to discover the host, they triggered their OnFailureListener. I tried to search for a solution online (including SO), but i could not find any useful information.
Im testing the application on a HTC ONE M8 and a Samsung Galaxy S7. To Ensure the Nearby Connection API features should work I also downloaded 2 example apps and those worked just fine. I tried how these handled the usage of the api but could not find the important part.
Q2. Where do i use the API wrong ? Or is it really just a error in the coding ?
MainActivity.kt
private const val TAG = android.R.attr.packageNames.toString() + "/Filter"
class MainActivity : AppCompatActivity() {
private lateinit var connectionClient : ConnectionsClient
private val payloadCallback = object : PayloadCallback() {
override fun onPayloadReceived(p0: String, p1: Payload) {
Toast.makeText(applicationContext, "Payload Received", Toast.LENGTH_SHORT).show()
}
override fun onPayloadTransferUpdate(p0: String, p1: PayloadTransferUpdate) {
Toast.makeText(applicationContext, "Payload Transfer Update", Toast.LENGTH_SHORT).show()
}
}
private val connPoint = object : ConnectionLifecycleCallback() {
override fun onConnectionInitiated(p0: String, p1: ConnectionInfo) {
connectionClient.acceptConnection(p0, payloadCallback)
Log.i(TAG, "OnConnectionInitiated")
}
override fun onConnectionResult(p0: String, p1: ConnectionResolution) {
when(p1.status.statusCode){
ConnectionsStatusCodes.STATUS_OK -> Log.i(TAG, "ConnectionsStatusCodes STATUS_OK")
ConnectionsStatusCodes.STATUS_CONNECTION_REJECTED -> Log.i(TAG, "ConnectionsStatusCodes STATUS_CONNECTION_REJECTED")
ConnectionsStatusCodes.STATUS_ERROR -> Log.i(TAG, "ConnectionsStatusCodes STATUS_ERROR")
else -> Log.i(TAG, "ConnectionsStatusCodes STATUS_UNKNOWN")
}
}
override fun onDisconnected(p0: String) {
Log.i(TAG, "onDisconnected $p0")
}
}
private val endPoint = object : EndpointDiscoveryCallback() {
override fun onEndpointFound(p0: String, p1: DiscoveredEndpointInfo) {
Log.i(TAG, "onEndpointFound ID: $p0 Name: ${p1.endpointName} ")
connectionClient.requestConnection(p1.endpointName, p0, connPoint)
.addOnSuccessListener {
Log.i(TAG, "OnSuccessListener requestConnection")
}
.addOnFailureListener {
Log.i(TAG, "OnFailureListener requestConnection")
}
}
override fun onEndpointLost(p0: String) {
Log.i(TAG, "$p0 disconnected")
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
connectionClient = Nearby.getConnectionsClient(this.applicationContext)
//Toast.makeText(applicationContext, connectionClient.instanceId, Toast.LENGTH_SHORT).show()
setButtonOnClick()
}
override fun onStop() {
connectionClient.stopAllEndpoints()
connectionClient.stopAdvertising()
connectionClient.stopDiscovery()
super.onStop()
}
private fun setButtonOnClick(){
val create = findViewById<Button>(R.id.create_btn)
val join = findViewById<Button>(R.id.join_btn)
create.setOnClickListener{ _ -> CreateGroup()}
join.setOnClickListener{ _ -> JoinGroup()}
Log.i(TAG, "On Click Listener set")
}
private fun CreateGroup(){
Log.i(TAG, "Starting Advertising")
connectionClient
.startAdvertising(android.os.Build.MODEL,
packageName.toString(),
connPoint,
AdvertisingOptions.Builder().apply{
setStrategy(Strategy.P2P_CLUSTER)
}.build())
.addOnSuccessListener {
OnSuccessListener<Void> {
Log.i(TAG, "OnSuccessListener CreateGroup() was triggered")
}
}
.addOnFailureListener {
OnFailureListener {
Log.i(TAG, "OnFailureListener CreateGroup() was triggered")
}
}
}
private fun JoinGroup(){
Log.i(TAG, "Starting Discovering")
connectionClient.startDiscovery(packageName.toString(),
endPoint,
DiscoveryOptions.Builder().apply{
setStrategy(Strategy.P2P_CLUSTER)
}.build())
.addOnSuccessListener {
OnSuccessListener<Void> {
Log.i(TAG, "OnSuccessListener JoinGroup() was triggered")
}
}
.addOnFailureListener {
OnFailureListener {
Log.i(TAG, "OnSuccessListener JoinGroup() was triggered")
}
}
}
}
Android Manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.testapplication">
<!-- Required for Nearby Connections -->
<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" />
<!-- Optional: only required for FILE payloads -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>