전문가: Kotlin을 사용하는 Android의 Courier App MVVM Jetpack(HMS 푸시 키트 업링크 메시지) - Part-4

20276 단어
개요

이 기사에서는 HMS Account, Push, CloudDB, AuthService 및 Push Kit Uplink Message와 같은 HMS Core 키트를 통합할 Kotlin을 사용하여 Courier Android 애플리케이션을 만들 것입니다.

이 시리즈의 Part-1에서는 HMS Account 및 AuthService Kit를, Part-2에서는 HMS 푸시 키트를 사용한 푸시 알림을, Part-3에서는 클라우드 DB 키트를 통합했습니다. 아래 링크로 들어가주세요-

파트 1 https://forums.developer.huawei.com/forumPortal/en/topic/0202841957497640128

파트 2 https://forums.developer.huawei.com/forumPortal/en/topic/0201847982965230092

3부 https://forums.developer.huawei.com/forumPortal/en/topic/0201854022878900124?fid=0101187876626530001

앱은 DataBinding, AndroidViewModel, Observer, LiveData 등과 같은 Jetpack 구성 요소를 사용하여 Android MVVM 클린 아키텍처를 사용합니다.

이 기사에서는 Observable 패턴을 사용하여 DataBinding을 구현하려고 합니다.

Huawei 푸시 키트 소개

푸시 키트는 개발자를 위해 Huawei에서 제공하는 메시징 서비스입니다. 푸시 키트는 클라우드에서 장치로의 메시징 채널을 설정합니다. HUAWEI 푸시 키트를 통합함으로써 개발자는 실시간으로 사용자 장치의 앱에 메시지를 보낼 수 있습니다. 푸시 키트는 개발자가 대상 고객에게 신속하게 도달할 수 있도록 도와줍니다. 푸시 알림은 모든 사람 또는 특정인에게 개별적으로 보낼 수 있습니다. 알림을 보내려면 사용자의 토큰이 필요합니다. 장치 그룹 또는 특정 사용자에게 메시지를 보낼 수 있습니다. 푸시 키트에는 두 가지 알림 유형이 있습니다. 텍스트 전용 스타일(더 긴 텍스트 메시지 표시) 및 큰 그림 스타일(큰 텍스트 및 이미지 메시지 표시).

전제 조건

Huawei Phone EMUI 3.0 이상.
Huawei가 아닌 휴대폰 Android 4.4 이상(API 레벨 19 이상).
HMS 코어 APK 4.0.0.300 이상
안드로이드 스튜디오
AppGallery 계정
앱 갤러리 통합 프로세스

로그인하고 AppGallery Connect 포털에서 프로젝트를 생성하거나 선택합니다.
프로젝트 설정으로 이동하여 구성 파일을 다운로드합니다.
일반 정보로 이동한 다음 데이터 저장소 위치를 제공합니다.
앱 개발

필수 종속성 추가:
Android 스튜디오를 시작하고 새 프로젝트를 만듭니다. 일단 프로젝트가 준비되었습니다.
Gradle 스크립트 폴더로 이동하여 build.gradle(모듈: 앱)을 엽니다.

//HMS Kits
    implementation 'com.huawei.agconnect:agconnect-core:1.5.0.300'
    implementation 'com.huawei.hms:hwid:5.3.0.302'

    implementation 'com.huawei.hms:push:4.0.3.301'

    implementation 'com.huawei.agconnect:agconnect-cloud-database:1.5.0.300'
    implementation "com.huawei.agconnect:agconnect-auth-huawei:1.6.0.300"
    implementation 'com.huawei.agconnect:agconnect-auth:1.5.0.300'


Gradle 스크립트 폴더로 이동하여 build.gradle(프로젝트: 앱)을 엽니다.

ext.kotlin_version = "1.4.21"
    repositories {
        google()
        jcenter()
        maven {url 'https://developer.huawei.com/repo/'}
    }
    dependencies {
        classpath "com.android.tools.build:gradle:4.0.1"
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
        classpath 'com.huawei.agconnect:agcp:1.4.2.300'


코드 구현
다음 패키지 모델인 push, viewmodel을 생성했습니다.
모델: 기본 폴더에서 새 패키지를 만들고 이름을 모델로 지정합니다.

배송체크아웃 활동:


package com.hms.corrierapp

import android.os.Bundle
import android.text.TextUtils
import android.util.Log
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.DataBindingUtil
import com.hms.corrierapp.databinding.ActivityAddressBinding
import com.hms.corrierapp.push.*
import com.huawei.agconnect.config.AGConnectServicesConfig
import com.huawei.hms.aaid.HmsInstanceId
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response


class ShippingCheckoutAddressActivity : AppCompatActivity() {

    private lateinit var pushToken: String
    private var accessToken: String? = null

    private lateinit var binding: ActivityAddressBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = DataBindingUtil.setContentView(this, R.layout.activity_address)

        getToken()
        getAccessToken()

        binding.btnCheckout.setOnClickListener {
            sendNotification(pushToken)
        }
    }

    private fun getToken() {
        object : Thread() {
            override fun run() {
                try {
                    val appId: String =
                        AGConnectServicesConfig.fromContext(this@ShippingCheckoutAddressActivity)
                            .getString("client/app_id")
                    pushToken =
                        HmsInstanceId.getInstance(this@ShippingCheckoutAddressActivity)
                            .getToken(appId, "HCM")

                    if (!TextUtils.isEmpty(pushToken)) {
                        Log.i("Push", "get token:$pushToken")
                    }
                } catch (e: Exception) {
                    Log.i("Push", "getToken failed, $e")
                }
            }
        }.start()
    }

    private fun getAccessToken() {
        AccessTokenClient.getClient().create(AccessTokenInterface::class.java)
            .createAccessToken(
                "client_credentials",
                "a3c3072ecb38e7c58f3ad8ee48ed5a8e31a2f6bcddf5c094a00329fdd77c8f50",
                "105919003"
            )
            .enqueue(object : Callback<AccessTokenModel> {
                override fun onFailure(call: Call<AccessTokenModel>, t: Throwable) {
                    Log.d("Push", "ERROR : " + t.message)
                }

                override fun onResponse(
                    call: Call<AccessTokenModel>,
                    response: Response<AccessTokenModel>
                ) {
                    if (response.isSuccessful) {
                        Log.d("Push", "Token " + response.body()?.access_token)
                        accessToken = response.body()?.access_token
                    }
                }
            })
    }

    private fun sendNotification(pushToken: String) {

        val notifMessageBody: NotificationMessageBody = NotificationMessageBody.Builder(
            "Your Courier is Booked", "We will notify you once your courier dispatch",
            arrayOf(pushToken)
        )
            .build()

        NotificationClient.getClient().create(NotificationInterface::class.java)
            .createNotification(
                "Bearer $accessToken",
                notifMessageBody
            )
            .enqueue(object : Callback<NotificationMessageModel> {
                override fun onFailure(call: Call<NotificationMessageModel>, t: Throwable) {
                    Log.d("Push", "ERROR :  " + t.message)
                }

                override fun onResponse(
                    call: Call<NotificationMessageModel>,
                    response: Response<NotificationMessageModel>
                ) {
                    if (response.isSuccessful) {
                        Log.d("Push", "Response " + response.body())
                        Toast.makeText(
                            this@ShippingCheckoutAddressActivity,
                            "Sent For Track",
                            Toast.LENGTH_SHORT
                        )
                            .show()
                    }
                }

            })
    }
}


activity_shipping_checkout_activity:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">

    <data>

        <variable
            name="addressViewmODEL"
            type="com.hms.corrierapp.viewmodel.AddressViewModel" />
    </data>

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <LinearLayout
                android:id="@+id/profileLayout"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:orientation="vertical"
                android:paddingTop="20dp">

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:gravity="center"
                    android:padding="5dp"
                    android:text="@string/fill_shipping"
                    android:textAlignment="center"
                    android:textColor="@color/colorPrimaryDark"
                    android:textSize="34sp"
                    android:textStyle="bold" />


                <com.google.android.material.textfield.TextInputLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="5dp"
                    android:paddingLeft="6dp"
                    android:paddingRight="6dp"
                    android:textColor="@color/colorPrimaryDark">

                    <EditText
                        android:id="@+id/fullNameEdt"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:hint="Full Name"
                        android:imeOptions="actionNext"
                        android:singleLine="true"
                        android:textSize="14sp" />
                </com.google.android.material.textfield.TextInputLayout>


                <com.google.android.material.textfield.TextInputLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:paddingLeft="6dp"
                    android:paddingRight="6dp"
                    android:textColor="@color/colorPrimaryDark">

                    <EditText
                        android:id="@+id/mobEditText"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:hint="Mobile Number *"
                        android:imeOptions="actionNext"
                        android:inputType="number"
                        android:paddingLeft="6dp"
                        android:singleLine="true"
                        android:textSize="14sp" />

                </com.google.android.material.textfield.TextInputLayout>


                <com.google.android.material.textfield.TextInputLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:paddingLeft="6dp"
                    android:paddingRight="6dp"
                    android:textColor="@color/colorPrimaryDark">

                    <EditText
                        android:id="@+id/cityEditText"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:hint="City *"
                        android:imeOptions="actionNext"
                        android:paddingLeft="6dp"
                        android:singleLine="true"
                        android:textSize="14sp" />
                </com.google.android.material.textfield.TextInputLayout>

                <com.google.android.material.textfield.TextInputLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:paddingLeft="6dp"
                    android:paddingRight="6dp"
                    android:textColor="@color/colorPrimaryDark">

                    <EditText
                        android:id="@+id/areaEditText"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:hint="Locality, area or street *"
                        android:imeOptions="actionNext"
                        android:paddingLeft="6dp"
                        android:singleLine="true"
                        android:textSize="14sp" />
                </com.google.android.material.textfield.TextInputLayout>


                <com.google.android.material.textfield.TextInputLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:paddingLeft="6dp"
                    android:paddingRight="6dp"
                    android:textColor="@color/colorPrimaryDark">

                    <EditText
                        android:id="@+id/buildingEditText"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:hint="Flat no., Building name *"
                        android:imeOptions="actionNext"
                        android:paddingLeft="6dp"
                        android:singleLine="true"
                        android:textSize="14sp" />
                </com.google.android.material.textfield.TextInputLayout>

                <RelativeLayout
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content">

                    <com.google.android.material.textfield.TextInputLayout
                        android:id="@+id/relativeLayout2"
                        android:layout_width="150dp"
                        android:layout_height="wrap_content"
                        android:paddingLeft="6dp">

                        <EditText
                            android:id="@+id/pincodeEditText"
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:hint="Pincode *"
                            android:imeOptions="actionNext"
                            android:inputType="number"
                            android:paddingLeft="6dp"
                            android:singleLine="true"
                            android:textSize="14sp" />

                    </com.google.android.material.textfield.TextInputLayout>

                    <com.google.android.material.textfield.TextInputLayout
                        android:layout_width="150dp"
                        android:layout_height="wrap_content"
                        android:layout_marginLeft="52dp"
                        android:layout_toRightOf="@+id/relativeLayout2">

                        <EditText
                            android:id="@+id/stateEditText"
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:hint="State *"
                            android:imeOptions="actionNext"
                            android:singleLine="true"
                            android:textSize="14sp"

                            />

                    </com.google.android.material.textfield.TextInputLayout>
                </RelativeLayout>


                <com.google.android.material.textfield.TextInputLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:paddingLeft="6dp"
                    android:paddingRight="6dp">

                    <EditText
                        android:id="@+id/landmarkEditText"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:hint="Landmark(Optional)"
                        android:imeOptions="actionDone"
                        android:paddingLeft="6dp"
                        android:singleLine="true"
                        android:textSize="14sp" />
                </com.google.android.material.textfield.TextInputLayout>


                <Button
                    android:id="@+id/btn_checkout"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="10dp"
                    android:backgroundTint="@color/colorPrimary"
                    android:text="Checkout"
                    android:textColor="@color/white"
                    android:textSize="17sp" />


            </LinearLayout>

        </RelativeLayout>
    </ScrollView>
</layout>


앱 빌드 결과





팁과 요령

Identity Kit는 먼저 HUAWEI ID 등록 또는 로그인 페이지를 표시합니다. 사용자는 등록된 HUAWEI ID로 로그인한 후에만 Identity Kit에서 제공하는 기능을 사용할 수 있습니다.

푸시 키트는 지역 간 메시징을 지원하지만 메시징 성능이 영향을 받을 수 있습니다. 지역 간 메시징을 최소화하려면 사용자가 모이는 지역에 서버를 배치하는 것이 좋습니다.

반드시 SHA-256 지문을 추가했는지 확인하십시오.

minSDK 버전을 24 이상으로 설정하십시오. 그렇지 않으면 AndriodManifest 병합 문제가 발생합니다.

결론

이 기사에서는 Android 애플리케이션에서 Huawei ID와 푸시 키트를 통합하는 방법을 배웠습니다. 이 기사를 완전히 읽은 후 사용자는 Kotlin을 사용하여 Courier Android 애플리케이션에서 Huawei ID 및 클라이언트 측 푸시 알림을 쉽게 구현할 수 있습니다.

이 기사를 읽어 주셔서 감사합니다. 이 글이 도움이 되셨다면 좋아요와 댓글을 꼭 남겨주세요. 그건 나에게 큰 의미 야.

참조

HMS 문서:

https://developer.huawei.com/consumer/en/doc/development/HMSCore-Guides/introduction-0000001050048870

https://developer.huawei.com/consumer/en/doc/development/HMSCore-Guides/service-introduction-0000001050040060

푸시 키트 교육 비디오:

https://developer.huawei.com/consumer/en/training/course/video/101583005582480166

푸시 키트 코드 랩:

https://developer.huawei.com/consumer/en/codelabsPortal/carddetails/HMSPushKit

좋은 웹페이지 즐겨찾기