【Android】灵云手写离线识别使用说明
生活随笔
收集整理的這篇文章主要介紹了
【Android】灵云手写离线识别使用说明
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
注冊
使用靈云的手寫識別功能需要先在官網(wǎng)上進(jìn)行注冊應(yīng)用。官網(wǎng)地址
注冊比較簡單,就不做過多介紹了,注冊完應(yīng)用以后,在后臺創(chuàng)建自己的應(yīng)用,創(chuàng)建完應(yīng)用以后需要給應(yīng)用開通對應(yīng)的手寫功能。
capKey說明:
- hwr.cloud.letter 云端單字識別功能
- hwr.cloud.freewrite 云端多字識別功能
- hwr.local.letter 本地單字識別功能
- hwr.local.freestylus 本地多字識別功能
- hwr.local.associateword 本地聯(lián)想詞功能
集成
下載靈云的Android版本手寫識別功能,下載地址
如果使用在線功能,下載對應(yīng)的SDK,里面有jar包和so,就可以滿足需求了。如果要使用離線的手寫識別功能,還需要下載靈云資源文件
資源文件列表:
如果是在android平臺上使用,需要修改一下名字,修改為如下,并加入到libs/armeabi目錄下
源碼
Github
靈云離線手寫識別功能
需要加入的so和jar包有:
- libhci_curl.so
- libhci_sys.so
- libhci_sys_jni.so
- libhci_hwr.so
- libhci_hwr_hwr_jni.so
- libhci_hwr_local_recog.so
- libletter.conf.so
- libletter.dic.so
需要使用的權(quán)限
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />加載配置類
package com.miao.util;/*** 靈云配置信息* Created by 10048 on 2016/12/3.*/ public class ConfigUtil {/*** 靈云APP_KEY*/public static final String APP_KEY = "c85d54f1";/*** 開發(fā)者密鑰*/public static final String DEVELOPER_KEY = "712ddd892cf9163e6383aa169e0454e3";/*** 靈云云服務(wù)的接口地址*/public static final String CLOUD_URL = "test.api.hcicloud.com:8888";/*** 需要運(yùn)行的靈云能力*///云端多字識別功能public static final String CAP_KEY_HWR_CLOUD_FREETALK = "hwr.cloud.freetalk";//云端單字識別功能public static final String CAP_KEY_HWR_CLOUD_LETTER = "hwr.cloud.letter";//離線單字識別功能public static final String CAP_KEY_HWR_LOCAL_LETTER = "hwr.local.letter";//離線多字識別功能public static final String CAP_KEY_HWR_LOCAL_FREESTYLUS = "hwr.local.freestylus";//離線聯(lián)想功能public static final String CAP_KEY_HWR_LOCAL_ASSOCIATE_WORD = "hwr.local.associateword";//離線筆形功能public static final String CAP_KEY_HWR_LOCAL_PENSCRIPT = "hwr.local.penscript"; }封裝靈云系統(tǒng)的初始化功能
package com.example.sinovoice.util;import android.content.Context; import android.os.Environment; import android.util.Log;import com.sinovoice.hcicloudsdk.api.HciCloudSys; import com.sinovoice.hcicloudsdk.common.AuthExpireTime; import com.sinovoice.hcicloudsdk.common.HciErrorCode; import com.sinovoice.hcicloudsdk.common.InitParam;import java.io.File; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale;/*** Created by miaochangchun on 2016/11/28.*/ public class HciCloudSysHelper {private static final String TAG = HciCloudSysHelper.class.getSimpleName();private static HciCloudSysHelper mHciCloudSysHelper = null;private HciCloudSysHelper(){}public static HciCloudSysHelper getInstance() {if (mHciCloudSysHelper == null) {return new HciCloudSysHelper();}return mHciCloudSysHelper;}/*** 初始化函數(shù)* @param context* @return*/public int init(Context context){//配置串參數(shù)String strConfig = getInitParam(context);int errCode = HciCloudSys.hciInit(strConfig, context);if (errCode != HciErrorCode.HCI_ERR_NONE){Log.e(TAG, "hciInit Failed and return errcode = " + errCode);return errCode;}errCode = checkAuthAndUpdateAuth();if (errCode != HciErrorCode.HCI_ERR_NONE) {Log.e(TAG, "checkAuthAndUpdateAuth Failed and return errcode = " + errCode);return errCode;}return HciErrorCode.HCI_ERR_NONE;}/*** 獲取授權(quán)* @return*/private int checkAuthAndUpdateAuth() {// 獲取系統(tǒng)授權(quán)到期時間AuthExpireTime objExpireTime = new AuthExpireTime();int initResult = HciCloudSys.hciGetAuthExpireTime(objExpireTime);if (initResult == HciErrorCode.HCI_ERR_NONE) {// 顯示授權(quán)日期,如用戶不需要關(guān)注該值,此處代碼可忽略Date date = new Date(objExpireTime.getExpireTime() * 1000);SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd", Locale.CHINA);Log.i(TAG, "expire time: " + sdf.format(date));if (objExpireTime.getExpireTime() * 1000 > System.currentTimeMillis()) {// 已經(jīng)成功獲取了授權(quán),并且距離授權(quán)到期有充足的時間(>7天)Log.i(TAG, "checkAuth success");return initResult;}}// 獲取過期時間失敗或者已經(jīng)過期initResult = HciCloudSys.hciCheckAuth();if (initResult == HciErrorCode.HCI_ERR_NONE) {Log.i(TAG, "checkAuth success");return initResult;} else {Log.e(TAG, "checkAuth failed: " + initResult);return initResult;}}/*** 獲取配置傳參數(shù)* @param context* @return*/private String getInitParam(Context context) {InitParam initParam = new InitParam();//靈云云服務(wù)的接口地址,此項必填initParam.addParam(InitParam.AuthParam.PARAM_KEY_APP_KEY, ConfigUtil.APP_KEY);//靈云云服務(wù)的接口地址,此項必填initParam.addParam(InitParam.AuthParam.PARAM_KEY_DEVELOPER_KEY, ConfigUtil.DEVELOPER_KEY);//靈云云服務(wù)的接口地址,此項必填initParam.addParam(InitParam.AuthParam.PARAM_KEY_CLOUD_URL, ConfigUtil.CLOUD_URL);String authPath = context.getFilesDir().getAbsolutePath();//授權(quán)文件所在路徑,此項必填initParam.addParam(InitParam.AuthParam.PARAM_KEY_AUTH_PATH, authPath);//日志數(shù)目,默認(rèn)保留多少個日志文件,超過則覆蓋最舊的日志initParam.addParam(InitParam.LogParam.PARAM_KEY_LOG_FILE_COUNT, "5");String logPath = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator+ "sinovoice" + File.separator+ context.getPackageName() + File.separator+ "log" + File.separator;File file = new File(logPath);if (!file.exists()) {file.mkdirs();}//日志的路徑,可選,如果不傳或者為空則不生成日志initParam.addParam(InitParam.LogParam.PARAM_KEY_LOG_FILE_PATH, logPath);Log.d(TAG, "logPath = " + logPath);//日志大小,默認(rèn)一個日志文件寫多大,單位為KinitParam.addParam(InitParam.LogParam.PARAM_KEY_LOG_FILE_SIZE, "1024");//日志等級,0=無,1=錯誤,2=警告,3=信息,4=細(xì)節(jié),5=調(diào)試,SDK將輸出小于等于logLevel的日志信息initParam.addParam(InitParam.LogParam.PARAM_KEY_LOG_LEVEL, "5");return initParam.getStringConfig();}/*** 反初始化* @return*/public int release(){return HciCloudSys.hciRelease();} }封裝靈云手寫識別功能
package com.miao.util;import android.content.Context; import android.util.Log;import com.sinovoice.hcicloudsdk.api.hwr.HciCloudHwr; import com.sinovoice.hcicloudsdk.common.HciErrorCode; import com.sinovoice.hcicloudsdk.common.Session; import com.sinovoice.hcicloudsdk.common.hwr.HwrAssociateWordsResult; import com.sinovoice.hcicloudsdk.common.hwr.HwrConfig; import com.sinovoice.hcicloudsdk.common.hwr.HwrInitParam; import com.sinovoice.hcicloudsdk.common.hwr.HwrRecogResult; import com.sinovoice.hcicloudsdk.common.hwr.HwrRecogResultItem;import java.util.ArrayList; import java.util.Iterator; import java.util.List;/*** Created by miaochangchun on 2016/11/1.*/ public class HciCloudHwrHelper {public static final String TAG = HciCloudHwrHelper.class.getSimpleName();private static HciCloudHwrHelper mHciCloudHwrHelper = null;private HciCloudHwrHelper(){}public static HciCloudHwrHelper getInstance(){if (mHciCloudHwrHelper == null) {return new HciCloudHwrHelper();}return mHciCloudHwrHelper;}/*** 手寫功能初始化* @param context 上下文* @param capkey 使用的capkey,手寫單字識別為hwr.local.letter,多字識別為hwr.local.freestylus,聯(lián)想功能為hwr.local.associateword* @return 返回0為成功,其他為失敗*/public int initHwr(Context context, String capkey){String strConfig = getHwrInitParam(context, capkey);Log.d(TAG, "strConfig = " + strConfig);int errorCode = HciCloudHwr.hciHwrInit(strConfig);return errorCode;}/*** 手寫識別函數(shù)* @param data 筆跡坐標(biāo)* @param capkey 使用的capkey,手寫單字識別為hwr.local.letter,多字識別為hwr.local.freestylus,聯(lián)想功能為hwr.local.associateword* @return 返回識別的結(jié)果*/public String recog(short[] data, String capkey){Session session = new Session();String sessionConfig = getHwrSessionParam(capkey);Log.d(TAG, "sessionConfig = " + sessionConfig);//sessionStart開啟一個sessionint errorCode = HciCloudHwr.hciHwrSessionStart(sessionConfig, session);if (errorCode != HciErrorCode.HCI_ERR_NONE) {Log.e(TAG, "hciHwrSessionStart failed and return " + errorCode);HciCloudHwr.hciHwrSessionStop(session);return null;}//識別結(jié)果類進(jìn)行初始化HwrRecogResult recogResult = new HwrRecogResult();//識別的配置串參數(shù)可以設(shè)置為空,默認(rèn)就使用sessionConfig配置串參數(shù)errorCode = HciCloudHwr.hciHwrRecog(session, data, "", recogResult);if (errorCode != HciErrorCode.HCI_ERR_NONE) {Log.e(TAG, "hciHwrRecog failed and return " + errorCode);return null;}//關(guān)閉SessionerrorCode = HciCloudHwr.hciHwrSessionStop(session);if (errorCode != HciErrorCode.HCI_ERR_NONE) {Log.e(TAG, "hciHwrSessionStop failed and return " + errorCode);return null;}//返回識別結(jié)果StringBuilder sb = new StringBuilder();List<HwrRecogResultItem> lists = recogResult.getResultItemList();Iterator<HwrRecogResultItem> iterator = lists.iterator();while (iterator.hasNext()) {HwrRecogResultItem item = iterator.next();sb.append(item.getResult()).append(" , ");}return sb.toString(); // return recogResult.getResultItemList().get(0).getResult();}/*** 聯(lián)想詞功能,對str進(jìn)行聯(lián)想,返回聯(lián)想結(jié)果* @param str 需要聯(lián)想的字符串* @param assCapkey 聯(lián)想功能對應(yīng)的capkey。* @return*/public String associateWord(String str, String assCapkey){Session session = new Session();String sessionConfig = getAssociateWordSessionParam(assCapkey);int errorCode = HciCloudHwr.hciHwrSessionStart(sessionConfig, session);if (errorCode != HciErrorCode.HCI_ERR_NONE) {Log.e(TAG, "HciCloudHwr.hciHwrSessionStart failed and return " + errorCode);}HwrAssociateWordsResult hwrAssociateWordsResult = new HwrAssociateWordsResult();errorCode = HciCloudHwr.hciHwrAssociateWords(session, str, "", hwrAssociateWordsResult);if (errorCode != HciErrorCode.HCI_ERR_NONE) {Log.e(TAG, "HciCloudHwr.hciHwrAssociateWords failed and return " + errorCode);}errorCode = HciCloudHwr.hciHwrSessionStop(session);if (errorCode != HciErrorCode.HCI_ERR_NONE) {Log.e(TAG, "HciCloudHwr.hciHwrSessionStop failed and return " + errorCode);}ArrayList<String> lists = hwrAssociateWordsResult.getResultList();StringBuilder sb = new StringBuilder();Iterator<String> iterator = lists.iterator();while (iterator.hasNext()) {String string = iterator.next();sb.append(string).append(",");}return sb.toString();}/*** 設(shè)置聯(lián)想詞的配置參數(shù)* @param assCapkey 聯(lián)想詞功能所需的capkey,需要設(shè)置為 assCapkey=hwr.local.associateword* @return 聯(lián)想詞配置的字符串*/private String getAssociateWordSessionParam(String assCapkey) {HwrConfig hwrConfig = new HwrConfig();hwrConfig.addParam(HwrConfig.SessionConfig.PARAM_KEY_CAP_KEY, assCapkey);return hwrConfig.getStringConfig();}/*** 獲取手寫識別的配置參數(shù)* @param hwrCapkey 使用的capkey,手寫單字識別為hwr.local.letter,多字識別為hwr.local.freestylus* @return 返回配置串*/private String getHwrSessionParam(String hwrCapkey) {HwrConfig hwrConfig = new HwrConfig();hwrConfig.addParam(HwrConfig.SessionConfig.PARAM_KEY_CAP_KEY, hwrCapkey);//設(shè)置識別結(jié)果的候選個數(shù)hwrConfig.addParam(HwrConfig.ResultConfig.PARAM_KEY_CAND_NUM, "10");//設(shè)置識別結(jié)果的范圍hwrConfig.addParam(HwrConfig.ResultConfig.PARAM_KEY_RECOG_RANGE, "gbk");return hwrConfig.getStringConfig();}/*** 獲取手寫的初始化配置參數(shù)* @param context 上下文* @param initCapkeys 使用的capkey,手寫單字識別為hwr.local.letter,* 多字識別為hwr.local.freestylus,* 聯(lián)想功能為hwr.local.associateword* 可以設(shè)置多個,中間以分號隔開* @return 返回配置串*/private String getHwrInitParam(Context context, String initCapkeys) {HwrInitParam hwrInitParam = new HwrInitParam();hwrInitParam.addParam(HwrInitParam.PARAM_KEY_INIT_CAP_KEYS, initCapkeys);hwrInitParam.addParam(HwrInitParam.PARAM_KEY_FILE_FLAG, "android_so");String dataPath = context.getFilesDir().getAbsolutePath().replace("files", "lib");hwrInitParam.addParam(HwrInitParam.PARAM_KEY_DATA_PATH, dataPath);return hwrInitParam.getStringConfig();}/*** 手寫反初始化功能* @return 返回0為成功,其他為失敗*/public int releaseHwr(){return HciCloudHwr.hciHwrRelease();} }在MainActivity中使用手寫識別的功能
package com.miao.hwrtest;import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.PaintFlagsDrawFilter; import android.graphics.Path; import android.graphics.PixelFormat; import android.graphics.PorterDuff; import android.os.Handler; import android.os.Message; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.Window; import android.widget.EditText; import android.widget.Toast;import com.miao.util.ConfigUtil; import com.miao.util.HciCloudHwrHelper; import com.miao.util.HciCloudSysHelper; import com.sinovoice.hcicloudsdk.common.HciErrorCode;public class MainActivity extends AppCompatActivity implements SurfaceHolder.Callback{private static final int MAX_POINT = 2048;private SurfaceHolder surfaceHolder;private SurfaceView surface;private Paint paint;private Path path;private int top;private int bottom;private boolean isRunning = true;private Canvas canvas;private String TAG = MainActivity.class.getSimpleName();private boolean start = true;private long init;private long now;private int mCurX, mCurY;private int mCurIndex;private short[] mPoints = null;private boolean mEnd;private HciCloudSysHelper mHciCloudSysHelper;private HciCloudHwrHelper mHciCloudHwrHelper;private EditText myEditText;private Handler myHandler = new Handler(){@Overridepublic void handleMessage(Message msg) {switch (msg.arg1) {case 0:Bundle bundle = msg.getData();String result = bundle.getString("result");myEditText.setText(result);break;default:break;}}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);requestWindowFeature(Window.FEATURE_NO_TITLE);setContentView(R.layout.activity_main);initView();initSinovoice();}private void initView() {surface = (SurfaceView) findViewById(R.id.surface);myEditText = (EditText) findViewById(R.id.text);surfaceHolder = surface.getHolder(); //?獲得SurfaceHolder對象surface.setZOrderOnTop(true); //使surface可見surfaceHolder.setFormat(PixelFormat.TRANSPARENT); //設(shè)置背景透明surfaceHolder.addCallback(this); //?為SurfaceView添加狀態(tài)監(jiān)聽paint = new Paint(); //?創(chuàng)建一個畫筆對象path = new Path();mPoints = new short[MAX_POINT * 2];mCurIndex = 0;}/*** 靈云系統(tǒng)初始化*/private void initSinovoice() {mHciCloudSysHelper = HciCloudSysHelper.getInstance();mHciCloudHwrHelper = HciCloudHwrHelper.getInstance();int errorCode = mHciCloudSysHelper.init(this);if (errorCode != HciErrorCode.HCI_ERR_NONE) {Toast.makeText(this, "系統(tǒng)初始化失敗,錯誤碼=" + errorCode, Toast.LENGTH_SHORT).show();return;}errorCode = mHciCloudHwrHelper.initHwr(this, ConfigUtil.CAP_KEY_HWR_LOCAL_LETTER);if (errorCode != HciErrorCode.HCI_ERR_NONE) {Toast.makeText(this, "手寫初始化失敗,錯誤碼=" + errorCode, Toast.LENGTH_SHORT).show();return ;}}/*** 把坐標(biāo)添加到short數(shù)組* @param x* @param y* @return*/private boolean addStroke(short x, short y) {if (mCurX >= 0 && mCurY >= 0) {if ((mCurIndex / 2) < (MAX_POINT - 2)) {mPoints[mCurIndex] = x;mCurIndex++;mPoints[mCurIndex] = y;mCurIndex++;return true;} else if ((mCurIndex / 2) == (MAX_POINT - 2)) {mPoints[mCurIndex] = -1;mCurIndex++;mPoints[mCurIndex] = 0;mCurIndex++;return true;}}return false;}/*** 最后一筆添加坐標(biāo)(-1,-1)*/public void addLastStrokePoint() {if(mCurIndex < 2 ||(mPoints[mCurIndex-1] == -1 && mPoints[mCurIndex-2] == -1)){return;}mPoints[mCurIndex] = -1;mCurIndex++;mPoints[mCurIndex] = -1;mCurIndex++;}/*** 每次抬筆添加坐標(biāo)(-1,0)*/private void addStrokeEnd() {mPoints[mCurIndex] = -1;mCurIndex++;mPoints[mCurIndex] = 0;mCurIndex++;}/*** 重置筆跡點數(shù)據(jù)*/private void resetStroke() {mPoints = new short[MAX_POINT * 2];mCurIndex = 0;}/*** 獲取筆跡點數(shù)組* @return 筆跡點數(shù)組*/public short[] getStroke() {mEnd = true;addStrokeEnd();addLastStrokePoint();short[] stroke = new short[mCurIndex];System.arraycopy(mPoints, 0, stroke, 0, mCurIndex);return stroke;}/*** 當(dāng)SurfaceView創(chuàng)建的時候,調(diào)用此函數(shù)* @param holder*/@Overridepublic void surfaceCreated(SurfaceHolder holder) {int[] location = new int[2];surface.getLocationOnScreen(location);top = location[1];Log.d(TAG, "top = " + top);bottom = top + surface.getHeight();Log.d(TAG, "bottom = " + bottom);//開啟一個繪畫線程new Thread(wlineThread).start();}@Overridepublic boolean onTouchEvent(MotionEvent event) {if (event.getY() >= top && event.getY() <= bottom) {start = true;init = now;now = System.currentTimeMillis();switch (event.getAction()) {case MotionEvent.ACTION_DOWN:if (now - init >= 100 && now - init <= 1000) { //抬筆操作,加上(-1,0) // Log.d(TAG, "X坐標(biāo)=" + "-1" + "\tY坐標(biāo)=" + "0");addStrokeEnd();}path.moveTo(event.getX(), event.getY() - top); // Log.d(TAG, "X坐標(biāo)=" + event.getX() + "\tY坐標(biāo)=" + event.getY()); // addStroke((short) event.getX(), (short) event.getY());break;case MotionEvent.ACTION_MOVE:path.lineTo(event.getX(), event.getY() - top); // Log.d(TAG, "X坐標(biāo)=" + event.getX() + "\tY坐標(biāo)=" + event.getY());addStroke((short) event.getX(), (short) event.getY());break;default:break;}}return true;}@Overridepublic boolean onKeyDown(int keyCode, KeyEvent event) {if (keyCode == KeyEvent.KEYCODE_BACK) {isRunning = false;}return super.onKeyDown(keyCode, event);}/*** 當(dāng)SurfaceView的視圖發(fā)生改變的時候,調(diào)用此函數(shù)* @param holder* @param format* @param width* @param height*/@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}/*** 當(dāng)SurfaceView銷毀的時候,調(diào)用此函數(shù)* @param holder*/@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {Log.d(TAG, "surface Destroyed");isRunning = false;}Runnable wlineThread =new Runnable(){@Overridepublic void run() {while (isRunning) {drawView();if (start) {long temp = System.currentTimeMillis() - now; // Log.d(TAG, "temp=" + temp);if (temp > 1000 && temp < 100000) { //抬筆時間超過1秒,加上坐標(biāo)(-1,-1),過濾第一次時間的計算 // Log.d(TAG, "X坐標(biāo)=" + "-1" + "\tY坐標(biāo)=" + "-1");short[] data = getStroke();String result = mHciCloudHwrHelper.recog(data, ConfigUtil.CAP_KEY_HWR_LOCAL_LETTER);Message message = new Message();message.arg1 = 0;Bundle bundle = new Bundle();bundle.putString("result", result);message.setData(bundle);myHandler.sendMessage(message);start = false;clearCanvas();}}}}};/*** 清空Canvas上的筆跡*/private void clearCanvas() {for (int i = 0; i < 4; i++) {try {if (surfaceHolder != null) {canvas = surfaceHolder.lockCanvas();canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);path.reset();resetStroke();mEnd = false;}} catch (Exception e) {e.printStackTrace();} finally {if (canvas != null){surfaceHolder.unlockCanvasAndPost(canvas);}}}}/*** 再Canvas上畫*/private void drawView() {try {if (surfaceHolder != null) {canvas = surfaceHolder.lockCanvas();canvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG));paint.setColor(Color.RED);paint.setStyle(Paint.Style.STROKE);paint.setStrokeWidth(5);canvas.drawPath(path, paint);}} catch (Exception e) {e.printStackTrace();} finally {if (canvas != null) {surfaceHolder.unlockCanvasAndPost(canvas);}}}@Overrideprotected void onDestroy() {releaseSinovoice();super.onDestroy();}/*** 靈云系統(tǒng)反初始化*/private void releaseSinovoice() {if (mHciCloudHwrHelper != null) {mHciCloudHwrHelper.releaseHwr();}if (mHciCloudSysHelper != null) {mHciCloudSysHelper.release();}} }注:靈云的離線手寫識別能力,第一次使用的時候也是需要有一個聯(lián)網(wǎng)授權(quán)的過程,授權(quán)成功以后,即可在授權(quán)期內(nèi)使用離線手寫能力。
總結(jié)
以上是生活随笔為你收集整理的【Android】灵云手写离线识别使用说明的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 数据挖掘:降低汽油精制过程中的辛烷值损失
- 下一篇: android sina oauth2.