萤石云开放平台Android SDK使用说明

工程配置

快速入门

环境准备
支持 Android Studio 1.4 以上
支持 JDK 7.0 以上版本
支持 Android 手机系统 4.0 以上版本

一、创建应用

首先,你需要在萤石开放平台官网的 “ 开发者服务-我的应用-应用秘钥 ” 查看Appkey。

二、安装 SDK

SDK 的安装方式

1. 使用 Gradle 获得

如果是之前采用过直接下载方式的需要删除之前拷贝进来的所有so库文件以及jar包

dependencies {
    compile 'com.hikvision.ezviz:ezviz-sdk:4.8.0'
 }

2. 使用Maven中央仓库获得

如果是之前采用过直接下载方式的需要删除之前拷贝进来的所有so库文件以及jar包

<dependency>
    <groupId>com.hikvision.ezviz</groupId>
    <artifactId>ezviz-sdk</artifactId>
    <version>4.8.0</version>
</dependency>

3. 直接下载

下载EZOpenSDK
1、拷贝/libs/armeabi-v7a目录下so文件到自己工程对应目录;
2、拷/libs下jar包到自己工程对应目录(包含jmdns和gson);

三、 配置 Android 权限

在 AndroidMainfest.xml 文件中添加:

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
<uses-permission android:name="android.permission.READ_LOGS"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE"/>

四、 配置 build.gradle

    defaultConfig {
       ...
        targetSdkVersion 22//小于23
       ...
        ndk {
            abiFilters "armeabi-v7a"//只支持32位
        }
    }
     sourceSets {
        main {
            jniLibs.srcDirs = ['libs']
        }
    }

注意:

目前提供所有so均为32位,只能在armeabi-v7a引用,所以需要添加

    ndk {
    abiFilters "armeabi-v7a"//只支持32位
}

targetSdkVersion设置为23及以上,在android6.0系统的手机上会出现没有权限崩溃的情况,因为android6.0牵扯到Dangerous Permissions问题,如果需要使用高版本,需要自己处理Dangerous Permissions。

五、 配置 AndroidManifest.xml

添加如下activity定义,用于sdk中间页显示,包含登录、开通云存储等。

    <activity
        android:name="com.videogo.main.EzvizWebViewActivity"
        android:screenOrientation="portrait"
        android:configChanges="orientation|keyboardHidden"
    </activity>  

添加如下广播接收器,用于接收网络变化刷新SDK网络状态,接收中间页登录成功消息启动其他界面。其中##you_BroadcastReceiver替换为自己代码中定义的BroadcastReceiver

   <receiver
       android:name="you_BroadcastReceiver"
       android:exported="false" >
       <intent-filter>
            <action android:name="com.videogo.action.OAUTH_SUCCESS_ACTION" />
            <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
        </intent-filter>
   </receiver>

六、 代码初始化

一般建议在application中初始化

国内:

/** * sdk日志开关,正式发布需要去掉 */
EZOpenSDK.showSDKLog(true);
/** * 设置是否支持P2P取流,详见api */
EZOpenSDK.enableP2P(false);

/** * APP_KEY请替换成自己申请的 */
EZOpenSDK.initLib(this, APP_KEY);

海外:

/** * sdk日志开关,正式发布需要去掉 */
EZGlobalSDK.showSDKLog(true);
/** * 设置是否支持P2P取流,详见api */
EZGlobalSDK.enableP2P(false);
/** * APP_KEY请替换成自己申请的 */
EZGlobalSDK.initLib(this, APP_KEY);

七、 代码混淆

目前SDK在打包时不能混淆,请添加以下内容!

-dontwarn com.ezviz.player.**
-keep class com.ezviz.player.** { *;}

-dontwarn com.ezviz.statistics.**
-keep class com.ezviz.statistics.** { *;}

-dontwarn com.ezviz.stream.**
-keep class com.ezviz.stream.** { *;}

-dontwarn com.ezviz.hcnetsdk.**
-keep class com.ezviz.hcnetsdk.** { *;}

-dontwarn com.hik.**
-keep class com.hik.** { *;}

-dontwarn com.hikvision.**
-keep class com.hikvision.** { *;}

-dontwarn com.videogo.**
-keep class com.videogo.** { *;}

-dontwarn org.MediaPlayer.PlayM4.**
-keep class org.MediaPlayer.PlayM4.** { *;}


-dontwarn com.google.android.gcm.**
-keep class com.google.android.gcm.** { *;}

-dontwarn org.eclipse.paho.client.mqttv3.**
-keep class org.eclipse.paho.client.mqttv3.** { *;}


-dontwarn com.google.zxing.**
-keep class com.google.zxing.** { *;}

#Gson混淆配置
-keepattributes Annotation
-keep class sun.misc.Unsafe { *; }
-keep class com.idea.fifaalarmclock.entity.*
-keep class com.google.gson.stream.* { *; }

#引用mars的xlog,混淆配置
-keep class com.tencent.mars.** {
 public protected private *;
}

使用说明

一、 简介

本文档用于说明萤石开放平台SDK Android版本接口之间的关系以及接口调用顺序,对开放平台SDK Android版本各接口都有详细的说明。
对接主要接口在EZOpenSDK和EZPlayer中,请查看api。

二、 名词解释

名词 释义
accessToken 访问令牌,由server返回给client用于认证
AppKey 应用程序key
AppKey的申请可以参阅: https://open.ys7.com/view/app/app_edit.html
deviceSerial 设备序列号
CameraNo 设备通道号
deviceSerial+CameraNo 摄像头唯一标志
OSD 视频当前时间
PTZ 云台控制,可以通过终端控制操作设备

三、 功能介绍

V3.0: 账号对接(授权登录、sdk接口登录)、获取摄像头列表、直播预览、查看回放(SD卡、云存储)、设备添加删除、设备的设置功能(h5)、设备控制接口(云台、镜头画面)、WiFi配置、视频本地录像、视频截屏、报警消息等。

V3.1: 安全验证接口、获取设置设备验证码、数据解密接口等,主要功能是完成UI版本的开源项目。

V4.*: 账号对接(授权登录、sdk接口登录)、获取摄像头列表、直播预览、查看回放(SD卡、云存储)、设备添加删除、设备的设置功能、设备控制接口(云台、镜头画面)、WiFi配置、视频本地录像、视频截屏、报警消息等

四、 SDK主要流程

1. 初始化授权流程

图2

服务器对接授权客户

国内:
  1. 第三方服务器通过服务端api接口获取accesstoken和过期时间,accesstoken用来授权,过期时间用来定时刷新accesstoken

  2. 第三方服务器将获取到的accesstoken下发到第三方app(需集中EZOpenSDK),第三方app调用EZOpenSDK.getInstance().setAccessToken(String accesstoken),来完成授权

  3. EZOpenSDK会文件缓存accesstoken,下次打开app,初始化时会自动完成授权

  4. 退出登录后需要调用EZOpenSDK.getInstance().logout(),或者调用EZOpenSDK.getInstance().setAccessToken(null);

海外
  1. 第三方服务器通过服务端api接口获取accesstoken和过期时间,accesstoken用来授权,过期时间用来定时刷新accesstoken
  2. 第三方服务器将获取到的accesstoken下发到第三方app(需集中EZOpenSDK),第三方app调用EZGlobalSDK.getInstance().setAccessToken(String accesstoken),来完成授权
  3. 退出登录后需要调用EZGlobalSDK.getInstance().logout(),或者调用EZGlobalSDK.getInstance().setAccessToken(null);

针对需要调用EZOpenSDK登录页登录授权的客户:

国内
  1. 使用 EZOpenSDK.getInstance().openLoginPage()方法跳转到登录H5页,此页面可以登录萤石账号
  2. 登录成功之后会发送广播action为Constant.OAUTH_SUCCESS_ACTION为登录成功,登录成功后,app可以开展自己的业务,以及调用EZOpenSDK的接口,注意登录成功后EZOpenSDK自动完成accesstoken设置授权,第三个app无需再设置accesstoken;
  3. EZOpenSDK会文件缓存accesstoken,下次打开app,初始化时会自动完成授权
  4. 目前针对调用openLoginPage()页面获取accesstoken授权的,EZOpenSDK会内部自动刷新accesstoken,不用担心过期或者失效
  5. 如果需要获取EZOpenSDK内部缓存的accesstoken,调用方法EZOpenSDK.getInstance().getEZAccessToken(),得到EZAccessToken对象,包含accessToken和过去时间,拿accessToken自己去调用萤石api的需要考虑accessToken过期的情况‘’
海外:
  1. 使用 EZGlobalSDK.getInstance().getAreaList()方法获取区域列表,选择当前所在区域areaId通过EZGlobalSDK.getInstance().openLoginPage(String areaId)方法跳转到登录H5页,此页面可以登录萤石账号

  2. 登录成功之后会发送广播action为Constant.OAUTH_SUCCESS_ACTION为登录成功,登录成功后,app可以开展自己的业务,以及调用EZGlobalSDK的接口,注意登录成功后EZGlobalSDK自动完成accesstoken设置授权,第三个app无需再设置accesstoken;

  3. EZGlobalSDK会文件缓存accesstoken,下次打开app,初始化时会自动完成授权

  4. 目前针对H5页面获取accesstoken授权的,EZGlobalSDK会内部自动刷新accesstoken,不用担心过期或者失效

  5. 如果需要获取EZGlobalSDK内部缓存的accesstoken,调用方法EZGlobalSDK.getInstance().getEZAccessToken(),得到EZAccessToken对象,包含accessToken和过去时间,拿accessToken自己去调用萤石api的需要考虑accessToken过期的情况‘’

2. 预览流程

图3

  1. 初始化EZPlayer调用EZOpenSDK的createPlayer,详见api;
  2. 预览播放成功后可以进行以下操作:录像、拍照、画面翻转、对讲、云台控制、声音开关、视频画面缩放、拖动进度播放,详见api的EZPlayer,其中设备控制该接口的如云台控制和镜头显示功能、对讲,属于限制级接口,要优选通过判断设备的能力集来调用,设备能力集请查看EZDeviceInfo对象的属性值来判断具体方法;
  3. 关于对讲功能,如果预览播放有声音输出,则在开启对讲前需要关闭预览播放的声音closeSound,关闭对讲后开启预览播放的声音openSound,详见demo;
  4. EZOpenSDK中的setVideoLevel设置视频清晰度(videoLevel),此调节可以在视频播放前设置也可以在视频播放成功后设置,视频播放成功后设置了清晰度需要先停止播放stopRealPlay然后重新开启播放startRealPlay才能生效;
  5. 开始播放之后在消息回调中会收到a、成功消息:EZRealPlayConstants.MSG_REALPLAY_PLAY_SUCCESS,b、失败消息:EZRealPlayConstants.MSG_REALPLAY_PLAY_FAIL,失败回调时查看errorCode,如果为400035(需要输入验证码)和400036(验证码错误),则需要开发者自己处理让用户重新输入验证密码,并调用setPlayVerifyCode设置密码,然后重新启动播放。

3. 回放流程

图4

  1. 回放播放成功后可以进行以下操作:录像、拍照、声音开关、视频画面缩放、拖动进度seekPlayback播放,具体方法见api的EZPlayer;
  2. getOSDTime获取当前回放时间点,如果回放开始时间8:00,结束时间9:00,getOSDTime时间为8:30,那么播放进度为50%;
  3. 回放播放成功后可以调用pausePlayback(暂停远程回放播放)和 resumePlayback(恢复远程回放播放);
  4. 开始播放之后在消息回调中会收到a、成功消息:MSG_REALPLAY_PLAY_SUCCESS,b、失败消息:MSG_REALPLAY_PLAY_FAIL,失败回调时查看errorCode,如果为ErrorCode.ERROR_INNER_VERIFYCODE_NEED或者ErrorCode.ERROR_INNER_VERIFYCODE_ERROR则为验证密码错误,需要开发者自己处理让用户重新输入验证密码,然后调用setPlayVerifyCode设置密码,然后重新启动播放。

4. 设备添加流程

图5
1.查询设备信息(probeDeviceInfo接口)的所获得对象是EZProbeDeviceInfo,正常查询到设备信息对象说明查询成功,直接可以进行设备添加操作;
2.设备序列号输入正确的情况下报设备不存在的错误是因为全新设备没有注册到平台,直接进行配网流程成功以后就可以查询到设备信息了;
3.probeDeviceInfo主要是根据不同的错误码来处理不同的UI,跟Demo的业务相关性较高;
4.startWifiConfig和stopWifiConfig要成对出现,EZWifiConfigStatus的内容通过回调函数EZOpenSDKListener.EZStartConfigWifiCallback返回的EZConstants.EZWifiConfigStatus 获取的,见快速接入示范和demo。

DEVICE_WIFI_CONNECTED(2),   设备连接WiFi成功
DEVICE_PLATFORM_REGISTED(3);设备注册平台成功

当状态为"PLAT"时方可添加成功。
特别说明: 账户下删除设备重新wifi配置并且添加过程中,请在重置设备等待2分钟以后再调用wifi配置的相关接口可以提高wifi配置的成功率,否则会降低成功率,因为重置设备以后我们平台将在2分钟内得到设备下线的状态,只有平台认为下线了,wifi配置成功率才会高。

注意:DEVICE_WIFI_CONNECTED和DEVICE_PLATFORM_REGISTED状态上报可能会丢失,此时可在适当时机查询设备当前的状态,根据设备状态进行后续操作,详见demo中示例代码。

快速接入示范

本节旨在引导开发者进行快速接入,通过介绍几个关键的接口,并给出对应的界面和接口,以及代码范例,让开发者对sdk有个初步了解.
首先请下载并安装萤石云app, 登陆以后,进入的是监控列表界面,如下所示 图中橙色矩形框仅作为标注,并非原生app界面

1. 获取摄像头列表

APP 我的设备

new Thread(new Runnable() {
    @Override
    public void run() {
        try {
            List<EZDeviceInfo> result = null;

            result = mEZOpenSDK.getDeviceList(0, 10);

            return result;
        } catch (BaseException e) {
            mErrorCode = e.getErrorCode();
            return null;
        }
    }
}).start();

说明
通过调用getDeviceList,可以得到一个列表,列表每一项代表一个设备,每个设备下面又包含多个通道或者探测器。开发者可以通过list adapter将列表展示

代码参考

src\com\videogo\ui\cameralist\EZCameraListActivity.java

2. 添加设备

APP 加设备 APP 二维码扫描

APP 手动输入序列号

说明:
需要添加设备时,可以点击界面1中的加号(+),进入界面2,界面2是一个二维码扫描,用户可以通过扫描二维码获取设备序列号,也可以点击界面右上角的图标(橙色标注),进入界面3,界面3是一个手动输入序列号界面。

界面2(二维码扫描)代码在

src\com\videogo\scan\main\CaptureActivity.java

界面3(手动输入)代码在

src\com\videogo\ui\devicelist\SeriesNumSearchActivity

用户输入设备序列号,只有当设备没有被其他人添加,并且设备已经在线(注册上平台)时,才能够被添加,因此,必须要查询一下该设备状态,调用的接口是probeDeviceInfo

try {
    mEZProbeDeviceInfo = mEZOpenSDK.probeDeviceInfo(deviceSerial);
    sendMessage(MSG_QUERY_CAMERA_SUCCESS);
    LogUtil.infoLog(TAG, "probeDeviceInfo success");
} catch (BaseException e) {
    sendMessage(MSG_QUERY_CAMERA_FAIL, e.getErrorCode());
    LogUtil.infoLog(TAG, " probeDeviceInfo fail :" + e.getErrorCode());
    e.printStackTrace();
}

如果该接口返回成功,则说明该设备状态正常,继续调用addDevice接口添加。

try {
boolean result = mEZOpenSDK.addDevice(deviceSerial, mVerifyCode);
        // 添加成功
        sendMessage(MSG_ADD_CAMERA_SUCCESS);
    } catch (BaseException e) {
        sendMessage(MSG_ADD_CAMERA_FAIL, e.getErrorCode());
        LogUtil.errorLog(TAG, "add camera fail");
}

如果该接口返回错误,开发者需要处理以下几个错误码,告诉用户该设备不可添加的原因:

20020 设备在线,已经被自己添加 (给出提示)

20022 设备在线,已经被别的用户添加 (给出提示)

20023 设备不在线,未被用户添加 (这里需要调用wifi一键配置)

20002 设备不存在,未被用户添加 (这里需要调用wifi一键配置)

20024 设备不在线,已经被别的用户添加 (给出提示)

20029 设备不在线,已经被自己添加 (给出提示)

至此,一个简单的设备添加就完成了。

Wifi一键配置

在上述调用接口probeDeviceInfo过程中,如果返回的错误码是20023或者2002,说明设备还没有联网,这时需要让设备联网,如果是有线设备,需要提示用户插入网线。如果是无线设备,则需要进行wifi配置。

APP configWifi APP configWifi 第一步

APP configWifi 第二步 APP configWifi 第三步 1

APP configWifi 第三步 2 APP configWifi 第三步 3

APP configWifi 第三步 4

开始一键配置需要调用startConfigWifi接口:

new Thread(new Runnable() {

    @Override
    public void run() {
              EzvizApplication.getOpenSDK().startConfigWifi(AutoWifiConnectingActivity.this, serialNo, wifiSSID, wifiPassword, mEZStartConfigWifiCallback);
    }
}).start();

结束一键配置需要调用stopConfigWiFi接口(需要传入一个回调函数,用于处理事件):

    EZOpenSDKListener.EZStartConfigWifiCallback mEZStartConfigWifiCallback = new EZOpenSDKListener.EZStartConfigWifiCallback() {
        @Override
        public void onStartConfigWifiCallback(EZConstants.EZWifiConfigStatus status) {
            if (status == EZConstants.EZWifiConfigStatus.DEVICE_WIFI_CONNECTING) {

            } else if (status == EZConstants.EZWifiConfigStatus.DEVICE_WIFI_CONNECTED) {
                if (isWifiConnected) {
                    LogUtil.i(TAG, "defiveFindHandler: receiver WIFI while isWifiConnected is true");
                    return;
                }
                LogUtil.debugLog(TAG, "接收到设备连接上WIFI  " + serialNo);
                isWifiOkBonjourget = true;
                isWifiConnected = true;
                t2 = System.currentTimeMillis();
                stopWifiConfigOnThread();
                changeStatuss(STATUS_REGISTING);
            } else if (status == EZConstants.EZWifiConfigStatus.DEVICE_PLATFORM_REGISTED) {
                LogUtil.debugLog(TAG, "接收到设备连接上PLAT信息 " + serialNo);
                if (isPlatConnected) {
                    LogUtil.i(TAG, "defiveFindHandler: receiver PLAT while isPlatConnected is true");
                    return;
                }
                isPlatBonjourget = true;
                isPlatConnected = true;
                t3 = System.currentTimeMillis();
                cancelOvertimeTimer();
                changeStatuss(STATUS_ADDING_CAMERA);
            }
        }
    };

该回调用于处理WIFI和PLAT事件。

WIFI表示设备已经连上WIFI, PLAT表示设备已经注册上平台。一旦设备注册上平台之后,就可以调用addDevice进行添加

2. 设备预览

inithhhggggg

预览视频的代码参见src\com\videogo\ui\realplay\EZRealPlayActivity.java

if (mCameraInfo != null) {

   if (mEZPlayer == null) {
                mEZPlayer = EzvizApplication.getOpenSDK().createPlayer(mCameraInfo.getDeviceSerial(), mCameraInfo.getCameraNo());
            }

            if (mEZPlayer == null)
                return;
            if (mDeviceInfo == null) {
                return;
            }
            if (mDeviceInfo.getIsEncrypt() == 1) {
                mEZPlayer.setPlayVerifyCode(DataManager.getInstance().getDeviceSerialVerifyCode(mCameraInfo.getDeviceSerial()));
            }

            mEZPlayer.setHandler(mHandler);
            mEZPlayer.setSurfaceHold(mRealPlaySh);
            mEZPlayer.startRealPlay();
}

代码说明:

1、创建EZPlayer对象需要deviceSerial设备序列号以及cameraNo通道号,即摄像头的唯一标识,deviceSerial与cameraNo可从EZCameraInfo对象中获取

2、需要创建一个handler,用于接收播放器消息,比如播放器播放成功,失败等消息

public boolean handleMessage(Message msg) {
    switch (msg.what) {
        case EZRealPlayConstants.MSG_REALPLAY_PLAY_SUCCESS:
            handlePlaySuccess(msg);
            break;
        case EZRealPlayConstants.MSG_REALPLAY_PLAY_FAIL:
            handlePlayFail(msg.arg1, msg.arg2);
            break;
}

3、播放需要一个surfaceView,因此在你的xml layout 文件重要放置一个SurfaceView

<RelativeLayout
    android:id="@+id/realplay_play_rl"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:background="@color/black_bg" >

    <SurfaceView
       android:id="@+id/realplay_sv"
       android:layout_width="600dp"
       android:layout_height="200dp"
       android:layout_alignParentTop="true"
       android:layout_centerInParent="false"
       android:background="@android:color/transparent" />
</RelativeLayout>

在surface创建的过程中,保存SurfaceHolder对象:

@Override
public void surfaceCreated(SurfaceHolder holder) {
    if (mEZPlayer != null) {
        mEZPlayer.setSurfaceHold(holder);
    }
    mRealPlaySh = holder;
}

4、调用startRealPlay()

整个代码参见src\com\videogo\ui\realplay\EZRealPlayActivity.java