Android SDK 文档
1. 中英听写_开放平台能力简介(能力id:ee62fa27c)
#2.授权说明
#3. 兼容机型
类别 | 兼容范围 |
---|---|
系统 | 支持Android 5.0 ~ Android 13 版本,鸿蒙系统未做系统兼容性验证 |
机型 | 上市的Android手机和平板、及符合具体能力性能要求的Android系统扫描笔、手表等设备 |
网络 | 对网络无要求,设备具备联网条件,可使用在线激活方式,首次使用需要连接网络。若设备不能联网,需要使用离线激活方式 |
开发环境 | 建议使用 Android Studio 进行开发 |
#4. SDK包组成
#5. 接口调用流程

#6. 快速集成指南
#6.1 导入SDK库
dependencies {
// 已忽略无关代码
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation files('libs/AIKit.aar')
}
#6.2 配置权限
权限 | 使用说明 |
---|---|
INTERNET | SDK需要访问网络获取、更新授权 |
READ_PHONE_STATE | 获取设备IMEI用于精准授权,IMEI加密存储,不会存储明文 |
WRITE_EXTERNAL_STORAGE | SDK写本地日志需要用到该权限 |
READ_EXTERNAL_STORAGE | SDK加载本地模型资源文件需要该权限 |
MOUNT_UNMOUNT_FILESYSTEMS | Android 11以上需要该权限 |
READ_PRIVILEGED_PHONE_STATE | Android 10 以后新增权限,同 READ_PHONE_STATE |
MANAGE_EXTERNAL_STORAGE | 获取所有文件的访问权限(Android 11以上需要该权限) |
READ_PHONE_NUMBERS | 获取设备IMEI用于精准授权,IMEI加密存储,不会存储明文(Android 11及以上获取) |
<!-- 移除SDK非必须权限示例 -->
<uses-permission android:name="android.permission.READ_PHONE_STATE" tools:node="remove" />
<uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" tools:node="remove" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_PHONE_NUMBERS" />
<application android:requestLegacyExternalStorage="true"/>
#6.3 资源导入
#6.4 SDK初始化
// 初始化参数构建
AiHelper.Params params = AiHelper.Params.builder()
.appId(appID)
.apiKey(apiKey)
.apiSecret(apiSecret)
.ability("ee62fa27c")
.workDir("/sdcard/iflytek/aikit")//SDK工作路径,这里为绝对路径,此处仅为示例
.build();
// 初始化
AiHelper.getInst().init(this, params);
参数 | 类型 | 必填 | 说明 |
---|---|---|---|
appID | String | 是 | 应用ID |
apiKey | String | 是 | 离线引擎托管平台创建应用后,生成的唯一应用标识 |
apiSecret | String | 是 | 离线引擎托管平台创建应用后,生成的唯一应用秘钥 |
workDir | String | 是 | SDK工作目录。默认读取能力资源、写SDK日志在此路径下 |
licenseFile | String | 否 | (购买装机量达到10000台后,可以通过工单申请离线激活license文件)离线授权license文件绝对路径,SDK离线激活方式,需要从离线引擎托管平台申请的离线授 权license文件,放入设备指定路径中(可放入至SDK工作路径下),即licenseFile参数即为离线激活文件的绝对工作路径。 |
customDeviceId | String | 否 | 用户自定义设备指纹块,默认为空,设置后会成为设备指纹的一部分,建议设置长度低于256 |
authType | int | 否 | 离线授权类型(0或1),0-->(默认)设备级授权(DEVICE)和 1-->应用级授权(APP) |
authInterval | int | 否 | 在线授权校验间隔时长,默认为300s,可自定义设置,最短为60s,单位秒 |
resDir | String | 否 | 指定资源读取路径,不设置默认从workDir读取 |
ability | String | 是 | SDK v2.2.13+版本新增接口,传入需要用到的一个或多个能力ID,格式为"xxxx1;xxxx2",多个能力ID中间用 英文分号 隔开,如果注册的能力非空,SDK将对传入的能力ID授权; |
#6.5 注册监听代理
AiHelper.getInst().registerListener(coreListener);// 注册SDK 初始化状态监听 AiHelper.getInst().registerListener("ee62fa27c", aiRespListener);// 注册能力结果监听
#6.5.1 授权状态回调
private AuthListener coreListener = new AuthListener() {
@Override
public void onAuthStateChange(final ErrType type, final int code) {
Log.i(TAG, "core listener code:" + code);
switch (type) {
case AUTH:
Log.i(TAG,"SDK状态:授权结果码" + code);
break;
case HTTP:
Log.i(TAG,"SDK状态:HTTP认证结果" + code);
break;
default:
Log.i(TAG,"SDK状态:其他错误");
}
}
};
参数 | 类型 | 说明 |
---|---|---|
type | ErrType | SDK错误类型,0 表示授权错误,1 表示 http 请求错误 |
code | int | 错误码,0 表示正常 |
#6.5.2 能力计算进度、结果回调
/**
* 能力监听回调
*/
private AiListener aiRespListener = new AiListener() {
@Override
public void onResult(int handleID, List<AiResponse> outputData, Object usrContext) {
if (null != outputData && outputData.size() > 0) {
for (int i = 0; i < outputData.size(); i++) {
byte[] bytes = outputData.get(i).getValue();
if (bytes == null) {
continue;
}
String key = outputData.get(i).getKey();
//获取到结果的key及value,可根据业务保存存储结果或其他处理
}
}
}
@Override
public void onEvent(int handleID, int event, List<AiResponse> eventData, Object usrContext);
}
@Override
public void onError(int handleID, int err, String msg, Object usrContext);
}
};
参数 | 类型 | 说明 |
---|---|---|
handleID | int | 会话ID |
outputData | List | 能力执行结果 |
usrContext | Object | 用户自定义标识 |
参数 | 类型 | 说明 |
---|---|---|
handleID | int | 会话ID |
event | int | 事件状态,0:未知错误;1:开始;2:结束;3:超时;4:进行中 |
eventData | List | 事件消息数据 |
usrContext | Object | 用户自定义标识 |
参数 | 类型 | 说明 |
---|---|---|
handleID | int | 会话ID |
err | int | 错误码 |
msg | String | 错误相关标识 |
usrContext | Object | 用户自定义标识 |
参数 | 类 型 | 说明 |
---|---|---|
key | String | 输出数据名称 |
type | enum | 输出数据类型,1=文本 |
value | byte[] | 字节数组类型输出数据 |
varType | enum | 输出数据参数类型,0=字节数组 |
len | int | 输出数据长度 |
#6.6 个性化数据接口
int ret = 0;
AiRequest.Builder customBuilder = AiRequest.builder();
/**
* key 数据标识
* value 数据内容
* index 数据索引,用户可自定义设置
*/
customBuilder.customText("PPROC_NOT_REP", "/sdcard/iflytek/edcnen/num_not_change_list", 0);
customBuilder.customText("PPROC_REPLACE", "/sdcard/iflytek/edcnen/replace_list", 1);
ret = AiHelper.getInst().loadData("ee62fa27c", customBuilder.build());
if (ret != 0) {
Log.e(TAG, "loadData 失败:" + ret);
}
//指定要使用的个性化数据集合,未调用,则默认使用所有loadData加载的数据
int[] indexs0 = {0};
int[] indexs1 = {1};
/**
* indexs 个性化数据索引数组
*/
AiHelper.getInst().specifyDataSet("ee62fa27c", "PPROC_NOT_REP", indexs0);
AiHelper.getInst().specifyDataSet("ee62fa27c", "PPROC_REPLACE", indexs1);
if (ret != 0) {
Log.e(TAG, "specifyDataSet 失败:" + ret);
}
功能 | 个性化数据Key | 类型 | 试用场景 |
---|---|---|---|
热词 | PERSONAL | 文本配置文件 | 识别过程中相同发音会被识别为热词 (热词的设置只能是汉字,阿拉伯数字需要用汉字设置) |
替换列表 | PPROC_REPLACE | 文本配置文件 | 识别出结果后,后处理阶段可将替换列表中词自定义替换 |
不替换列表 | PPROC_NOT_REP | 文本配置文件 | 开启数字规整功能时,汉字数字会被识别为阿拉伯数字,对于不想转换的数字,可通过不替换列表配置实现 |
参数 | 类型 | 必填 | 说明 |
---|---|---|---|
abilityId | String | 是 | 能力标识ID |
request | AiRequest | 是 | 个性化数据构造器 |
参数 | 类型 | 必填 | 说明 |
---|---|---|---|
abilityId | String | 是 | 能力标识ID |
key | String | 是 | 个性化资源key |
indexs | AiRequest | 是 | 个性化资源索引 |
参数 | 类型 | 必填 | 说明 |
---|---|---|---|
abilityId | String | 是 | 能力标识ID |
request | AiRequest | 是 | 个性化资源key |
#6.7 能力调用接口
#6.7.1 创建会话start
AiRequest.Builder paramBuilder = AiRequest.builder();
//paramBuilder.param("lmLoad", false);
//paramBuilder.param("vadLoad", false);
//paramBuilder.param("lmOn", false);
//paramBuilder.param("numLoad", false);
//paramBuilder.param("puncLoad", false);
//paramBuilder.param("vadLinkOn", false);
//paramBuilder.param("vadOn", false);
//paramBuilder.param("postprocOn", false);
//paramBuilder.param("vadResponsetime", 6000);
//paramBuilder.param("vadSpeechEnd", 200);
//paramBuilder.param("dialectType", 0);
//paramBuilder.param("htkNeed", true);
//paramBuilder.param("readableNeed", true);
//paramBuilder.param("pgsNeed", true);
//paramBuilder.param("plainNeed", true);
//paramBuilder.param("vadNeed", true);
AiHandle handle = AiHelper.getInst().start("ee62fa27c",paramBuilder.build(),null);
if (!handle.isSuccess()) {
Log.e(TAG, "ERROR::START | handle code:" + handle.getCode());
return;
}
功能标识 | 功能描述 | 数据类型 | 取值范围 | 必填 | 默认值 |
---|---|---|---|---|---|
lmLoad | 加载二遍资源 | bool | true:加载, false:不加载 | 否 | false |
vadLoad | 加载VAD资源 | bool | true:加载, false:不加载 | 否 | false |
lmOn | 开启二遍 | bool | true:开启, false:不开启 | 否 | false |
numLoad | 加载数字规整资源 | bool | true:加载, false:不加载 | 否 | false |
puncLoad | 加载标点资源 | bool | true:加载, false:不加载 | 否 | false |
vadLinkOn | vad子句连接 | bool | true:开启, false:不开启 | 否 | false |
vadOn | 是否开启vad功能 | bool | true:开启, false:不开启 | 否 | false |
postprocOn | 是否开启后处理 | bool | true:开启, false:不开启 | 否 | false |
vadResponsetime | vad强行结束时间 | int | 最小值:0, 最大值:999999 | 否 | 6000 |
vadSpeechEnd | vad结束参数 | int | 最小值:0, 最大值:999999 | 否 | 200 |
htkNeed | 是否输出htk结果 | bool | true:输出, false:不输出 | 否 | true |
readableNeed | 是否输出readable结果 | bool | true:输出, false:不输出 | 否 | true |
pgsNeed | 是否输出pgs结果 | bool | true:输出, false:不输出 | 否 | true |
plainNeed | 是否输出plain结果 | bool | true:输出, false:不输出 | 否 | true |
vadNeed | 是否输出vad结果 | bool | true:输出, false:不输出 | 否 | true |
参数 | 类型 | 必填 | 说明 |
---|---|---|---|
key | String | 是 | 功能参数名称 |
value | String/int/double/bool | 是 | 功能参数取值 |
参数 | 类型 | 必填 | 说明 |
---|---|---|---|
ability | String | 是 | 能力标识ID |
request | AiRequest | 是 | 能力参数,可使用AiRequest.Builder快捷构建 |
usrContext | Object | 否 | 用户自定义标识 |
0=成功,其他=错误
#6.7.2 写入数据
参数 | 类型 | 必填 | 说明 |
---|---|---|---|
input | AiRequest | 是 | 能力输入,可使用AiRequest.Builder快捷构建 |
handle | AiHandle | 是 | 会话的handle对象 |
AiRequest.Builder dataBuilder = AiRequest.builder();
//输入音频数据
AiAudio.Holder PCMData = AiAudio
.get("PCM") //输入数据key
.encoding(AiAudio.ENCODING_DEFAULT) //设置音频类型
.data(part);//part为 byte[]类型输入数据
PCMData.status(AiStatus.BEGIN); //送入数据的状态,首帧数据、尾帧数据、中间数据,根据送入数据的状态传入对应的值,取值对应AiStatus.BEGIN、AiStatus.END、AiStatus.CONTINUE
dataBuilder.payload(PCMData.valid());
int ret = AiHelper.getInst().write(dataBuilder.build(), aiHandle);
//ret 值为0 写入成功;非0失败,请参照文档中错误码部分排查
if (ret != 0) {
String error = "start write failed" + ret;
Log.e(TAG, error);
}
字段 | 含义 | 数据类型 | 取值范围 | 默认值 | 说明 | 必填 |
---|---|---|---|---|---|---|
encoding | 音频编码 | string | pcm | pcm | 取值范围可枚举 | 否 |
sample_rate | 采样率 | int | 16000 | 16000 | 音频采样率,可枚举 | 否 |
channels | 声道数 | int | 1 | 1 | 声道数,可枚举 | 否 |
bit_depth | 位深 | int | 16 | 16 | 单位bit,可枚举 | 否 |
data | 音频数据 | string | 音频大小:0-10M | 否 | ||
frame_size | 帧大小 | int | 最小值:320, 最大值:1024 | 320 | 帧大小,默认320 | 否 |
#6.7.3 获取能力输出结果
try{
int ret = AiHelper.getInst().read("ee62fa27c", aiHandle);
if (ret != 0) {
String error = "start write failed" + ret;
Log.e(TAG, error);
}
}
} catch (Exception e) {
e.printStackTrace();
}
参数 | 类型 | 必填 | 说明 |
---|---|---|---|
ability | String | 是 | 能力标识ID |
handle | AiHandle | 是 | 会话的handle对象 |
字段 | 含义 | 数据类型 | 取值范围 | 默认值 | 说明 | 必填 |
---|---|---|---|---|---|---|
encoding | 文本编码 | string | utf8, gb2312 | utf8 | 取值范围可枚举 | 否 |
compress | 文本压缩格式 | string | raw, gzip | raw | 取值范围可枚举 | 否 |
format | 文本格式 | string | plain, json, xml | json | 取值 范围可枚举 | 否 |
data | 文本数据 | string | 文本大小:0-1M | 否 |
plain: {"sc":"0","ws":[{"sc":"0.000","w":"各","label":"","pinyin":"","boundary":"0-0"},{"sc":"0.000","w":"族","label":"","pinyin":"","boundary":"0-0"},{"sc":"0.000","w":"人","label":"","pinyin":"","boundary":"0-0"},{"sc":"0.000","w":"民","label":"","pinyin":"","boundary":"0-0"},{"sc":"0.000","w":"亲","label":"","pinyin":"","boundary":"0-0"},{"sc":"0.000","w":"如","label":"","pinyin":"","boundary":"0-0"},{"sc":"0.000","w":"一","label":"","pinyin":"","boundary":"0-0"},{"sc":"0.000","w":"家","label":"","pinyin":"","boundary":"0-0"},{"sc":"0.000","w":"是","label":"","pinyin":"","boundary":"0-0"},{"sc":"0.000","w":"中","label":"","pinyin":"","boundary":"0-0"},{"sc":"0.000","w":"华","label":"","pinyin":"","boundary":"0-0"},{"sc":"0.000","w":"民","label":"","pinyin":"","boundary":"0-0"},{"sc":"0.000","w":"族","label":"","pinyin":"","boundary":"0-0"},{"sc":"0.000","w":"伟","label":"","pinyin":"","boundary":"0-0"},{"sc":"0.000","w":"大","label":"","pinyin":"","boundary":"0-0"},{"sc":"0.000","w":"复","label":"","pinyin":"","boundary":"0-0"},{"sc":"0.000","w":"兴","label":"","pinyin":"","boundary":"0-0"},{"sc":"0.000","w":"必","label":"","pinyin":"","boundary":"0-0"},{"sc":"0.000","w":"定","label":"","pinyin":"","boundary":"0-0"},{"sc":"0.000","w":"要","label":"","pinyin":"","boundary":"0-0"},{"sc":"0.000","w":"实","label":"","pinyin":"","boundary":"0-0"},{"sc":"0.000","w":"现","label":"","pinyin":"","boundary":"0-0"},{"sc":"0.000","w":"的","label":"","pinyin":"","boundary":"0-0"},{"sc":"0.000","w":"根","label":"","pinyin":"","boundary":"0-0"},{"sc":"0.000","w":"本","label":"","pinyin":"","boundary":"0-0"},{"sc":"0.000","w":"保","label":"","pinyin":"","boundary":"0-0"},{"sc":"0.000","w":"证","label":"","pinyin":"","boundary":"0-0"}]}
结果json参数 | 字段含义 |
---|---|
sc | 置信度 |
w | 识别结果 |
label | 后处理标签 |
pinyin | 拼音 |
boundary | 边界词 |
#6.7.4 结束会话
int ret = AiHelper.getInst().end(aiHandle);
if (ret != 0) {
String error = "end failed" + ret;
Log.e(TAG, error);
}
参数 | 类型 | 必填 | 说明 |
---|---|---|---|
handle | AiHandle | 是 | 会话的handle对象 |
#6.8 SDK逆初始化
AiHelper.getInst().unInit();
#6.9 导入资源验证
#7. 高级功能
#7.1 日志配置
AiHelper.getInst().setLogInfo(LogLvl.DEBUG, 1, "/sdcard/iflytek/aikit");
参数 | 类型 | 说明 |
---|---|---|
LogLvl | enum | 日志级别枚举值如下: DEBUG, INFO, WARN, ERROR, FATAL, OFF |
LogMode | int | 日志模式(stadout:0 logcat:1 file:2) |
LogPath | String | 日志路径(路径可根据实际需求进行修改) |
#7.2 参数配置
AiHelper.getInst().setConfig("licenseStoragePath","/sdcard/iflytek/aikit");
参数 | 类型 | 说明 |
---|---|---|
licenseStoragePath | String | 授权文件存储路径,Android平台默认保存在 SharePreference下,可通过该配置设置保存在其他路径下。 |
logMaxSize | String | 日志文件上限 |
#7.3 个性化数据卸载
int[] indexs0 = {0};
int[] indexs1 = {1};
AiHelper.getInst().unLoadData("ee62fa27c", "PPROC_NOT_REP", index0);
AiHelper.getInst().unLoadData("ee62fa27c", "PPROC_REPLACE", index1);
参数 | 类型 | 说明 |
---|---|---|
ability | String | 能力id |
key_word | String | 个性化数据唯一标识 |
index | String | 个性化数据索引 |
功能 | 个性化数据Key | 类型 | 试用场景 |
---|---|---|---|
热词 | PERSONAL | 文本配置文件 | 识别过程中相同发音会被识别为热词(热词的设置只能是汉字,阿拉伯数字需要用汉字设置) |
替换列表 | PPROC_REPLACE | 文本配置文件 | 识别出结果后,后处理阶段可将替换列表中词自定义替换 |
不替换列表 | PPROC_NOT_REP | 文本配置文件 | 开启数字规整功能时,汉字数字会被识别为阿拉伯数字,对于不想转换的数字,可通过不替换列表配置实现 |
#7.4 资源从asset读取
#8. Android平台常见问题
1.
appid 未授权该SDK 能力,请申请授权后使用该能力。
1.
appid、apiKey、apiSecret 配置有误,请检查配置。
1.
apiKey 或 apiSecret 有误,请检查apiKey、apiSecret 的值是否正确,并替换为正确的值。
1.
appid 不存在或appid 未授权,请使用正确的 appid。
1.
SDK 初始化时设置的SDK工作路径即“workDir” 无读写权限,请确保SDK 初始化时,SDK工作路径具有读写权限。
1.
Caused by: java.security.InvalidParameterException
at com.iflytek.edgeAI.core.JLibrary$Params$Builder.build(Unknown Source:``41``)
at com.iflytek.aeesdkdemo.sdk.SDKHelper.initSdk(SDKHelper.java:``55``)``
at com.iflytek.aeesdkdemo.xtts.XTTSActivity.initSDK(XXXXActivity.java:``144``)
at com.iflytek.aeesdkdemo.xtts.XTTSActivity.onCreate(XXXXActivity.java:``81``)
at android.app.Activity.performCreate(Activity.java:``8214``)
崩溃原因为 appid、apiKey、apiSecret 存在为空的值,请正确配置 appid、apiKey、apiSecret。
1.
能力(能力id为 xxxxxx)不存在,初始化引擎时传入的能力id有误,请检查能力id是否正确;或改能力未授权,请确认该能力是否已申请授权。
1.
该错误为资源未找到,请检查是否将资源导入到了SDK的工作路径下。
1.
流式接口能力,调用 AEE_Start 或 start 方法开始的会话,未调用AEE_End 或 end 方法打断或正常结束,再次调用AEE_Srart则SDK会返回18310错误,同一个能力SDK不支持并发调用,需要结束本次会话之后,才能开始下一次会话。
1.
请检查确认引擎初始化及调用能力时所传能力id参数是否正确;如果能力ID无误,SDK日志中打印的 xxxxxx 能力未授权。
1.
应用安全等级与设备指纹不符,须申请调整appid 安全等级;
#错误码
错误码 | 含义 | 自查指南 |
---|---|---|
18000 | 本地 license 文件不存在 | 离线激活方式,请检查离线授权文件路径下,license 文件是否存在;如果不存在,请将申请的离线授权文件放置在对应路径下; 在线激活方式下,请检查 workDir 目录下 license 文件是否存在,如果不存在,请将设备联网,重启应用。 |
18001/18002 /18003/18004 | 授权问题 | Linux 平台删除授权文件,将设备联网,重启应用,重新从云端获取授权文件; Android 端清除应用缓存,将设备联网,重启应用,重新从云端获取授权文件; 如仍有问题,请联系项目经理协助解决。 |
18005 | 授权已过期 | 能力授权已过期。 |
18006 | 授权时间错误,设备时间比标准时间慢 30 分钟以上 | 设备时间不准确导致,请校正设备时间为标准时间,重启应用。 |
18007 |