search
LoginSignup
0

posted at

updated at

NCMBのKotlin SDKを使ってTodoアプリを作ろう

NCMBでは公式SDKとしてSwift/Objective-C/Kotlin/Java/Unity/JavaScript SDKを用意しています。また、それ以外にもコミュニティSDKとして、非公式ながらFlutter/React Native/Google Apps Script/C#/Ruby/Python/PHPなど幅広い言語向けにSDKが開発されています。

今回は公式SDKの一つ、Kotlin SDKを使ってTodoアプリを作ってみます。まず画面の仕様とSDKの初期化について解説します。

完成版のコード

作成したデモアプリのコードはNCMBMania/Kotlin_Todo: Kotlin SDKを使ったTodoアプリですにアップロードしてあります。

ベースアプリのダウンロードまで

ベースについて

今回はKotlin + Jetpack Composeの組み合わせになっています。

NCMBMania/Kotlin_Todo_Handson

NCMB SDKのインストール

NCMB SDKはReleases · NIFCLOUD-mbaas/ncmb_kotlinよりダウンロードします。Zipファイルをダウンロードして展開すると、NCMB.jarというファイルが取得できます。このファイルをKotlinプロジェクトの app/libs 以下にコピーします。

app/build.gradle を開いて編集します。そして以下の4つを追加します。一番下のkotlinx-coroutinesを追加すると、保存処理などが同期的に処理できるようになります。

dependencies {
	// 省略
  implementation 'com.squareup.okhttp3:okhttp:4.8.1'
	implementation 'com.google.code.gson:gson:2.3.1'
	api files('libs/NCMB.jar')
	implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.9'
}

編集したら同期します。これでNCMB SDKの利用準備が整います。

Composeについて

今回は以下のComposeを用意しています。

  • Navigation
  • FormScreen
  • ListScreen
  • TaskRow
  • DetailScreen

Navigation

各画面への遷移をハンドリングしています。Navigationコンポーネントを利用しています。

FormScreen

Screenshot_20220414_155917.png

タスクの入力フォームです。新規登録、編集の両方で利用しています。

ListScreen

Screenshot_20220414_155935.png

タスクを一覧表示します。各行のデータはTaskRowにて表示しています。

TaskRow

タスクの一覧表示で、各行を表示するのに使います。

DetailScreen

Screenshot_20220414_155946.png

一覧表示で選択された、タスクの詳細表示を行います。

コードの編集

MainActivity.ktを開いてNCMBの初期化を行います。 super.onCreate の下でNCMBを初期化します。 YOUR_APPLICATION_KEYYOUR_CLIENT_KEY はそれぞれあなたのものと書き換えてください。

// 1. NCMBをインポート
import com.nifcloud.mbaas.core.NCMB

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // 2. NCMBを初期化
        NCMB.initialize(
            this,
            "YOUR_APPLICATION_KEY",
            "YOUR_CLIENT_KEY"
        )
        setContent {
						// 省略
        }
    }
}

これでNCMBの初期化が終わり、利用準備が整います。

タスク保存処理の実行

Navigation.ktの修正

Navigation.kt にて、NCMB SDKをインポートします。

// 1. NCMBObjectをインポートします
import com.nifcloud.mbaas.core.NCMBObject

次に var obj = 0 をNCMBObjectに変更します。

// 2. 新しいNCMBObjectを作成
val obj = NCMBObject(className)

次の修正に入る前に、 Util.kt に関数を追加します。

Util.ktについて

文字列をNCMBObjectに戻す関数 strToNCMBObject と JSONObjectをNCMBAclに変換する関数 getAcl を用意します。まずSDKをインポートします。

// 1. NCMBAcl/NCMBObjectを読み込みます
import com.nifcloud.mbaas.core.NCMBObject
import com.nifcloud.mbaas.core.NCMBAcl

strToNCMBObjectの内容です。画面遷移する際に受け取った文字列をJSONObjectにし、それをNCMBObjectのフィールド(DBで言うカラム相当)にセットしていきます。

objectIdはNCMBのデータ管理におけるユニークキー、createDateは作成日時、updateDateは更新日時、aclはアクセス権限に関するフィールドになります。これらはNCMBの規定フィールドです。className(クラス名)はDBで言うところのテーブル名相当になります。

// 2. 文字列をNCMBObjectに復元する関数です
fun strToNCMBObject(str: String, className: String): NCMBObject {
    val json = JSONObject(str)
    val obj = NCMBObject(className = className)
    json.keys().forEach { key ->
        when (key) {
            "objectId" -> {
                obj.setObjectId(json.get(key) as String)
            }
            "createDate" -> {
                obj.setCreateDate(getDate(json.get(key) as String))
            }
            "updateDate" -> {
            } // obj.put("updateDate", getDate(json.get(key) as String))}
            "acl" -> {
                obj.setAcl(getAcl(json.get(key) as JSONObject))
            }
            else -> obj.put(key, json.get(key))
        }
    }
    return obj
}

上記関数で呼ばれている getAcl の内容です。ACLは誰がデータにアクセスできるかを指定するものです。NCMBでは以下の条件に対して、読み書き設定ができます。

  • 誰でも
  • 特定のユーザー
  • 特定のグループ
// 3. NCMBAclを復元する関数です
fun getAcl(obj: JSONObject): NCMBAcl {
    val acl = NCMBAcl()
    obj.keys().forEach { key ->
        val map = obj.get(key) as JSONObject
        when {
            key == "*" -> {
                if (!map.isNull("read") && map.get("read") as Boolean) {
                    acl.publicReadAccess = true
                }
                if (!map.isNull("write") && map.get("write") as Boolean) {
                    acl.publicWriteAccess = true
                }
            }
            key.indexOf("role:") > -1 -> {
                val match = "role:(.*)$".toRegex().find(key)
                val roleName = match?.groups?.get(1)?.value
                if (roleName != null) {
                    if (!map.isNull("read") && map.get("read") as Boolean) {
                        acl.setRoleReadAccess(roleName, true)
                    }
                    if (!map.isNull("write") && map.get("write") as Boolean) {
                        acl.setRoleWriteAccess(roleName, true)
                    }
                }
            }
            else -> {
                if (!map.isNull("read") && map.get("read") as Boolean) {
                    acl.setUserReadAccess(key, true)
                }
                if (!map.isNull("write") && map.get("write") as Boolean) {
                    acl.setUserWriteAccess(key, true)
                }
            }
        }
    }
    return acl
}

Navigation.ktの修正(2)

関数が準備できたので、 Navigation.kt の修正に戻ります。

// 4. 受け取った文字列からNCMBObjectを復元します
val obj = strToNCMBObject(backStackEntry.arguments!!.getString("task")!!, className)

FormScreen.ktの修正

NCMB SDKをインポートします

// 1. NCMBExceptionとNCMBObjectを読み込みます
import com.nifcloud.mbaas.core.NCMBException
import com.nifcloud.mbaas.core.NCMBObject

元々はエラーを出さないためにAnyにしていたのをNCMBObjectに直します。

// 2. AnyをNCMBObjectに変更します
fun FormScreen(navController: NavController, obj: Any) {

// ↓ 修正後
fun FormScreen(navController: NavController, obj: NCMBObject) {

インスタンス変数を設定します。今回はTodoのタイトル(title)と本文(body)をデフォルト値として受け取ります。これは編集時を想定してのことです。

// 3. objectIdを入れます
var objectId = obj.getObjectId();
// 4. titleをrememberで定義します。デフォルト値はNCMBObjectのtitleです
var title by remember { mutableStateOf(if (objectId != null) obj.getString("title")!! else "") }
// 5. bodyをrememberで定義します。デフォルト値はNCMBObjectのbodyです
var body by remember { mutableStateOf(if (objectId != null) obj.getString("body")!! else "") }

保存処理

保存を実行する save メソッドは次のようになります。関数全体を紹介します。

// 保存処理
val save = {
		progress = true
		// 6. 保存処理を記述します
		try {
				obj.put("title", title)
				obj.put("body", body)
				obj.save()
				navController.navigate("list")
		} catch(e: NCMBException){
				Log.d("INFO",  e.message)
				message = "タスクが保存できませんでした"
				showDialog = true
		}
		progress = false
}

一覧画面の作成

ListScreen.ktの編集

NCMB SDKを読み込みます。

// 1. NCMBCallback/NCMBObject/NCMBQueryを読み込みます
import com.nifcloud.mbaas.core.NCMBCallback
import com.nifcloud.mbaas.core.NCMBObject
import com.nifcloud.mbaas.core.NCMBQuery

NCMBからデータを取得する際には NCMBQuery クラスを使います。 NCMBQuery.forObject で指定するクラス名は、NCMBのデータストアにあるクラス名になります。データを取得後、 remember で定義した ary に結果を入れることで、画面描画に使われます。

results は List<dynamc> なので、 List<NCMBObject> にキャストしています。

// 2. aryをrememberのNCMBObjectのListで定義します。デフォルトは空です
var ary = remember { mutableStateOf<List<NCMBObject>>(emptyList()) }
// 3. NCMBQueryを定義します。クラス名はTaskです。
val query = NCMBQuery.forObject("Task")
// 4. 検索を実行して、結果をaryに格納します
query.findInBackground(NCMBCallback { e, results ->
		if (e == null) {
				ary.value = results as List<NCMBObject>
		}
})

元々 ary をただの配列で定義しています(エラー防止のため、単なる配列でした)。 remember にしたので、利用法を変えます。

// 5. ary -> ary.value に書き直してください
items(ary) { obj ->

// ↓
items(ary.value) { obj ->

TaskRow.kt の修正

NCMB SDKを読み込みます。

// 1. NCMBObjectを読み込みます
import com.nifcloud.mbaas.core.NCMBObject

Any 型だったのを NCMBObject にします(エラー防止のため、Any型にしてました)。

// 2. Any -> NCMBObjectにします
fun TaskRow(obj: Any, navController: NavController) {

// ↓
fun TaskRow(obj: NCMBObject, navController: NavController) {

タスクのタイトルを画面に表示します。

// 4. NCMBObjectのtitleを表示します
Text(obj.getString("title")!!, fontSize = 25.sp)

タスクをタップした後の処理の実装

TaskRow.kt の修正

詳細画面に遷移する際にはNCMBObjectを文字列にして送らないといけません。そこで、JSONObjectを使ってNCMBObjectを文字列化します。

// 3. NCMBObjectを文字列化します
obj.keys.forEach {key ->
		json.put(key, obj.get(key)!!)
}

Navigation.ktの修正

detail/task={task} のルーティングでも、文字列をNCMBObjectに戻す処理にします。

// 3. 受け取った文字列からNCMBObjectを復元します
val obj = strToNCMBObject(backStackEntry.arguments!!.getString("task")!!, className)

DetailScreen.ktの修正

NCMB SDKを読み込みます。

// 1. NCMBObjectをインポート
import com.nifcloud.mbaas.core.NCMBObject

Any型をNCMBObjectにします。

// 2. Any -> NCMBObjectに変更します
fun DetailScreen(navController: NavController, obj: Any) {

// ↓
fun DetailScreen(navController: NavController, obj: NCMBObject) {

受け取ったNCMBObjectを画面に表示します。

// 5. NCMBObjectのtitleを表示します
Text(text = obj.getString("title")!!,
		fontSize = 35.sp,
		modifier = Modifier.padding(5.dp)
)
// 6. NCMBObjectのbodyを表示します
Text(text = obj.getString("body")!!,
		fontSize = 30.sp,
		modifier = Modifier.padding(5.dp)
)

ゴミ箱アイコンをタップした際のイベントは、NCMBObjectの削除処理です。

// 4. NCMBObjectを削除します
obj.delete()

編集アイコンをタップした際のイベントは、NCMBObjectを文字列化した上で edit/task へ遷移します。

// 3. NCMBObjectを文字列化します
obj.keys.forEach {key ->
		json.put(key, obj.get(key)!!)
}

まとめ

ここまででNCMBのデータストアを使ったTodoアプリ開発は完了となります。NCMBには他にも認証やファイル保存機能、プッシュ通知などがあります。ぜひあなたのアプリ開発に役立ててください。

mBaaSでサーバー開発不要! | ニフクラ mobile backend

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
0