更新时间:2024-09-13 GMT+08:00

快速入门

本文面向有一定Android原生开发能力的开发者,以登录华为云会议并发起和加入视频会议的流程为例,介绍如何使用SDK 进行二次开发

开发环境准备

在接入SDK前需要准备如下环境:

环境要求(强制要求)

开发环境,目的是为了给编译运行源码的人员提供参考:

环境要求(非强制要求)

SDK快速集成

  1. 解压SDK

    下载解压软件包,得到如下几个文件:

    图1 文件目录

  2. 新建工程

    • 打开Android Studio,单击File -> New -> New Project...新建工程,选择Phone and Tablet -> Empty Activity 单击Next:
    图2 创建工程

    • 输入相关项目信息,单击“Finish”完成工程创建。(请注意最小Android API 版本为23):
    图3 设置名称

  3. 集成SDK

    • 在Android Studio中,将工程目录结构切换到Project:
      图4 切换成Project

    • 将libs下的aar包拷贝到你的工程目录:
      图5 添加aar

  4. 添加依赖

    • 添加三方依赖。

    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仓

    图9 gradle-wrapper.properties

    • 单击Build -> make project,等待项目编译完成

    如果客户集成libc++_shared.so到app层面,无需配置;如果使用的第三方库的aar中使用到了该动态库,则只需在build.gradle中做如下配置即可:

    packagingOptions {

    merge lib/armeabi-v7a/libc++shared.so

    }

  5. 配置混淆

    • 设置混淆,在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.** { *;}

  6. 添加权限

    在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" />

  7. 添加屏幕共享的服务

    如果需要使用会中屏幕共享功能,在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"/>
    

  8. SDK初始化

    • 初始化建议放在Application的onCreate里,尽量时序提前,以保证sdk内部可以通过监听activity的生命周期的方式来获取当前activity并跳转界面:
      1
      2
      3
      OpenSDKConfig sdkConfig = new OpenSDKConfig(this)        
               .setAppId(getAppId())    //设置唯一App ID,可填应用英文名,使用App ID登录必须设置
      HWMSdk.init(this,sdkConfig);
      

  9. 接口调用示例。

    • 登录接口
      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工程。