快速入门
本文面向有一定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包拷贝到你的工程目录(10.3.6及以后版本,图5的8个aar已合并为HWMSdk-release.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.3.0', "vectordrawable" : 'androidx.vectordrawable:vectordrawable:1.2.0-alpha02', "rxjava" : 'io.reactivex.rxjava3:rxjava:3.0.13', "recyclerview" : 'androidx.recyclerview:recyclerview:1.2.1', "aspectjrt" : 'org.aspectj:aspectjrt:1.9.6', "okhttp" : 'com.squareup.okhttp3:okhttp:4.9.1', "gson" : 'com.google.code.gson:gson:2.8.9', "design" : 'com.google.android.material:material:1.3.0', "lifecycle-process" : 'androidx.lifecycle:lifecycle-process:2.4.1', "eventbus" : 'org.greenrobot:eventbus:3.3.1', "constraint-layout" : 'androidx.constraintlayout:constraintlayout:2.0.4', "glide" : 'com.github.bumptech.glide:glide:4.13.0', "swiperefreshlayout" : 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0', "hms:scan-kit" : 'com.huawei.hms:scan:2.1.0.300',
图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上实现。
华为云会议期望给您带来更好的产品体验,如有问题,请拨打4000-955-988 | 950808 按1转1进行快速解答!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
//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["hms:scan-kit"] 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中添加
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318
# 不开启优化,因为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.rtc.**{*;} -keep class com.huawei.allplatform.**{*;} ## 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.**{*;}
- 添加权限
在AndroidManifest.xml中添加SDK必要的权限:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
<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 12 中的新蓝牙权限--> <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" /> <uses-permission android:name="android.permission.VIBRATE" /> <!--会议中会启动前台服务器保活--> <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 4 5
OpenSDKConfig sdkConfig = new OpenSDKConfig(this) .setAppId(getAppId()) //设置唯一App ID,可填应用英文名,使用App ID登录必须设置 .setServerAddress(getDefaultServerAddress()) //设置会议服务器地址,可选配置项,不配置则使用默认会议服务器地址 .setServerPort(getDefaultServerPort()); //设置会议服务器端口,可选配置项,不配置则使用默认会议服务器端口 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工程。
- 登录接口