趣味は多い方がいい

バイク(GSR250S)とカメラと自転車とキャンプと旅行。ほかにもいろいろと。淫要無。

【備忘録】NCMB(iOS、Android)のObjectID取得でつまづいた話



Qiitaでやれ


iOSアプリでニフクラ(NCMB)を使用しプッシュ通知を発報する、そのためにアプリ上でNCMBのObjectIDを取得する必要があった。
ObjectIDはアプリインストールごとに一意の値が発行されるので、このアプリではそれを用いて端末の判別を行うつもりのようだ。要件定義した人がもういないので細かい仕様はワカラン(あるある)

ということで最初に作ったのがこれ。

    override func viewDidLoad() {
        super.viewDidLoad()
        
        let installation: NCMBInstallation = NCMBInstallation.currentInstallation
        let objectId =  installation.objectId

        // 以後、objectIdを使用した処理
    }


この処理でエラーもなくプッシュ通知も届いていると思っていた。が、ある時「なんか届くときと届かない時があるな?」と感じ、
あれこれ調べてみるとどうもアプリの初回起動時にはObjectIDがnil、二回目以降の起動では値が入るということが判明した。

なんで?と思ってあれこれ調べた際に偶然発見したのが公式のこの記事。
blog.mbaas.nifcloud.com

Monaca版のNCMBではInstallationId(ObjectID相当)を取得するのに遅延があり、インターバル実行などで解決しろとの内容だが、実はこの仕様はネイティブ版のSDKにもあるのではなかろうか。と思い調査したところビンゴ。NCMB初期化時に裏でいろいろ処理を回し、数秒後にObjectIDを発行していた。二回目以降ObjectIDが取れるのはおそらく初回起動での発行時にストレージに保存しているからか?(未調査)

つまり、SwiftでObjectIDを取得したい場合もMonacaと同様にObjectIDが見つかるまで定期実行する必要があるようだ。そこで改良したコードがこれ。

    override func viewDidLoad() {
        super.viewDidLoad()

        let timer = Timer(timeInterval: 1.0, repeats: true, block: {
            let installation: NCMBInstallation = NCMBInstallation.currentInstallation
            if let objectId = installation.objectId {
                // ここにobjectIdを使用した処理
                $0.invalidate()
            }
        })
        RunLoop.main.add(timer, forMode: .default)
    }


これで初回起動時にもObjectIDが取得できるようになった。(アプリ起動して2~3秒後くらいに取得できるようになるようだ)
ObjectIDを自分でセットする場合も初期化完了を待たないと「任意のObjectIDをセット→裏で初期化が完了しNCMBが発行したObjectIDで上書き」といった挙動になるため上記のような待ち合わせが必要。


ちなみに、Android(Kotlin)でも同様に初回起動時にnullが返ってくるため対策する必要がある。

    val scope = GlobalScope

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        scope.launch(Dispatchers.IO) {
            NCMB.initialize(this@MainActivity.applicationContext, "APP_KEY", "CLIENT_KEY")
            val ncmb = NCMBInstallation.getCurrentInstallation()
            var objectId:String? = null

            while (objectId == null) {
                objectId = ncmb.objectId
                Thread.sleep(1000)
            }
            // ここにobjectIdを使用した処理
        }
    }


試してみたところこれでObjectIDが取得できたが、while周りが明らかにクソコードなので、このコードを真似するのはお勧めしない。Kotlinのお勉強しようね!(自戒)