専門家:クーリエアプリMVVM Jetpack(HMSアカウントとAuthService)Kotlinを使用しているアンドロイド-パート1

24207 ワード

概要
この記事では、私はHMSのアカウントとAuthServiceキットなどのHMSコアキットを統合するKotlinを使用してクーリエAndroidアプリケーションを作成します.
アプリケーションは、DataBinding、AndroidViewModel、オブザーバー、LiveDataなどのJetpackのコンポーネントを使用してAndroid MVVMのクリーンなアーキテクチャを使用するようになります.
本稿では,観測可能なパターンを用いたデータベース化を実装する.
Huawei IDサービス紹介
Huawei IDログインシンプルかつ安全な、迅速なサインインと認証機能を提供します.代わりにアカウントとパスワードを入力し、認証を待っているだけで、ユーザーはすぐにHuawei IDボタンを使用してHuawei IDを使用してアプリケーションに迅速かつ安全にサインをタップすることができます.
前提条件
Huawei電話エミュ3.0以降.
非Huawei電話アンドロイド4.4以降(APIレベル19以上).
HMSコアAPK
アンドロイド
アカウントアカウント

アプリケーションギャラリー統合プロセス


ログインして、AppGallery Connectポータルのプロジェクトを作成または選択します.
プロジェクトの設定に移動し、設定ファイルをダウンロードします.
一般的な情報に移動し、データストレージの場所を提供します.
アプリ開発
必要な依存関係を追加します.
Androidのスタジオを起動し、新しいプロジェクトを作成します.プロジェクトが完了したら.
Gradleスクリプトフォルダに移動し、ビルドを開きます.Gradle (モジュール: app ).
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'com.huawei.agconnect'

android {
    compileSdkVersion 30
    buildToolsVersion "29.0.3"

    buildFeatures {

        dataBinding = true
        viewBinding = true
    }
同じビルドで.Gradleファイルで、ライフサイクルライブラリを依存関係に追加します.このライブラリは、UIをViewModelとLiveDataに接続するのに役立ちます.
dependencies {
    implementation fileTree(dir: "libs", include: ["*.jar"])
    //noinspection GradleDependency
    implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
    implementation 'androidx.core:core-ktx:1.6.0'
    implementation 'androidx.appcompat:appcompat:1.4.1'
    implementation 'androidx.annotation:annotation:1.3.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
    implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
    implementation 'androidx.navigation:navigation-fragment-ktx:2.4.1'
次の依存関係を追加する
    //HMS Kits
    implementation 'com.huawei.agconnect:agconnect-core:1.5.0.300'
    implementation 'com.huawei.hms:hwid:5.3.0.302'
Gradleスクリプトフォルダに移動し、ビルドを開きます.Gradleプロジェクト.
classpath 'com.huawei.agconnect:agcp:1.4.2.300'
maven {url 'https://developer.huawei.com/repo/'}
コード実装
次のパッケージモデル、イベント、ViewModelを作成しました.
モデル:プライマリフォルダで新しいパッケージを作成し、モデル名を指定します.次に、ユーザーを作成します.このパッケージのKTファイル.
data class User(
    var from: String,
    var to: String
)
ViewModel : ViewModelはUIのデータ変更を簡単に更新できます.ViewModelという名前のパッケージをメインフォルダに作成します.次に、新しいファイルを作成し、LoginViewModelという名前を付けます.KT,OrderViewModelそれらのファクタyviewModelProviderと一緒のKT.
LoginViewModel.KT
package com.hms.corrieraap.viewmodel

import android.app.Activity
import android.app.Application
import android.content.Context
import android.content.Intent
import android.util.Log
import androidx.databinding.Observable
import androidx.lifecycle.AndroidViewModel
import com.hms.corrieraap.OrderActivity
import com.hms.corrieraap.event.ActivityNavigation
import com.hms.corrieraap.event.LiveMessageEvent
import com.huawei.hmf.tasks.Task
import com.huawei.hms.support.account.AccountAuthManager
import com.huawei.hms.support.account.request.AccountAuthParams
import com.huawei.hms.support.account.request.AccountAuthParamsHelper
import com.huawei.hms.support.account.result.AuthAccount
import com.huawei.hms.support.account.service.AccountAuthService

const val HMS_SIGN_IN: Int = 9001


class LoginViewModel(application: Application) : AndroidViewModel(application), Observable {

    private var mAuthManager: AccountAuthService? = null
    private var mAuthParam: AccountAuthParams? = null

    val startActivityForResultEvent = LiveMessageEvent<ActivityNavigation>()

    fun login() {
        mAuthParam = AccountAuthParamsHelper(AccountAuthParams.DEFAULT_AUTH_REQUEST_PARAM)
            .setIdToken()
            .setAccessToken()
            .createParams()
        mAuthManager = AccountAuthManager.getService(Activity(), mAuthParam)
        startActivityForResultEvent.sendEvent {
            startActivityForResult(
                mAuthManager?.signInIntent,
                HMS_SIGN_IN
            )
        }
    }

    fun onResultFromActivity(context: Context, requestCode: Int, data: Intent?) {
        when (requestCode) {
            HMS_SIGN_IN -> {
                val authAccountTask = AccountAuthManager.parseAuthResultFromIntent(data)
                onCompleteLogin(context, authAccountTask)
            }
        }
    }

    private fun onCompleteLogin(context: Context, doneTask: Task<AuthAccount>) {
        if (doneTask.isSuccessful) {
            val authAccount = doneTask.result
            Log.d("LoginViewModel", "SigIn Success")
            context.startActivity(Intent(context, OrderActivity::class.java))

        } else {
            Log.d("LoginViewModel", "SigIn Error")
        }
    }

    override fun addOnPropertyChangedCallback(callback: Observable.OnPropertyChangedCallback?) {
    }

    override fun removeOnPropertyChangedCallback(callback: Observable.OnPropertyChangedCallback?) {
    }

}
LoginViewModelFactoryKT
package com.hms.corrieraap.viewmodel

import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider


class LoginViewModelFactory : ViewModelProvider.Factory {
    override fun <T : ViewModel?> create(modelClass: Class<T>): T {
        if(modelClass.isAssignableFrom(LoginViewModel::class.java)){
            return LoginViewModel() as T
        }
        throw IllegalArgumentException ("UnknownViewModel")
    }

}
OrderViewModel.KT

package com.hms.corrieraap.viewmodel

import androidx.databinding.Bindable
import androidx.databinding.Observable
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import com.hms.corrieraap.model.User


class OrderViewModel : ViewModel(), Observable {

    @Bindable
    val from = MutableLiveData<String>()

    @Bindable
    val to = MutableLiveData<String>()

    var data = MutableLiveData<User>()

    fun onDataChanged() {
        val from = from.value!!
        val to = to.value!!

        val user = User(from, to)
        data.value = user
    }

    override fun addOnPropertyChangedCallback(callback: Observable.OnPropertyChangedCallback?) {
        TODO("Not yet implemented")
    }

    override fun removeOnPropertyChangedCallback(callback: Observable.OnPropertyChangedCallback?) {
        TODO("Not yet implemented")
    }
}
OrderViewModelファクトリKT
package com.hms.corrieraap.viewmodel

import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import java.lang.IllegalArgumentException


class OrderViewModelFactory : ViewModelProvider.Factory {
    override fun <T : ViewModel?> create(modelClass: Class<T>): T {
        if (modelClass.isAssignableFrom(OrderViewModel::class.java)){
            return OrderViewModel() as T
        }
        throw IllegalArgumentException("UnknownViewModel")
    }
}
XMLレイアウトデータベース
UIにデータバインディングを含めるには、すべてのコンテンツをエンクロージャします.
表示されるように、セクションのレイアウトにViewModelが導入されます.タイプ値が必要なViewModelを持つ特定のフォルダーにポイントしていることを確認します.
<layout xmlns:android="http://schemas.android.com/apk/res/android">

    <data>
        <variable
            name="LoginViewModel"
            type="com.hms.corrieraap.viewmodel.LoginViewModel" />
    </data>
主な活動.XML :
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">

    <data>
        <variable
            name="LoginViewModel"
            type="com.hms.corrieraap.viewmodel.LoginViewModel" />
    </data>

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/colorPrimary">

        <com.google.android.material.appbar.AppBarLayout
            style="@style/AppTheme.AppBarOverlay"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:theme="@style/AppTheme.AppBarOverlay">

            <androidx.appcompat.widget.Toolbar
                android:id="@+id/toolbar"
                style="@style/AppTheme.PopupOverlay"
                android:layout_width="match_parent"
                android:layout_height="?actionBarSize"
                android:background="@color/colorPrimaryDark" />
        </com.google.android.material.appbar.AppBarLayout>

        <ScrollView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_centerHorizontal="true"
            android:layout_centerVertical="true"
            android:gravity="center">

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:orientation="vertical"
                android:padding="16dp">


                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:padding="5dp"
                    android:text="SigIn / SignUp "
                    android:textAlignment="center"
                    android:textColor="@color/white"
                    android:textSize="34sp"
                    android:textStyle="bold" />


                <Button
                    android:id="@+id/btn_sign"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="20dp"
                    android:layout_marginBottom="5dp"
                    android:background="@color/colorPrimaryDark"
                    android:text="Login With Huawei Id"
                    android:onClick="@{()->LoginViewModel.login()}"
                    android:textColor="@color/white"
                    android:textStyle="bold" />
            </LinearLayout>

        </ScrollView>

    </RelativeLayout>
</layout>
アクティブな順序.XML :
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">

    <data>
        <variable
            name="orderViewModel"
            type="com.hms.corrieraap.viewmodel.OrderViewModel" />
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <com.google.android.material.appbar.AppBarLayout
            style="@style/AppTheme.AppBarOverlay"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:theme="@style/AppTheme.AppBarOverlay">

            <androidx.appcompat.widget.Toolbar
                android:id="@+id/toolbar"
                style="@style/AppTheme.PopupOverlay"
                android:layout_width="match_parent"
                android:layout_height="?actionBarSize"
                android:background="@color/colorPrimaryDark" />
        </com.google.android.material.appbar.AppBarLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="@dimen/activity_vertical_margin"
            android:orientation="horizontal">

            <TextView
                android:id="@+id/heading_from_text_view"
                android:layout_width="60dp"
                android:layout_height="wrap_content"
                android:layout_marginLeft="@dimen/activity_horizontal_margin"
                android:layout_marginTop="@dimen/activity_vertical_margin"
                android:layout_marginRight="@dimen/activity_horizontal_margin"
                android:text="@string/heading_from"
                android:textAllCaps="true"
                android:textSize="20sp" />

            <FrameLayout
                android:id="@+id/place_autocomplete_frame"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_marginTop="@dimen/activity_vertical_margin"
                android:layout_weight="1">

                <TextView
                    android:id="@+id/place_autocomplete_from"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:hint="@string/hint_address"
                    android:text="@={orderViewModel.from}"
                    android:textSize="20sp" />
            </FrameLayout>
        </LinearLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="@dimen/activity_vertical_margin"
            android:orientation="horizontal">

            <TextView
                android:id="@+id/heading_to_text_view"
                android:layout_width="60dp"
                android:layout_height="wrap_content"
                android:layout_marginLeft="@dimen/activity_horizontal_margin"
                android:layout_marginTop="@dimen/activity_vertical_margin"
                android:layout_marginRight="@dimen/activity_horizontal_margin"
                android:text="@string/heading_to"
                android:textAllCaps="true"
                android:textSize="20sp" />

            <FrameLayout
                android:id="@+id/place_autocomplete_frame2"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_marginTop="@dimen/activity_vertical_margin"
                android:layout_weight="1">

                <TextView
                    android:id="@+id/place_autocomplete_to"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:hint="@string/hint_address"
                    android:text="@={orderViewModel.to}"
                    android:textSize="20sp" />
            </FrameLayout>
        </LinearLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="@dimen/activity_vertical_margin"
            android:layout_marginBottom="@dimen/activity_vertical_margin"
            android:gravity="center_horizontal"
            android:orientation="horizontal"
            android:weightSum="1.0">

            <Button
                android:id="@+id/neworder_button_calculate"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="start"
                android:layout_marginEnd="0dp"
                android:layout_marginRight="0dp"
                android:layout_weight="0.4"
                android:text="@string/heading_calculate" />

            <Button
                android:id="@+id/neworder_button_additional"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:layout_weight="0.4"
                android:text="@string/neworder_alert_additional" />

            <Button
                android:id="@+id/neworder_button_call"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="end"
                android:onClick="@{()->orderViewModel.onDataChanged()}"
                android:layout_weight="0.4"
                android:text="@string/heading_call" />
        </LinearLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center_horizontal"
            android:orientation="horizontal">

            <TextView
                android:id="@+id/neworder_textview_summary"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_gravity="center_horizontal"
                android:layout_marginTop="@dimen/activity_vertical_margin"
                android:layout_marginBottom="@dimen/activity_vertical_margin"
                android:layout_weight="0.2"
                android:gravity="center_horizontal"
                android:textAlignment="center"
                android:textAllCaps="true" />
        </LinearLayout>

    </LinearLayout>
</layout>
LiveMessageEvent : lifeemessageeventsを実装して、ライフキャストを提供する
package com.hms.corrieraap.event

import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.Observer

class LiveMessageEvent<T> : SingleLiveEvent<(T.() -> Unit)?>() {

    fun setEventReceiver(owner: LifecycleOwner, receiver: T) {
        observe(owner, Observer { event ->
            if (event != null) {
                receiver.event()
            }
        })
    }

    fun sendEvent(event: (T.() -> Unit)?) {
        value = event
    }
}
SingleEvent:LifefeycleObserverのための実装singleliveEvent
package com.hms.corrieraap.event

import android.util.Log

import androidx.annotation.MainThread
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Observer
import java.util.concurrent.atomic.AtomicBoolean

open class SingleLiveEvent<T> : MutableLiveData<T>() {

    private val mPending = AtomicBoolean(false)

    @MainThread
    override fun observe(owner: LifecycleOwner, observer: Observer<in T>) {

        if (hasActiveObservers()) {
            Log.w(TAG, "Multiple observers registered but only one will be notified of changes.")
        }

        super.observe(owner, Observer { t ->
            if (mPending.compareAndSet(true, false)) {
                observer.onChanged(t)
            }
        })
    }

    @MainThread
    override fun setValue(t: T?) {
        mPending.set(true)
        super.setValue(t)
    }

    @MainThread
    fun call() {
        value = null
    }

    companion object {

        private val TAG = "SingleLiveEvent"
    }
}
アクティブナビゲーション.KT:アクティビティ遷移のための実装インタフェイス
package com.hms.corrieraap.event

import android.content.Intent


interface ActivityNavigation {
    fun startActivityForResult(intent: Intent?, requestCode: Int)
}
​​​​​​​
メインアクティビティ.KT : Huawei IDログイン用に実装.
package com.hms.corrieraap

import android.content.Intent
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.DataBindingUtil
import androidx.lifecycle.ViewModelProviders
import com.hms.corrieraap.databinding.ActivityMainBinding
import com.hms.corrieraap.event.ActivityNavigation
import com.hms.corrieraap.viewmodel.LoginViewModel
import com.hms.corrieraap.viewmodel.LoginViewModelFactory

class MainActivity : AppCompatActivity(), ActivityNavigation {

    private lateinit var viewModel: LoginViewModel
    private lateinit var dataBinding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        dataBinding = DataBindingUtil.setContentView(this, R.layout.activity_main)
        val factory = LoginViewModelFactory()
        viewModel = ViewModelProviders.of(this, factory).get(LoginViewModel::class.java)
        dataBinding.loginViewModel = viewModel
        dataBinding.lifecycleOwner=this
        viewModel.startActivityForResultEvent.setEventReceiver(this, this)
    }


    public override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        viewModel.onResultFromActivity(requestCode, data)
        super.onActivityResult(requestCode, resultCode, data)
    }

}
OrderactivityKT :注文新しい宅配便のために実装.
「パッケージコム.HMSコルリエレープ
アンドロイド.os束
アンドロイド.ウィジェット.トースト
輸入アンドロイド.appcompatアプリ.appcompatactivity
輸入アンドロイド.データベース化.データグラム
輸入アンドロイド.ライフサイクル.観測者
輸入アンドロイド.ライフサイクル.ビューモデラー
インポートCOM.HMSコルリアーナップ.データベース化.アクティブ結合
インポートCOM.HMSコルリアーナップ.ViewModelOrderViewModel
インポートCOM.HMSコルリアーナップ.ViewModel(株)
クラスの動作
private lateinit var activityOrderBinding: ActivityOrderBinding
private lateinit var orderViewModel: OrderViewModel

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    activityOrderBinding = DataBindingUtil.setContentView(this, R.layout.activity_order)
    val factory = OrderViewModelFactory()
    orderViewModel = ViewModelProviders.of(this, factory).get(OrderViewModel::class.java)
    activityOrderBinding.lifecycleOwner = this

    orderViewModel.data.observe(this, Observer {
        Toast.makeText(this, "Placed Order", Toast.LENGTH_SHORT).show();
    })

}

​​​​​​​
**
アプリケーションのビルド結果

ヒントとトリック
アイデンティティキットは、最初にHuawei ID登録またはサインをページに表示します.ユーザーは、登録されたHuawei IDを使用して署名した後のみIDキットによって提供される機能を使用することができます.
結論
この記事では、AndroidアプリケーションでHuawei IDを統合する方法を学びました.完全にこの記事を読んだ後、ユーザーは簡単にKotlinを使用してクーリエAndroidアプリケーションでHuawei IDを実装することができます.
この記事を読んでくれてありがとう.あなたがそれが役に立つとわかるならば、この記事に好きで、コメントしてください.それは私にたくさん意味します.
参考文献
HMSドキュメント
https://developer.huawei.com/consumer/en/doc/development/HMSCore-Guides/introduction-0000001050048870
アカウントキットトレーニングビデオ
https://developer.huawei.com/consumer/en/training/course/video/101603872818951100