Android 标准 Demo
1. Android 标准 Demo 说明
Android 标准 Demo 基于 OpenSDK 组件,实现了 Imou 云开放平台音视频相关的核心能力。
建议开发者阅读 Demo 源码作为参考,或移植到自有工程,以加快集成。
特别注意:
Demo 无后台 SaaS 服务,因此在客户端直接请求开放平台接口获取数据等。
建议开发者通过自有后端 SaaS 服务调用 Imou 开放平台 OpenApi,再将数据返回客户端 App,整体采用云云对接架构。
调用 Imou 云开放平台接口需要 appId 与 appSecret。若将 appId、appSecret 写入客户端(APP)代码,一旦 App 被反编译,存在凭证泄露风险。
流程如下:

2. 功能说明
管理员模式登录:获取 accessToken,作为各 Api 接口与 SDK 方法的必填参数
获取设备列表:分别获取绑定在开放平台与 easy4ip App 下的设备
设备详情:设备解绑、布撤防、升级、网络配置等
实时预览:视频播放、语音对讲、抓图、本地录像等
录像回放:录像下载、云录像/设备录像回放、倍速播放等
设备添加 功能已封装为独立模块组件,可直接使用

3. 术语说明
| 术语 | 说明 |
|---|---|
| 管理员模式 | 使用在开放平台注册的 AppId、AppSecret 换取 accessToken,类似账号登录 |
| 获取设备列表 | 通过开发者账号请求 设备列表 相关接口,从 Imou 云开放平台获取该账号下的设备列表 |
| 实时预览、本地录像/抓图 | 实时预览指在客户端(如手机)获取设备实时码流并解码显示; 本地录像指将预览码流保存为本地视频文件,支持 MP4; 本地抓图指预览过程中将当前画面保存为本地图片,格式为 JPG |
| 设备录像回放 | 在客户端获取设备 SD 卡中存储的录像文件流并解码显示 |
| 语音对讲 | 客户端与设备之间的对讲过程,当前支持双向语音对讲 |
| 云录像回放 | 客户端获取设备上传至云端的录像并解码显示 |
| 动检开关 | 设备检测到移动时是否产生告警消息与录像 |
| 云台(PTZ) | 通过终端(如 App)控制设备转动 |
| OpenApi | 客户端与 easy4ip 平台之间的接口,Restful Api 风格 |
4. 工程结构说明
从官网下载 Demo 源码并解压后,目录结构如下图所示:
- DeviceAddModule 文件夹:设备添加模块
- DeviceDetailModule 文件夹:设备详情模块
MediaModule 文件夹:媒体模块
MessageModule 文件夹:消息模块
mobilecommon 文件夹:公共模块
PlayBackModule 文件夹:录像回放模块
thrid zxing 文件夹:设备添加模块依赖,主要用于添加设备时扫码(读取设备二维码并解析)
usermodule 文件夹:用户模块
app 文件夹:Demo 源码,依赖 DeviceAddModule

5. 管理员账号模拟登录
开发者应用场景不同,使用的 easy4ip 开放平台云视频能力也会有所差异。
在获取管理员设备列表并操作设备前,须先获取 accessToken(管理员 token)。我们将获取 accessToken 的过程称为管理员账号模拟登录。取得管理员 token 后,直接进入设备列表界面。
Android Demo 源码已实现 accessToken 接口调用逻辑,详见 com.mm.android.mobilecommon.openapi.TokenHelper.java 类中的 getToken 方法。
6. 获取设备列表
Demo 会展示该账号下绑定在开放平台与 easy4ip App 的设备列表。示例代码见 com.lechange.demo.ui.DeviceListActivity.java 中的 deviceList 方法。
流程如下图所示:

7. 实时预览页
实时预览页主要展示从设备拉取的实时视频流,支持横屏与竖屏两种播放样式,并包含对讲、云台、抓图/录像等功能。详见 Demo 中的 DeviceOnlineMediaPlayActivityNew.java。
流程如下图所示:

7.1 实时预览与语音对讲
两项功能均调用 SDK 方法,涉及的部分 SDK 接口参数说明如下:
设备编号:在获取设备详细列表时可得到对应设备编号
通道号:在获取设备详细列表时可得到对应通道号
播放码:在获取设备详细列表时可得到对应播放码
码流类型:默认为高清;0:高清;1:标清
7.2 云台
通过 OpenApi 实现 App 控制设备,具体代码见 DeviceInfoOpenApiManager.java 的 controlMovePTZ 方法。
7.3 录像列表
购买云存储套餐后可查看云录像,相关 OpenApi 请求见 DeviceInfoOpenApiManager.java 的 getCloudRecords 方法。
设备插入 TF 卡后可查看设备录像,相关 OpenApi 请求见 DeviceInfoOpenApiManager.java 的 queryLocalRecords 方法。
7.4 视频封面
Demo 在退出实时预览页前会保存最后一帧,写入本地数据库与 SD 卡,作为设备列表页与预览页默认图。具体代码见 DeviceLocalCacheManager.java 与 DeviceLocalCacheDatabase.java。
8. 设备详情
8.1 设备升级
设备程序有更新时,可通过 OpenApi 升级设备,代码见 DeviceInfoOpenApiManager.java 的 upgradeDevice 方法。
8.2 设备重命名
代码见 DeviceInfoOpenApiManager.java 的 modifyDeviceName 方法。
8.3 设备布撤防
代码见 DeviceInfoOpenApiManager.java 的 modifyDeviceAlarmStatus 方法。
8.4 设备网络配置
设备在线时,可通过 OpenApi 查询设备当前连接的 Wi-Fi 及周围 Wi-Fi,并切换设备连接的 Wi-Fi。
相关 OpenApi 代码:
DeviceAddOpenApiManager.java 的 CurrentDeviceWifi 方法
DeviceAddOpenApiManager.java 的 WifiAround 方法
DeviceAddOpenApiManager.java 的 ControlDeviceWifi 方法
8.5 解绑设备
代码见 DeviceInfoOpenApiManager.java 的 unBindDevice 方法。
8.6 本地存储
代码见 DeviceInfoOpenApiManager.java 的 getDeviceStoreInfo、deviceSdcardStatus 方法。
8.7 云存储
代码见 DeviceInfoOpenApiManager.java 的 setAllStorageStrategy 方法。
9. 录像回放
录像回放页展示录像列表中某一段的回放,主要包括云录像播放/暂停、下载、倍速、抓图、录像,以及设备录像播放/暂停、抓图、录像等。相关功能均调用 SDK 方法,详见 DeviceRecordPlayActivityNew.java。
主流程如下:

10. 设备添加组件
10.1 使用流程
将 DeviceAddModule 导入自有工程,步骤如下:
- 在 Android Studio 菜单栏选择 File -> New -> Import Module

- 选择 Demo 工程中 DeviceAddModule 所在路径,点击 Finish 完成导入


- 在工程 app 目录的 build 文件中添加依赖,示例:
//High version Android Stduio
api project(':usermodule')
api project(':MediaModule')
api project(':PlaybackModule')
api project(':MessageModule')
api project(':DeviceDetailmodule')
//Or lower version Android Stduio
compile project(':usermodule')
compile project(':MediaModule')
compile project(':PlaybackModule')
compile project(':MessageModule')
compile project(':DeviceDetailmodule')
说明: 部分开发者完成上述集成后,编译可能出现 Manifest merger failed with multiple errors, see logs。须在 AndroidManifest.xml 的 application 节点下添加 tools:replace="android:allowBackup,android:label,android:supportsRtl"。
- 若在 build.gradle 中设置 targetSdkVersion >= 29,须在 AndroidManifest.xml 的 application 节点添加 android:requestLegacyExternalStorage="true",以申请兼容存储权限。
<application
android:allowBackup="false"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:requestLegacyExternalStorage="true"
tools:replace="android:allowBackup,android:label,android:supportsRtl"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
- 当前设备添加模块以源码形式提供。集成后若需对设备相关代码混淆,可在混淆配置中加入模块涉及的 jar/aar 包规则:
#gson
-keepattributes Signature
-dontwarn com.google.gson.**
-keep class sun.misc.Unsafe {*;}
-keep class com.google.gson.**{*;}
#eventbus
-keep class org.greenrobot.eventbus.**{*;}
-keepclassmembers class **{
@org.greenrobot.eventbus.Subscribe <methods>;
}
-keep enum org.greenrobot.eventbus.ThreadMode {*;}
#zxing.jar
-dontwarn com.google.zxing.**
-keep class com.google.zxing.**{*;}
#lechangeSDK.jar
-dontwarn com.lechange.**
-keep class com.lechange.**{*;}
-dontwarn com.company.**
-keep class com.company.**{*;}
#pulltorefreshlib.jar
-dontwarn com.lechange.pulltorefreshlistview.**
-keep class com.lechange.pulltorefreshlistview.**{*;}
#DHScanner-1.0.7.aar
-dontwarn com.mm.android.**
-keep class com.mm.android.**{*;}
#imageload4dh.jar
-dontwarn com.nostra13.universalimageloader.**
-keep class com.nostra13.universalimageloader.**{*;}
10.2 调用示例代码
/**
* The first step: initialize the device to add a module
*
* 1: When using the device to add a module, you must first call this method to complete the initialization. This initialization will include the setHost() method in the LCOpenSDK_Api class, so there is no need to call setHost() again
* 2: This method will throw an exception. If the initialization fails (such as failure to obtain the token, etc.), the specific Throwable will be returned in the exception
*/
try {
CommonParam commonParam = new CommonParam();
// 开放平台域名(含端口),与 OpenSDK 初始化 host 一致
commonParam.setEnvirment("https://openapi-[DataCenter].easy4ip.com:443");
//(Required) Android Application object
commonParam.setContext(EnvGuideActivity.this.getApplication());
//(Required) Application Id (obtained by registration on easy4ip Open Platform)
commonParam.setAppId("Please replace with your own appId");
//(Required) Application Id (obtained by registration on easy4ip Open Platform)
commonParam.setAppSecret("Please replace with your own appSecret");
//(Optional) The unique id of the user, the default appId
commonParam.setUserId("");
//Start initialization
LCDeviceEngine.newInstance().init(commonParam);
} catch (Throwable e) {
}
/**
* Step 2: Open the device adding process
*
* 1: This method will throw an exception (such as uninitialized, etc.)
* 2: This method needs to be called after the init initialization is successful
*/
try {
LCDeviceEngine.newInstance().addDevice(this);
} catch (Exception e) {
}
10.3 注意事项
设备添加模块的 AndroidManifest.xml 已默认声明 easy4ip SDK 所需的全部权限,集成后开发者无需重复声明。具体权限见该模块的 AndroidManifest.xml。
设备添加模块中 LCDeviceEngine 类的 Init 方法已调用 LCOpenSDK_Api.setHost,若工程使用了该模块,无需再次调用 setHost。
设备添加模块源码当前不支持 AndroidX。若工程使用 AndroidX,可采用以下方式迁移:
方式一:使用 Android Studio 将工程迁移至 AndroidX(具体操作请自行查阅文档);
方式二:将设备添加模块打包为 aar 后再引入工程。
