2017年01月31日

[Android][Kotlin] AltBeaconを使ってiBeaconを受信する

基本的に以下のサイトを参考にして実装しました。
AltBeaconを使ってAndroidでiBeaconを検知しよう

一応、AltBeaconのライブラリのコード全部見て、個人情報とか抜いてないことは確認した。
一部、ライブラリ本体には「android.permission.INTERNET」の権限付与されてないのに、ライブラリ内で「android.permission.INTERNET」を必要とするところがあったので見てみたら、距離計算のためのフォーマットファイル?をダウンロードしているだけだった。
android.permission.INTERNET」が付与されてない場合はローカルファイルを読みに行く実装でした。

上記のサイトと違う点。

・言語がKotlin
・startRangingBeaconsInRegion/stopRangingBeaconsInRegionをするタイミング
・onBeaconServiceConnectした時にNotifier等を削除


・言語がKotlin
Kotlin楽しいよ。Kotlin。わからないことだらけだけど!
配列の初期化とか無理やりチックに似できるのが楽しい(ぇ

・startRangingBeaconsInRegion/stopRangingBeaconsInRegionをするタイミング
参考にしたサイトではdidEnterRegionstartdidExitRegionstopしてるんだけど、BeaconManagerをunbind→bindすると何故かonBeaconServiceConnect後にdidEnterRegionが呼ばない。
なので、startRangingBeaconsInRegionが呼べずにRegionのモニタリングができなくなった。
ってことでdidDetermineStateForRegionの出入りのタイミングで登録、削除をしてあげるようにした。

・onBeaconServiceConnectした時にNotifier等を削除
BeaconActivityが破棄されて、もう一度生成され、BeaconManagerを取得しーのNotifierをセットするとaddされる感覚で通知がたくさん来るようになった。
まぁ、呼び出してるのadd〜〜〜なんだけど、、、。
unbindしたタイミングで破棄してくれないみたい。
同じインスタンスでセットする分には重複チェックされてるのかaddされてない感じ。
実装上はaddしてるんだけど、CopyOnWriteArraySetってクラス使っててよくわからない(調べてない)
なのでとりあえず、onBeaconServiceConnect時に削除するようにした。
unbindないしonDestroyとかのタイミングで消しても良さそうっちゃ良さそうだが、、、。


ってことで実装。
abstract class BeaconActivity : BaseActivity(), BeaconConsumer {


companion object {
private val TAG = "hoge"

// iBeaconのデータを認識するためのParserフォーマット
val IBEACON_FORMAT = "m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24"
}

// BeaconManagerクラスの変数を定義
protected var mBeaconManager: BeaconManager? = null
// Beacon UUIDの作成
protected var mBeaconIdentifier = Identifier.parse("hogehage-0000-0000-0000-000000000000")
protected var mNearestBeacon: Beacon? = null

private val mRegion = Region("unique-id-001", mBeaconIdentifier, null, null)


override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// staticメソッドでBeaconManagerクラスのインスタンスを取得
mBeaconManager = BeaconManager.getInstanceForApplication(applicationContext)
// BeaconParseをBeaconManagerに設定
mBeaconManager?.beaconParsers?.add(BeaconParser().setBeaconLayout(IBEACON_FORMAT))

}

override fun onResume() {
super.onResume()
mBeaconManager?.bind(this)
}

override fun onPause() {
super.onPause()
mBeaconManager?.unbind(this)
}


override fun onBeaconServiceConnect() {
Log.d(TAG, "onBeaconServiceConnect")
// 2重登録されるので一旦削除
mBeaconManager?.removeAllMonitorNotifiers()
mBeaconManager?.removeAllRangeNotifiers()
mBeaconManager?.rangedRegions?.forEach {region ->
mBeaconManager?.stopRangingBeaconsInRegion(region)
}
// BeaconManagerクラスのモニタリング設定
mBeaconManager?.addMonitorNotifier(mMonitorNotifier)
// BeaconManagerクラスのレンジング設定
mBeaconManager?.addRangeNotifier(mRangeNotifier)
startMonitoringBeacons()
}

/**
* ビーコンのモニタリング開始
*/
private fun startMonitoringBeacons() {

try {
// モニタリングの開始
mBeaconManager?.startMonitoringBeaconsInRegion(mRegion)
} catch (e: RemoteException) {
e.printStackTrace()
}

}

/**
* ビーコンモニター
*/
private val mMonitorNotifier = object : MonitorNotifier {
override fun didEnterRegion(region: Region) {
// 領域進入時に実行
Log.d(TAG, "didEnterRegion")
}

override fun didExitRegion(region: Region) {
// 領域退出時に実行
Log.d(TAG, "didExitRegion")
}

override fun didDetermineStateForRegion(i: Int, region: Region) {
// 領域への侵入/退出のステータスが変化したときに実行
Log.d(TAG, "didDetermineStateForRegion i = " + i)

try {
if (i == 1) {
mBeaconManager?.startRangingBeaconsInRegion(region)
} else {
mBeaconManager?.stopRangingBeaconsInRegion(region)
}
} catch (e: RemoteException) {
Log.d(TAG, "didDetermineStateForRegion e = " + e.message)
}

}
}

/**
* ビーコンレンジ
*/
private val mRangeNotifier = RangeNotifier { beacons, region ->
// 検出したビーコンの情報を全部Logに書き出す

for (beacon in beacons) {
Log.d(TAG, "UUID:" + beacon.id1 + ", major:" + beacon.id2 +
", minor:" + beacon.id3 + ", Distance:" + beacon.distance +
",RSSI" + beacon.rssi + ", TxPower" + beacon.txPower)
}
}
}

これで受信できるようになるはず。
ただ、BlueToothがON状態じゃないと受信できないのと、6系以上は「Manifest.permission.ACCESS_COARSE_LOCATION」が許可されていないと受信できない。

posted by すとれん at 21:00 | Comment(0) | Android開発ネタ | このブログの読者になる | 更新情報をチェックする