ニフクラmobile backendの新Kotlin SDKについて

4年ぶりのqiita記事になりますが、今回FCJTが開催している[アドベントカレンダー](https://qiita.com/advent-calendar/2021/fjct)に参加するために、記事を書くことになりました。ということで、20日目の記事となりますが、どうぞよろしくお願いします。
昨日は[ysaotome](https://qiita.com/ysaotome)さんのがっちり内容となった [ニフクラ上の Docker ホストへ VMware Tanzu Community Edition(TCE) のマネージドクラスタを構築してみた（V0.9.1）](https://sotm.jp/2021/12/18/vmware-tanzu-community-edition-v091-managed-clusters-on-docker-on-nifcloud/)内容でしたが、今回はかなり初心者向けの内容になります。ニフクラmBaaSが2年ぶりに新SDKとなるKotlin SDK (ncmb_kotlin)を対応し、12月中に正式にリリースすることになりますので、こちらについていくつか紹介できればなと思います。

### ニフクラ mobile backend (mBaaS)とは

おさらいですが、初めての方もいるかもしれないので、雄一かつ歴史も長く国産mBaaSについて紹介いたします。mBaaS（mobile backend as a Service）とは、スマートフォンアプリでよく利用される汎用的な機能をクラウドから提供するサービスです。

クラウド上に用意された機能をAPIで呼び出すだけで利用できるので、サーバー開発・運用不要でよりリッチなバックエンド機能をアプリに実装することができ、工数削減によるコストカット・スピードアップすることができます。[ニフクラmBaaS](https://mbaas.nifcloud.com/) はニフクラが提供するmBaaSとなります。2013年から提供はじめ、現在多くアプリに採用いただいております。

### ニフクラmBaaSのKotlin SDKについて

#### SDKの役割について

SDKの役割について紹介いたします。通常だと、データストア、会員管理なmBaaSが用意するREST APIがありますので、REST APIの仕様を沿って、リクエストをすることで、機能を使うことができます。ニフクラmBaaSのREST API仕様は特定ヘッダー情報にはたくさんフォーマットに従って作る情報が多く、特にアクセスセキュリティ上でシグネチャーの計算も毎回リクエストするときに必ず行わないといけないので、かなり大変な作業になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18698/7efeb9c8-3de5-cc42-7874-6cf536ed3eab.png)
そこで、SDKが登場します。アプリとサーバの間いにおり、アプリ側は言語ごとに簡単なコードを書く事で、REST APIの複雑仕様に応じて、SDKがリクエストを生成し、レスポンスを受け取って、アプリ側でその結果を言語ごとに定義している形を返却してくれます。ある意味、アプリとサーバの通訳役を行っているとも言えますね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18698/69c7efa8-f959-a223-5876-893b21d7803e.png)

#### なぜKotlin SDKなのか

- Android開発の次世代言語
  - 2011年にJetbrains社がKotlinを開発始めていることを公表してから注目が集め、2016年にKotlin言語がバージョンv1.0.0が初めてリリースされました。2019年にGoogle社はAndroid開発用プログラミング主言語としてKotlinが勧められました。
- Javaと何が違うのか
  - 様々なJavaの問題点を考慮し、作られた言語なので、開発側として比較すると、非常に直感的にコード書くことと、例外発生（特にnull関連の Runtime例外）の事前防ぐ点はとても優れています。
詳細は[こちら](https://kotlinlang.org/docs/comparison-to-java.html#what-kotlin-has-that-java-does-not)をご覧ください。

#### 新Kotlin SDKの紹介ポイントまとめ

今までのAndroid SDKとどこが違うなのか、主にインターフェースの部分ですが、いくつかポイントとして紹介させていただきます。
これから移行する方、新規利用する方、Kotlin SDKについてぜひ参考にしていただければと思います。

##### 1.データ登録など非同期処理のコールバックが簡単に書けるように

サーバとの通信が必要な処理には同期処理、非同期処理がありますが、非同期処理の場合、サーバからレスポンスが帰った後の処理としてコールバック（予約処理）を指定することができますが、こちらのコールバックはAndroid SDKの場合、それぞれ通信に応じてコールバッククラスが違っていたので、利用する場合、レファレンスを確認する必要がありました。Kotlin SDKの場合、コールバッククラスは`NCMBCallback` しかありませんので、その点はより利用しやすくなるかと思います。

一番シンプルな例としてデータ登録処理ですが、今までのAndroid SDKの場合、以下のように `DoneCallback` を定義する必要があります。データ取得する処理の場合、 `FetchCallback` を利用します。

```java
NCMBObject obj = new NCMBObject("SaveObjectTest");
obj.put("key", "value");
obj.saveInBackground(new DoneCallback() {
    @Override
    public void done(NCMBException e) {
        if (e != null) {
            //エラー発生時の処理
        } else {
            //成功時の処理
        }
    }
});
```
但し、Kotlin SDKの場合、以下のようにどちらでも`NCMBCallback`を利用できます。

```kotlin
val obj = NCMBObject("TestClass")
obj.put("message", "Hello, NCMB!")
obj.saveInBackground(NCMBCallback { e, ncmbObj ->
    if (e != null) {
            //保存に失敗した場合の処理
            Log.d("error","保存に失敗しました : " + e.message)
    } else {
            //保存に成功した場合の処理
            val result = ncmbObj as NCMBObject
            Log.d("success","保存に成功しました ObjectID :" + result.getObjectId())
    }
})
```

##### 2. クエリのクラスごとに専用メソッドを用意

データを検索処理では、どちらも `NCMBQuery` というクラスを利用し、検索条件を設定していきますが、Android SDKと `NCMBQuery` の初期化するコードは違いますので、移行する時に注意する必要。

Android SDKは以下のようにクエリを書きます。データストアクラスにある `TestClass` に対する検索クエリ初期化です。

```java
NCMBQuery<NCMBObject> query = new NCMBQuery<>("TestClass");
```
標準クラスに対する検索、例えば会員の検索の場合は以下のように書きます。

```java
NCMBQuery<NCMBUser> query = new NCMBQuery<>("user");
```
上記のように `NCMBUser` と`user`をセットとして指定する必要がありますが、`user`ではない文字列を指定しても、コンパイル時には通りますが、実行時に例外発生するリスクがあります。

Kotlin SDKの場合は、そこを改善し、以下のように書く必要があり、よりシンプルになり、上記の実行時のエラーを防ぐことができます。

```kotlin
val query1 = NCMBQuery.forObject("TestClass")
val query2 = NCMBQuery.forUser()
```

##### 3.プッシュ通知の初期化が独立に

ニフクラmBaaSのSDKでは、プッシュ通知を利用するために、SDK側での設定も必要になりることが多く、その設定の中に、アプリの初期コードであるプッシュ通知用の端末情報の登録も手動で行うことが多いです。但し、Android SDKだけでは、端末情報登録という処理はSDK初期化時に含まれる仕様となっています。つまり、以下のコードを書けば、SDKの初期化もプッシュ通知用の初期化も実施されています。`AndroidManifest` ファイルなどの設定が揃えていれば、プッシュ通知の機能を利用することができます。

```java
 // APIキーの設定とSDK初期化、配信端末の登録
 NCMB.initialize(this.getApplicationContext(), "APP_KEY", "CLIENT_KEY");
```

こちらの仕様は、良い点として、お客様が端末情報の処理は気にせず、書かないといけないコードが減るので、便利ではありますが、但し、プッシュ通知を意図的に使いたくない場合は制御が難しい点もあります。

そこで、Kotlin SDKでは、プッシュ通知の初期化メソッドを新たに定義し、SDK初期化と別として設けられます。従って、以下のように、プッシュ通知を利用したい場合、`initializePush()` というメソッドを実施することで、端末情報の登録など必要な設定は実施されます。

```kotlin
NCMB.initialize(this.getApplicationContext(),"YOUR_APPLICATION_KEY","YOUR_CLIENT_KEY");
NCMB.initializePush(this.getApplicationContext())
```
現在、`initializePush()` はデバイストークンを取得し、端末情報の登録・更新を実施する処理をしていますが、もっと便利に使っていただくために、今後再インストールなどのエラーが発生時の対応も含まれる予定しています。

##### 4.位置情報の利用は独自クラスに

今まで、Android SDKでは、位置情報データの扱いは`Location`という標準クラスを利用して、データを扱う時に以下のように書くのです。

```java
Location geo = new Location("test");
geo.setLatitude(10.0);
geo.setLongitude(10.0);

NCMBObject obj = new NCMBObject("TestClass");
obj.put("geo", geo);
```
こちらのLocationを利用するために、`android.location.Location`をインポートしないといけないのですが、今後Android以外のプラットフォームも利用すると想定し、独自クラス（ `NCMBGeoPoint`）を設けることになりました。KotlinSDKの場合だと、以下のようにコードを書くことで、同様に機能は実現できます。

```kotlin
val latitude : Double = 35.6666269
val longitude : Double = 139.765607
val obj = NCMBObject("TestClass")
val geopoint = NCMBGeoPoint(latitude, longitude)
obj.put("geoPoint", geopoint)
```

### まとめ

現在のAndroid SDKと違う点、細かいところは他にまだありますが、移行しやすいために、なるべくお客様が負荷かからないように、メソッド名など維持できるところは維持するようにしています。12月中に公式にv1.0.0リリースする予定しており、今回開発者ドキュメントも含まれ、公式サポートも対象に、一緒に公開する予定です。ぜひリリースされましたら、お試しください。

公式バージョンでもまだ不足部分があり、またいただいたフィードバックの基づいて、今後も定期的にバージョンアップし、リリース予定です。ぜひ安定に利用しやすいSDKを目指していきますので、ぜひフィードバックがあれば、Kotlin SDKの [githubリポジトリ](https://github.com/NIFCLOUD-mbaas/ncmb_kotlin) にissueなどご登録ください。

以上ですが、明日は [@kodakku](https://qiita.com/kodakku)さんの __教師なし学習で周期表(金属)を分析してみる【主成分分析・R・Python】__の内容になります。お楽しみに！


### 参考

https://en.wikipedia.org/wiki/Kotlin_(programming_language)

https://kotlinlang.org/docs/comparison-to-java.html#what-kotlin-has-that-java-does-not