LoginSignup
0
0

More than 1 year has passed since last update.

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

Last updated at Posted at 2022-05-16

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

0
0
0

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
  3. You can use dark theme
What you can do with signing up
0
0