1、介绍
Overview
云数据库是AppGallery Connect提供的服务之一,实现云端数据的同步,提供统一的数据模型和丰富的数据管理接口。在保证数据的可用性、可靠性、一致性,以及安全等特性基础上,能够实现数据在客户端和云端之间的无缝同步,并为应用提供离线支持,以帮助开发者快速构建端云、多端协同的应用。
您将建立什么
在本次codelab中,您将建立一个MVVM架构的安卓项目,实现Video Calling应用的云数据库和WebRTC功能,集成通知系统的推送服务、分析服务、机器学习服务、安全检测服务以及崩溃服务,实现数据安全和真实用户验证。
您将会学到什么
-
集成AppGallery Connect的华为帐号登录认证服务。
-
集成AppGallery Connect的崩溃服务。
-
集成AppGallery Connect的云数据库。
-
使用云数据库和WebRTC开发应用。
-
通过Safety Detect检查运行应用的设备是否安全。
-
使用推送服务和分析服务实现给受众发送通知。
-
使用机器学习服务活体检测特性验证用户帐号。
2、您需要什么
硬件需求
-
安装Android Studio并已连网的电脑
-
华为或安卓手机(带USB线),用于调测和运行
软件需求
-
JDK版本:1.8.211或以上
-
Android API 21或以上
-
HMS Core (APK) 6.0.0.300或以上
-
Android Studio版本:3.6.1或以上
-
华为手机:EMUI 5.0版本或以上;非华为手机:Android 5.0或以上
3、能力接入准备
如果您需要正式发布一款集成音频编辑服务的应用,请参阅HUAWEI HMS Core集成准备做好相关准备工作。本codelab提供的样例已为您完成准备工作。如您使用示例代码,忽略本步骤。
准备集成HMS Core前,在华为开发者联盟上注册成为开发者并完成实名认证,具体方法可参考帐号注册认证。
4、配置开发环境
-
登录AppGallery Connect,点击“我的项目”。
-
在项目列表中找到您的项目,在项目下的应用列表中选择您需要集成SDK的应用。
-
在“项目设置”页面选择“常规”页签。点击“应用”区域里的“agconnect-services.json”下载配置文件。
-
把agconnect-services.json文件复制到项目里。
配置HMS Core SDK的Maven仓地址
Android Studio的Maven仓地址配置方式在Gradle插件7.0以下版本、7.0版本和7.1及以上版本有所不同。
Maven仓地址无法直接在浏览器中打开访问,只能在IDE中配置。如需添加多个Maven代码库,请将华为公司的Maven仓地址配置在最后。
以7.1及以上版本为例。
-
打开Android Studio项目根路径下的build.gradle文件。
-
如agconnect-services.json文件已添加到应用中,选择buildscript > dependencies添加AppGallery Connect和Android Gradle插件配置。
buildscript { dependencies { ... //添加Android Gradle插件配置。将{version}替换为真实的Gradle插件版本,例如,7.1.1。 classpath 'com.android.tools.build:gradle:{version}' //添加AppGallery Connect插件配置。 classpath 'com.huawei.agconnect:agcp:1.6.0.300' } }
-
打开项目及settings.gradle文件,为HMS Core SDK配置Maven仓地址。
pluginManagement { repositories { gradlePluginPortal() google() mavenCentral() //为HMS Core SDK配置Maven仓地址。 maven { url 'https://developer.huawei.com/repo/' } } } dependencyResolutionManagement { ... repositories { google() mavenCentral() //为HMS Core SDK配置Maven仓地址。 maven { url 'https://developer.huawei.com/repo/' } } }
5、启用服务
集成云数据库SDK前,请启用云数据库服务。步骤如下:
-
登录AppGallery Connect,点击“我的项目”。
-
在项目列表中选择您需要开通云数据库服务的项目。
-
在导航树上点击“构建 > 云数据库”。在云数据库服务界面,点击“立即开通”。
-
在引导界面选择“数据处理位置”。
-
启用认证服务,机器学习服务,推送服务,安全检测服务和华为分析。
6、设计UI
本codelab将设计app主页,联系人页面,以及携带用户资料页面。在主页中,您可以输入会议ID进入会议。
7、集成认证服务 – 华为账号登录
示例代码使用华为帐号登录模式,所以您需要在AppGallery Connect中启用认证服务的华为帐号认证模式。否则,登录将会失败。
-
登录AppGallery Connect,点击“我的项目”。
-
在项目列表中选择您的项目。
-
点击“构建 > 认证服务”,进入认证服务的页面。如果首次使用认证服务,请点击“立即开通”开通服务。
-
进入“认证服务”界面后,选择“认证方式”页签,点击“华为帐号”对应“操作”列的“启用”。
-
在项目里调用认证服务相关方法。使用云数据库函数前,确保您已使用华为账号登录应用。
示例代码:
authParams = AccountAuthParamsHelper(AccountAuthParams.DEFAULT_AUTH_REQUEST_PARAM) .setAccessToken() .createParams() private fun signInHuaweiId(){ val signInIntent = service.signInIntent startActivityForResult(signInIntent, HUAWEI_ID_SIGN_IN) }
8、集成崩溃服务
启用华为分析服务
崩溃服务使用华为分析能力实现崩溃事件上报,因此您在集成崩溃SDK前需要启用华为分析。
-
将编译依赖项添加到“dependencies”中。
dependencies { implementation 'com.huawei.hms:hianalytics:5.2.0.301' implementation 'com.huawei.agconnect:agconnect-crash:1.5.1.300' }
-
在左侧导航栏选择“质量 > 崩溃”。如果首次使用崩溃服务,请点击“立即开通”开通服务。
buildscript { repositories { google() jcenter() //为HMS Core SDK配置Maven仓地址。 maven {url 'https://developer.huawei.com/repo/'} } dependencies { ... //添加AppGallery Connect插件配置。 classpath 'com.huawei.agconnect:agcp:1.6.0.300' } } allprojects { repositories { google() jcenter() //为HMS Core SDK配置Maven仓地址。 maven {url 'https://developer.huawei.com/repo/'} } }
9、添加和导出对象类型
-
登录AppGallery Connect,点击“我的项目”。
-
在项目列表中选择您的项目。
-
在导航树上点击“构建 > 云数据库”。
-
单击“新增”,进入创建对象类型页面。
-
输入“对象类型名”为“CallsSdp”后,单击“下一步”。
-
单击“新增字段”,新增如下字段后,单击“下一步”。
字段名称
类型
主键
非空
加密
默认值
meetingID
String
√
√
–
–
sdp
Text
–
–
–
–
callType
String
–
–
–
–
-
设置索引,单击“下一步”。
-
设置所需的角色和权限。
-
单击“确定”。创建完成后返回对象类型列表中,可以查看已创建的对象类型。
-
单击“导出”。
-
选择导出文件格式,选择“java格式”。
-
单击“确定”。导出的JAVA文件包含该版本中所有的对象类型信息。在接下来的步骤中,该文件将被添加到本地开发环境中。
10、新增存储区
-
登录AppGallery Connect,选择“我的项目”。
-
在项目列表页面中选择项目。
-
在导航树上点击“构建 > 云数据库”。
-
单击“存储区”页签。
-
单击“新增”,进入创建存储区页面。
-
设置“存储区名称”为“QuickLine”。
-
单击“确定”。
11、添加对象类型文件
将导出的JAVA格式文件添加至本地开发环境。如已存在,请覆盖原文件。为保证集成成功,请勿修改导出的JAVA文件。
12、初始化云数据库
在添加对象类型文件后,您可以使用云数据库开发应用。开发应用前,需要初始化AGConnectCloudDB,然后创建Cloud DB zone和对象类型。示例代码已在各步骤中列出,方便您查看。
-
在application类中初始化云数据库。您需在CloudDbWrapper.kt中创建initialize方法来初始化AGConnectCloudDB。
AGConnectCloudDB.initialize(context)
-
为云数据库创建RoutePolicy、Instance、和ObjectTypes。
instance = AGConnectInstance.buildInstance(AGConnectOptionsBuilder() .setRoutePolicy(AGCRoutePolicy.GERMANY) .build(context)) cloudDB = AGConnectCloudDB.getInstance( AGConnectInstance.getInstance(), AGConnectAuth.getInstance()) cloudDB?.createObjectType(ObjectTypeInfoHelper.getObjectTypeInfo())
-
创建存储区配置对象并打开该存储区。
config = CloudDBZoneConfig( Constants.CloudDbZoneName, CloudDBZoneConfig.CloudDBZoneSyncProperty.CLOUDDBZONE_CLOUD_CACHE, CloudDBZoneConfig.CloudDBZoneAccessProperty.CLOUDDBZONE_PUBLIC ) config?.persistenceEnabled = true val task = cloudDB?.openCloudDBZone2(config!!, true) task?.addOnSuccessListener { cloudDBZone = it cloudDbInitializeResponse(true) }?.addOnFailureListener { Log.e(TAG, "Open cloudDBZone failed for " + it.message) cloudDbInitializeResponse(false) }
13、写入数据
本节主要介绍如何使用云数据库服务在应用中写入数据。本例使用executeUpsert方法写入数据。如下代码通过方法调用将SDP示例代码写入数据库中。
fun call() {
Log.d(TAG, "contacts: called")
peerConnection?.createOffer(
SdpObserverImpl(
onCreateSuccessCallback = { sdp ->
Log.d(TAG, "contacts: onCreateSuccessCallback called")
peerConnection?.setLocalDescription(SdpObserverImpl(
onSetSuccessCallback = {
Log.d(TAG, "contacts: onSetSuccess called")
val offerSdp = CallsSdp()
offerSdp.meetingID = meetingID
offerSdp.sdp = Text(sdp.description)
offerSdp.callType = sdp.type.name
val upsertTask = cloudDBZone?.executeUpsert(offerSdp)
upsertTask?.addOnSuccessListener { cloudDBZoneResult ->
Log.i(TAG, "Calls Sdp Upsert success: $cloudDBZoneResult")
}?.addOnFailureListener {
Log.e(TAG, "Calls Sdp Upsert failed: ${it.message}")
}
Log.e(TAG, "onSetSuccess")
}
), sdp)
}
), _mediaConstraints
)
}
14、查看数据
不同场景下需要查看的数据不同,例如,查看注册用户列表。我们使用executeQuery方法实现这个功能。如您定义查询和策略参数后收到成功消息,您可以通过收到的截图访问数据并添加到用户列表中。
Sample code:
fun queryUsers(userList: (ArrayList<Users>) -> Unit) {
val queryUsers = CloudDBZoneQuery.where(Users::class.java)
val queryTask = cloudDBZone?.executeQuery(
queryUsers,
CloudDBZoneQuery.CloudDBZoneQueryPolicy.POLICY_QUERY_FROM_CLOUD_ONLY
)
queryTask?.addOnSuccessListener { snapshot ->
val usersList = arrayListOf<Users>()
try {
while (snapshot.snapshotObjects.hasNext()) {
val user = snapshot.snapshotObjects.next()
usersList.add(user)
}
} catch (e: AGConnectCloudDBException) {
Log.e(TAG, "processQueryResultExc: " + e.message)
} finally {
userList(usersList)
snapshot.release()
}
}?.addOnFailureListener {
Log.e(TAG, "Fail processQueryResult: " + it.message)
}
}
15、使用安全检测服务提高设备安全性
安全检测服务提供强健的安全能力。本项目使用SysIntegrity来检查运行应用的设备是否安全,例如,检查设备是否被root过。
-
将编译依赖项添加到“dependencies”中。
dependencies { implementation 'com.huawei.hms:safetydetect:5.0.5.302' }
-
新增SysIntegrity代码块。
private fun invokeSysIntegrity() { val nonce = ByteArray(24) try { val random: SecureRandom = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { SecureRandom.getInstanceStrong() } else { SecureRandom.getInstance("SHA1PRNG") } random.nextBytes(nonce) } catch (e: NoSuchAlgorithmException) { Log.e("NoSuchAlgorithmException", e.message!!) } SafetyDetect.getClient(this) .sysIntegrity(nonce, "YOUR_APPID") .addOnSuccessListener { response -> val jwsStr = response.result val jwsSplit = jwsStr.split(".").toTypedArray() val jwsPayloadStr = jwsSplit[1] val payloadDetail = String( Base64.decode( jwsPayloadStr.toByteArray(StandardCharsets.UTF_8), Base64.URL_SAFE ), StandardCharsets.UTF_8 ) try { val jsonObject = JSONObject(payloadDetail) val basicIntegrity = jsonObject.getBoolean("basicIntegrity") val isBasicIntegrity = basicIntegrity.toString() val basicIntegrityResult = "Basic Integrity: $isBasicIntegrity" Log.i("Basic Integrity", basicIntegrityResult) showToastLong(this, "The device is secure") if (!basicIntegrity) { Log.i("Advice", jsonObject.getString("advice")) } } catch (e: JSONException) { val errorMsg = e.message Log.e("JsonException", errorMsg ?: "unknown error") } } .addOnFailureListener { e -> val errorMsg: String? = if (e is ApiException) { SafetyDetectStatusCodes.getStatusCodeString(e.statusCode) + ": " + e.message } else { e.message } Log.e("TAG", errorMsg.orEmpty()) errorMsg?.let { showToastShort(this, it) } }
16、使用推送服务和分析服务实现面向受众的推送
推送服务实现消息发送。分析服务提供用户数据,推送服务能更精准地把消息推送给目标用户。
-
将编译依赖项添加到“dependencies”中。
dependencies { implementation 'com.huawei.hms:push:6.5.0.300' implementation 'om.huawei.hms:hianalytics:6.5.0.300' }
-
在Activity或Fragment中启用华为分析服务。
HiAnalyticsTools.enableLog() HiAnalytics.getInstance(this)
-
Generate a user's token.
fun getPushToken(context: Context) { coroutineScope.launch { async(dispatcher) { val tokenScope = "HCM" val token = HmsInstanceId.getInstance(context).getToken("YOUR_APP_ID", tokenScope) Log.i("PushNotificationTAG", "get token:$token") userPushTokenLiveData.postValue(token) } } }
-
在AppGallery Connect推送服务页面发送通知。
17、真实用户验证
静态活体检测服务实时捕捉人脸,无需用户另外操作即可检测是否为真实人脸还是虚假人脸(例如,捕捉的人脸图片、视频截图、面具等)
-
将编译依赖项添加到“dependencies”中。
dependencies { implementation 'com.huawei.hms:ml-computer-vision-livenessdetection:2.2.0.300302'}
-
在AndroidManifest.xml文件中添加权限,确保活体检测服务能访问摄像机。
<uses-permission android:name="android.permission.CAMERA" />
-
添加必要条件并获得用户同意后,添加验证用户是否真实的代码。
private fun livenessDetection() { //获取活体检测配置并设置面具和太阳镜检测。 val captureConfig: MLLivenessCaptureConfig = MLLivenessCaptureConfig.Builder().setOptions( MLLivenessCaptureConfig.DETECT_MASK ).build() //获取活体检测插件实体。 val capture: MLLivenessCapture = MLLivenessCapture.getInstance() capture.setConfig(captureConfig) capture.startDetect(requireActivity(), this.callback) }
18、测试和验证
完成必要步骤后,将手机和电脑连接,启用USB调测模式。在Android Studio页面,点击运行 您创建的项目,生成APK包。在手机上安装APK包。
-
安装完成后,打开应用。
-
使用华为账号登录。
-
如您没有会议ID,输入一个ID并点击“CREATE”按钮生成会议。然后您可以把会议ID分享给好友,开始视频会议。
-
如需呼叫联系人,在“Contacts”页面点击。
注意:如对方在忙,呼叫将失败。
19、恭喜您
祝贺您,您已经成功完成了本codelab并学到了:
-
如何集成Cloud DB和WebRTC。
-
如何集成机器学习服务和真实用户验证。
-
如何使用推送服务和分析服务实现面向受众的提醒。
-
如何使用Kotlin和MVVM架构。
20、参考文件
华为认证服务
开发指南 | FAQs
华为崩溃服务
开发指南 | FAQs
华为云数据库
开发指南 | FAQs
华为安全检测服务
开发指南 | FAQs
华为推送服务
开发指南 | FAQs
华为分析服务
开发指南 | FAQs
华为机器学习服务
开发指南 | FAQs
WebRTC
开发指南
您可以下载源代码。
欲了解更多更全技术文章,欢迎访问https://developer.huawei.com/consumer/cn/forum/?ha_source=zzh