输入法最佳实践

25.07版本的云手机镜像开始,无影云手机支持使用本地输入法,可在部分场景下提供比云手机内置输入法更好的输入体验。

输入法对比

本地输入法是指运行云手机客户端或通过SDK调取云手机画面的本地设备上安装的输入法,即在本地输入,并在云手机实例中进行响应并输出。

本地输入法与云手机内置的输入法相比,各有优劣,分别适用于不同的场景,具体对比如下表所示。

对比项

云手机内置输入法

本地输入法

效果

云手机内置Gboard输入法

ime_cloud_phone

Windows本地的Emoji输入面板

ime_local

Pixel 8a本地的搜狗输入法

ime_local_mobile

优势

  • 兼容:兼容性好,可以兼容几乎任意Android输入法;

  • 稳定:输入法运行在云端系统内,即使因弱网等因素意外断开连接,也不会丢失正在输入的内容。

  • 连贯:输入体验连贯,用户可以使用熟悉的本地输入法完成自己工作中所有的输入,无需频繁切换输入法;

  • 流畅:按键和触摸的处理、输入的预测和推荐、选词都在本地进行,不会因为网络延迟或弱网环境而造成迟滞感;

  • 方便:在Windows/iOS/macOS等非Android平台,都可以使用对应平台的输入法,不是必须使用Android输入法;

  • 高效:输入法所需要的运算资源取自本地,不会占用云端算力,适合新兴的AI、语音识别输入法等需要较高算力的输入法。

弊端

  • 流畅性:由于网络存在物理延迟,因此触摸和键盘输入的透传也是存在延迟的,这导致操作有迟滞感。对于弱网环境,这种迟滞感对输入体验造成的负面影响可能会很严重;

  • 便利性:非Android平台的用户(如Windows、iOS、macOS用户)将被迫使用Android输入法,无法使用熟悉的输入法;

  • 连贯性:整体而言输入体验不够连贯,如果用户的使用场景涉及本地应用和云手机之间的频繁切换,所使用的输入法也会在本机输入法和云手机内置输入法之间来回切换。

  • 稳定性:在完成一次输入(通常是完成选词)之前,本地内容不会被提交到云侧,因此意外的网络中断可能导致正在输入的内容丢失;

    说明

    已经输入完成的文本不受影响,只影响正在拼写的文本。

  • 兼容性:对于极少数不调用Android标准输入框架进行输入操作的应用场景,可能仍然会切换到云手机内置输入法。

输入法切换方法

您可以根据需要切换输入法。

ADB

初次启用

在云手机实例刚刚创建完成时,需要启用云手机内置输入法。

adb shell settings put secure enabled_input_methods "com.google.android.inputmethod.latin/com.android.inputmethod.latin.LatinIME:com.wuying.wyime/.PseudoImeService"
切换为本地输入法
adb shell ime set com.wuying.wyime/.PseudoImeService
切换为云手机内置输入法

本示例中使用的是云手机预装的Gboard输入法,您也可以替换为其他输入法。

adb shell ime set com.google.android.inputmethod.latin/com.android.inputmethod.latin.LatinIME

Web SDK

说明

请获取最新的SDK(以支持本地输入法)和Demo。具体操作,请参见Web SDK

  1. 在连接时指定下面的参数。

    config.useCustomIme=true
  2. 随后按照正常连接流程进行连接即可。详细信息可参见Demo。

Android SDK

Android SDK要启用本地输入法,需要在StreamView连接前监听来自ASP Engine的连接状态回调,并在连接成功的回调中将本地输入法设置为启用状态。

说明

请获取最新的SDK(以支持本地输入法)和Demo。具体操作,请参见Android SDK

@Override
public void onCreate() {
    super.onCreate();
    IASPEngineListener listener = new IASPEngineListener() {
        @Override
        public void onConnectionSuccess(int connectionId) {
            mStreamView.getASPEngineDelegate().setImeType(ASPIMEType.ASP_IME_TYPE_LOCAL);
            mStreamView.shouldProactivelyShowIME(true);
        }
    
        /* 注意:也需要实现其他接口 */
    }
    
    StreamView streamView = findViewById(R.id.stream_view);
    streamView.getASPEngineDelegate().registerASPEngineListener(listener);

    /* 其他 onCreate 过程 */
}