Nearby Connectionsは難しい

過去にKotlin+Androidの事を書きました。

wwkk.hateblo.jp

結局諦めきれないで、そのまま勉強を継続してこつこつ作っていたりします。

その途中でGoogleさんが新しいandroid用の機能を追加したというニュースを見まして、調べてみました。

公式の説明はこちら

公式のほうにはJavaサンプルも乗っています。

結論からいうと、不具合を気にしないで使うだけなら簡単でしたが、まだテスト版という感じの位置づけらしく終了処理がきちんと出来ていなかった感じです。

あとandroid7.0.0以上という事らしい?

使い方としては単純です。

build.gradleに追加

dependencies {
    (略)
    implementation 'com.google.android.gms:play-services-nearby:15.0.1'

AndroidManifest.xmlにも追加

    <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_FINE_LOCATION" />

で、最初に引っかかったのが途中のアクセス権限 Nearby ConnectionsでstartAdvertising()などする前に確認しましょう。 なんかこの確認がとれないと実行で失敗したりする。

        if (ActivityCompat.checkSelfPermission(this,
                        Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this,
                    arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), 200)
        } 

あとは結構単純。

private var mConnectionClient = Nearby.getConnectionsClient(this)

// あとはAdvertisingとDiscoverでちょっと処理が違う
// 例えばこんな感じ
// mLocalNameは接続に使う固有のStrings
// NC_SERVICE_IDもサービスに使う
fun setAdvertising() {
    val aob = AdvertisingOptions.Builder()
    val mAdvertising = mConnectionClient
            .startAdvertising(
                    mLocalName,
                    NC_SERVICE_ID,
                    mConnectionLifecycleCallback,
                    aob.setStrategy(Strategy.P2P_STAR).build()
            )
            .addOnSuccessListener {
            // Advertise開始した
            }
            .addOnFailureListener{
                // Advertiseできなかった
            }
    }
}

private val mConnectionLifecycleCallback = object : ConnectionLifecycleCallback() {
    override fun onConnectionInitiated(endpointID: String, connectionInfo: ConnectionInfo) {}
    override fun onConnectionResult(endpointID: String, result: ConnectionResolution) {}
    override fun onDisconnected(endpointID: String) {}
}

companion object {
    const val NC_SERVICE_ID = "com.exsample.nearby.connections" // 推奨はあるが決まっていない
}

あとはdiscovoer側も似たようなことやってPayloadつかってデータ送信とかなんですが、終了処理が出来ない。 startAdvertising()してやるとbluetoothとかスイッチが自動で入って、近くの端末を探します。

で接続処理とかはプログラムでやって、データおわって「切断だーーー!」とmConnectionClient.stopAllEndpoints()を呼び出してもbluetoothは起動したまま。はて。

その為の専用のactivityやfragmentを用意してそのなかで実行させても変わらず。アプリケーションそのものを終了してバックグランドからも消してやって漸く止まる。

applicationContextを使って実行している感が満載すぎる挙動な気がする。