更新时间:2024-09-13 GMT+08:00
快速入门
本文面向有一定Android原生开发能力的开发者,以登录华为云会议并发起和加入视频会议的流程为例,介绍如何使用SDK 进行二次开发
SDK快速集成
- 解压SDK
下载解压软件包,得到如下几个文件:
图1 文件目录 - 新建工程
- 打开Android Studio,单击 新建工程,选择Phone and Tablet -> Empty Activity 单击Next:
图2 创建工程- 输入相关项目信息,单击“Finish”完成工程创建。(请注意最小Android API 版本为23):
图3 设置名称 - 集成SDK
- 在Android Studio中,将工程目录结构切换到Project:
图4 切换成Project
- 将libs下的aar包拷贝到你的工程目录:
图5 添加aar
- 在Android Studio中,将工程目录结构切换到Project:
- 添加依赖
- 添加三方依赖。
SDK依赖了一些优秀的开源库,需要在gradle中添加对这些库的依赖,方法如下。
在项目根目录下创建config.gradle(如您已创建统一配置文件,可参考demo中config.gradle中配置版本):
图6 打开config.gradle- 在项目build.gradle内首行添加:
apply from:"config.gradle"
config.gradle内使用到的第三方依赖声明及版本号:"rxandroid" : 'io.reactivex.rxjava3:rxandroid:3.0.2', "appcompat-v7" : 'androidx.appcompat:appcompat:1.4.1', "vectordrawable" : 'androidx.vectordrawable:vectordrawable:1.2.0-beta01', "rxjava" : 'io.reactivex.rxjava3:rxjava:3.0.13', "recyclerview" : 'androidx.recyclerview:recyclerview:1.2.1', "palette" : 'androidx.palette:palette:1.0.0', "aspectjrt" : 'org.aspectj:aspectjrt:1.9.6', "okhttp" : 'com.squareup.okhttp3:okhttp:4.11.0', "gson" : 'com.google.code.gson:gson:2.10.1', "design" : 'com.google.android.material:material:1.6.1', "annotations" : 'androidx.annotation:annotation:1.0.0', "lifecycle-process" : 'androidx.lifecycle:lifecycle-process:2.5.1', "eventbus" : 'org.greenrobot:eventbus:3.2.0', "tinypinyin" : 'com.github.promeg:tinypinyin:3.0.0', "constraint-layout" : 'androidx.constraintlayout:constraintlayout:2.0.4', "glide" : 'com.github.bumptech.glide:glide:4.11.0', "glide:compiler" : 'com.github.bumptech.glide:compiler:4.11.0', "legacy" : 'androidx.legacy:legacy-support-v13:1.0.0', "swiperefreshlayout" : 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0', "viewbinding" : 'androidx.databinding:viewbinding:7.1.3'
图7 设置项目build.gradle- 在app/build.gradle添加开源包依赖及会议sdk依赖:
由于原Android support库已不再被Google维护演进,将从28版本升级替换为AndroidX。
因此华为云会议从8月发布的70.8.5版本开始,将不再在support库基础上开发,而是替换为AndroidX进行迭代。
如果您仍在使用原Android support库依赖:
- 我们推荐您与我们一样更新替换使用新的AndroidX依赖,以免您在后续开发时无法正常对接我们采用AndroidX的SDK版本,相关文档请见快速入门。
- 如果您无法立即更新,我们会提供原有基于support库开发的SDK入口,并持续维护6个月。在维护期间,您仍可以集成我们的旧版SDK(70.7.5及之前版本)进行开发,我们会对于此类版本发现的问题进行修复与更新,但是之后迭代的新功能将只在AndroidX版本SDK上实现。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
//sdk 用到的一些三方框架 api rootProject.ext.dependencies["appcompat-v7"] api rootProject.ext.dependencies["recyclerview"] api rootProject.ext.dependencies["design"] api rootProject.ext.dependencies["aspectjrt"] api rootProject.ext.dependencies["rxandroid"] api rootProject.ext.dependencies["constraint-layout"] api rootProject.ext.dependencies["glide"] implementation rootProject.ext.dependencies["rxjava"] implementation rootProject.ext.dependencies["gson"] implementation rootProject.ext.dependencies["eventbus"] implementation rootProject.ext.dependencies["okhttp"] implementation rootProject.ext.dependencies["lifecycle-process"] implementation rootProject.ext.dependencies["viewbinding"] implementation rootProject.ext.dependencies["swiperefreshlayout"] //添加会议依赖 implementation(name: 'hwmmediapicker-release', ext: 'aar') implementation(name: 'HWMSdk-release', ext: 'aar')
- 在project/build.gradle allprojects/repositories内添加
flatDir { dirs 'libs' }
在无法连接谷歌的情况下可以添加自己的maven仓
图8 添加maven仓- 配置gradle-wrapper.properties,参照配置gradle-wrapper.properties
图9 gradle-wrapper.properties- 单击Build -> make project,等待项目编译完成
如果客户集成libc++_shared.so到app层面,无需配置;如果使用的第三方库的aar中使用到了该动态库,则只需在build.gradle中做如下配置即可:
packagingOptions {
merge lib/armeabi-v7a/libc++shared.so
}
- 配置混淆
- 设置混淆,在build.gradle中添加:
buildTypes { release { minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } }
- 混淆文件proguard-rules.pro中添加
# 不开启优化,因为android的dex并不像Java虚拟机需要optimize(优化)和preverify(预检)两个步骤。 -dontoptimize #不使用大小写混合类名,注意,windows用户必须为ProGuard指定该选项, #因为windows对文件的大小写是不敏感的,也就是比如a.java和A.java会认为是同一个文件。 #如果不这样做并且你的项目中有超过26个类的话,那么ProGuard就会默认混用大小写文件名,导致class文件相互覆盖 -dontusemixedcaseclassnames #指定不去忽略非公共库的类和成员 -dontskipnonpubliclibraryclasses -dontskipnonpubliclibraryclassmembers #抛出异常时保留代码行号,方便抛出异常时定位问题 -keepattributes SourceFile,LineNumberTable #重命名抛出异常时的文件名称,方便抛出异常时定位问题 -renamesourcefileattribute SourceFile # 混淆后就会生成映射文件 # 包含有类名->混淆后类名的映射关系 # 然后可以使用printmapping指定映射文件的名称 -verbose # 不做预校验,preverify是proguard的4个步骤之一 # Android不需要preverify,去掉这一步可加快混淆速度 -dontpreverify # dump.txt文件列出apk包内所有class的内部结构 -dump class_files.txt # seeds.txt文件列出未混淆的类和成员 -printseeds seeds.txt # usage.txt文件列出从apk中删除的代码 -printusage usage.txt # mapping.txt文件列出混淆前后的映射 -printmapping mapping.txt #忽略library里面非public修饰的类。 #library里的非公开类是不能被程序使用的,忽略掉这些类可以加快混淆速度。 #但是请注意,有一种特殊情况:有些人编写的代码与类库中的类在同一个包下,而且对该包的非public类进行了使用,在这种情况下,就不能使用该选项了。 #-skipnonpubliclibraryclasses # 保留注解,因为注解是通过反射机制来实现的 -keepattributes *Annotation* # 保留js接口 -keepattributes *JavascriptInterface* # 保留exception -keepattributes Exceptions # 保留内部类 -keepattributes InnerClasses #保留泛型 -keepattributes Signature #保留本地native方法不被混淆 -keepclasseswithmembernames class * { native <methods>; } #保留枚举类 -keepclassmembers enum * { public static **[] values(); public static ** valueOf(java.lang.String); } # 保留Parcelable序列化类不被混淆 -keep class * implements android.os.Parcelable { public static final android.os.Parcelable$Creator *; } # 保留Serializable序列化的类不被混淆 -keepclassmembers class * implements java.io.Serializable { static final long serialVersionUID; private static final java.io.ObjectStreamField[] serialPersistentFields; !static !transient <fields>; !private <fields>; !private <methods>; private void writeObject(java.io.ObjectOutputStream); private void readObject(java.io.ObjectInputStream); java.lang.Object writeReplace(); java.lang.Object readResolve(); } # 保留资源应用名 -keepclassmembers class **.R$* { public static <fields>; } # 忽略support包下的警告 -dontwarn android.support.** # 保留support包下的动画 -keep class android.support.annotation.Keep -keep @android.support.annotation.Keep class * {*;} -keepclasseswithmembers class * { @android.support.annotation.Keep <methods>; } -keepclasseswithmembers class * { @android.support.annotation.Keep <fields>; } -keepclasseswithmembers class * { @android.support.annotation.Keep <init>(...); } #保留系统类库 -keep public class * extends android.app.Activity -keep public class * extends android.app.Application -keep public class * extends android.app.Service -keep public class * extends android.content.BroadcastReceiver -keep public class * extends android.preference.Preference -keep public class * extends android.content.ContentProvider -keep public class * extends android.view.View { public <init>(android.content.Context); public <init>(android.content.Context, android.util.AttributeSet); public <init>(android.content.Context, android.util.AttributeSet, int); public void set*(...); } #保留华为sdk相关 -keep class com.hianalytics.android.**{*;} -keep class com.huawei.updatesdk.**{*;} -keep class com.huawei.hms.**{*;} -keep class com.huawei.android.hms.agent.**{*;} #OKhttp 混淆配置 #https://github.com/square/okhttp/blob/5fe3cc2d089810032671d6135ad137af6f491d28/README.md#proguard -dontwarn okhttp3.** -dontwarn okio.** -dontwarn javax.annotation.** -dontwarn org.conscrypt.** # A resource is loaded with a relative path so the package of this class must be preserved. -keepnames class okhttp3.internal.publicsuffix.PublicSuffixDatabase #Eventbus 混淆配置 #http://greenrobot.org/eventbus/documentation/proguard/ -keepclassmembers class ** { @org.greenrobot.eventbus.Subscribe <methods>; } -keep enum org.greenrobot.eventbus.ThreadMode { *; } # Only required if you use AsyncExecutor #-keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent { # <init>(java.lang.Throwable); #} #配置HME java不混淆,C++ 会调用,HMW-Video.jar -keep class com.huawei.media.audio.AudioDeviceAndroid { *;} -keep class com.huawei.media.audio.AudioDeviceAndroidService { *;} -keep class com.huawei.media.audio.JniAudioDeviceImpl { *;} -keep class com.huawei.media.audio.JniAudioDeviceMeetingImpl { *;} -keep class com.huawei.media.audio.JniAudioDeviceRtcImpl { *;} -keep class com.huawei.media.video.Camera2Characteristic { *;} -keep class com.huawei.media.video.CaptureCapabilityAndroid { *;} -keep class com.huawei.media.video.DeviceInfo { *;} -keep class com.huawei.media.video.H264Decoder { *;} -keep class com.huawei.media.video.HmeDefinitions { *;} -keep class com.huawei.media.video.JNIBridge { *;} -keep class com.huawei.media.video.JNIBridgeImpl { *;} -keep class com.huawei.media.video.JNIMeetingImpl { *;} -keep class com.huawei.media.video.JNIRtcImpl { *;} -keep class com.huawei.media.video.KirinMediaCodecEncoder { *;} -keep class com.huawei.media.video.LogFile { *;} -keep class com.huawei.media.video.MediaCodecDecoder { *;} -keep class com.huawei.media.video.MediaCodecEncoder { *;} -keep class com.huawei.media.video.ScreenCaptureImageActivity { *;} -keep class com.huawei.media.video.SurfaceEncoder { *;} -keep class com.huawei.media.video.VideoCapture { *;} -keep class com.huawei.media.video.VideoCapture2Android { *;} -keep class com.huawei.media.video.VideoCaptureAndroid { *;} -keep class com.huawei.media.video.VideoCaptureDeviceInfo { *;} -keep class com.huawei.media.video.VideoCaptureDeviceInfoAndroid { *;} -keep class com.huawei.media.video.VideoRender { *;} -keep class com.huawei.media.video.VideoRenderNoGLES { *;} -keep class com.huawei.media.video.ViEAndroidGLES20 { *;} -keep class com.huawei.media.video.ViERenderer { *;} -keep class com.huawei.media.video.ViESurfaceRenderer { *;} -keep class com.huawei.media.video.VtNativeDecoder { *;} -keep class com.huawei.media.video.codec.KirinDecoder { *;} -keep class com.huawei.media.video.codec.KirinEncoder { *;} -keep class com.huawei.media.video.codec.** { *;} -keep class com.huawei.media.video.Camera2VideoCapture { *;} -keep class com.huawei.media.video.capture.Camera2EncodedImageReader { *;} -keep class com.huawei.media.video.capture.Camera2TextureImageReader { *;} -keep class com.huawei.media.video.capture.Camera2VideoCaptureImpl { *;} -keep class com.huawei.media.video.capture.Camera2YUVImageReader { *;} -keep class com.huawei.media.video.capture.CaptureRequestExKeyUtils { *;} -keep class com.huawei.media.video.capture.StreamConfig { *;} -keep class com.huawei.media.video.capture.StreamResolution { *;} -keep class com.huawei.media.video.capture.VideoCaptureDevInfoCamera2Impl { *;} -keep class com.huawei.media.mcuvideo.CaptureCapabilityAndroid { *;} -keep class com.huawei.media.mcuvideo.HmeDefinitions { *;} -keep class com.huawei.media.mcuvideo.JNIBridge { *;} -keep class com.huawei.media.mcuvideo.LogFile { *;} -keep class com.huawei.media.mcuvideo.MediaCodecDecoder { *;} -keep class com.huawei.media.mcuvideo.MediaCodecEncoder { *;} -keep class com.huawei.media.mcuvideo.VideoCapture { *;} -keep class com.huawei.media.mcuvideo.VideoCaptureDeviceInfo { *;} -keep class com.huawei.media.mcuvideo.VideoRender { *;} -keep class com.huawei.media.mcuvideo.VideoRenderNoGLES { *;} -keep class com.huawei.media.mcuvideo.ViERenderer { *;} -keep class com.huawei.media.mcuvideo.codec.** { *;} -keep class com.huawei.media.mcuvideo.capture.Camera2EncodedImageReader { *;} -keep class com.huawei.media.mcuvideo.capture.Camera2TextureImageReader { *;} -keep class com.huawei.media.mcuvideo.capture.Camera2VideoCaptureImpl { *;} -keep class com.huawei.media.mcuvideo.capture.Camera2YUVImageReader { *;} -keep class com.huawei.media.mcuvideo.capture.CaptureRequestExKeyUtils { *;} -keep class com.huawei.media.mcuvideo.capture.StreamConfig { *;} -keep class com.huawei.media.mcuvideo.capture.StreamResolution { *;} -keep class com.huawei.media.mcuvideo.capture.VideoCaptureDevInfoCamera2Impl { *;} -keep class com.huawei.media.oldvideo.CaptureCapabilityAndroid { *;} -keep class com.huawei.media.oldvideo.HmeDefinitions { *;} -keep class com.huawei.media.oldvideo.JNIBridge { *;} -keep class com.huawei.media.oldvideo.LogFile { *;} -keep class com.huawei.media.oldvideo.MediaCodecDecoder { *;} -keep class com.huawei.media.oldvideo.MediaCodecEncoder { *;} -keep class com.huawei.media.oldvideo.VideoCapture { *;} -keep class com.huawei.media.oldvideo.VideoCaptureDeviceInfo { *;} -keep class com.huawei.media.oldvideo.VideoRender { *;} -keep class com.huawei.media.oldvideo.VideoRenderNoGLES { *;} -keep class com.huawei.media.oldvideo.ViERenderer { *;} -keep class com.huawei.media.oldvideo.codec.** { *;} #配置TUP java 不混淆,c++ 会调用 -keep class tupsdk.Tupmedia { *;} #TupCall.jar -keep class com.huawei.media.data.Conference { *;} #TupConf.jar -keep class imssdk.** { *;} # rtc sdk 混淆 -keep class com.huawei.mmr.**{*;} -keep class com.huawei.mmrallplatform.**{*;} ## native sdk 混淆 -keep class com.huawei.hwmsdk.**{*;} # WebViewInterface 不能混淆 -keepclassmembers class com.huawei.hwmclink.jsbridge.model.GHConfigModel { public *; } # API不能被混淆 -keep public class com.huawei.**.*Api { *;} -keep class com.huawei.cloudlink.openapi.api.ICloudLinkOpenApi{*;} -keep class com.huawei.cloudlink.openapi.api.impl.CloudLinkOpenApiImpl{*;} -keep class com.huawei.hwmbiz.IBizOpenApi{*;} -keep class com.huawei.hwmbiz.impl.BizOpenApiImpl{*;} #micro service 不能混淆,有反射调用,参考华为云配置 -keep public class * extends com.huawei.hwmfoundation.microservice.HCMicroService -keep public class * extends com.mapp.hcmobileframework.microapp.HCMicroApplicationDelegate -keep public class * implements com.huawei.hwmclink.jsbridge.bridge.** {*;} #继承自AbsCache 的类,要保留构造函数,否则构造函数会被优化掉,这里保留所有的构造函数,不论有没有在使用 -keepclassmembers class * { <init>(...); } #RXJava 不能被混淆,因为内部有hook操作 -keep class io.reactivex.**{*;} #自定义注解不能被混淆 -keep public class com.huawei.hwmbiz.aspect.CheckToken -keep public class com.huawei.hwmfoundation.hook.annotation.TimeConsume -keep public class com.huawei.hwmfoundation.hook.annotation.HookDisable -keep public class com.huawei.hwmfoundation.hook.annotation.HookNotNeeded #glide 不混淆 -keep class com.github.bumptech.glide.**{*;} #需要用json转换生成javabean 不混淆 -keep public class * extends com.huawei.hwmfoundation.base.BaseModel{*;} #HMS SDK不可混淆 -ignorewarnings -keepattributes *Annotation* -keepattributes Exceptions -keepattributes InnerClasses -keepattributes Signature -keepattributes SourceFile,LineNumberTable -keep class com.hianalytics.android.**{*;} -keep class com.huawei.updatesdk.**{*;} -keep class com.huawei.hms.**{*;} #Androidx 混淆 -keep class com.google.android.material.** {*;} -keep class androidx.** {*;} -keep public class * extends androidx.** -keep interface androidx.** {*;} -dontwarn com.google.android.material.** -dontnote com.google.android.material.** -dontwarn androidx.** #路由表不能混淆,启动会从固定package下汇总路由表 -keep class com.huawei.cloudlink.router.routermap.** {*;} # crashreport混淆 -keep public class com.huawei.crashreport.**{*;} # IMSDK 混淆 -keep class com.huawei.imsdk.ECSProxy {*;} -keep class com.huawei.imsdk.msg.** {*;} # HWMUserState用户状态不混淆 -keep public class com.huawei.cloudlink.openapi.model.HWMUserState{*;} # netty不混淆,投影要用到-keep class io.netty.**{*;} # demo代码不用混淆 -keep class com.huawei.hwmdemo.** { *;}
- 添加权限
在AndroidManifest.xml中添加SDK必要的权限:
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.READ_PHONE_STATE" /> <uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.READ_CONTACTS" /> <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" /> <uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.WAKE_LOCK" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.DISABLE_KEYGUARD" /> <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" /> <uses-permission android:name="com.huawei.android.launcher.permission.CHANGE_BADGE" /> <uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30"/> <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" /> <uses-permission android:name="android.permission.VIBRATE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.SYSTEM_OVERLAY_WINDOW" /> <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/> <!--会议中会启动前台服务器保活--> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
- 添加屏幕共享的服务
如果需要使用会中屏幕共享功能,在AndroidManifest.xml中添加以下服务的申明
1 2 3 4
<!-- 会议sdk 需要增加以下配置,如果是compileSdkVersion >= 29,需要增加属性android:foregroundServiceType="mediaProjection", 否则去掉该属性--> <service android:name="com.huawei.hwmconf.sdk.ScreenRecorderService" android:exported="false" android:enabled="true"/>
- SDK初始化
- 初始化建议放在Application的onCreate里,尽量时序提前,以保证sdk内部可以通过监听activity的生命周期的方式来获取当前activity并跳转界面:
1 2 3
OpenSDKConfig sdkConfig = new OpenSDKConfig(this) .setAppId(getAppId()) //设置唯一App ID,可填应用英文名,使用App ID登录必须设置 HWMSdk.init(this,sdkConfig);
- 初始化建议放在Application的onCreate里,尽量时序提前,以保证sdk内部可以通过监听activity的生命周期的方式来获取当前activity并跳转界面:
- 接口调用示例。
- 登录接口
1
HWMSdk.getOpenApi(Application).login(LoginParam, HwmCallback<LoginResult>);
- 创会接口
1
HWMSdk.getOpenApi(Application).createConf(CreateConfParam, HwmCancelableCallBack<ConfInfo>);
- 入会接口
1
HWMSdk.getOpenApi(Application).joinConf(JoinConfParam, HwmCancelableCallBack<Void>);
- 退出登录接口
1
HWMSdk.getOpenApi(Application).logout(HwmCallback<LoginCompletedResult>);
完成上述调用步骤,就可以运行 新建的demo工程。
- 登录接口
父主题: Android SDK