Android 实现 Alexa App-to-App Account Linking

1,210 阅读7分钟

前言

Alexa 的 App-to-App Account Linking 指的是将你的 App 账号与 Alexa App 账号进行 “链接”,“链接” 的作用是为了通过 Amazon Echo 系列音箱来语音控制支持 Alexa 的设备。App-to-App Account Linking 有两种方式,分别 ”从您的应用开始“ 和 ”从 Alexa 应用开始“,这篇文章讲的是第一种。

对于没有实现过的小伙伴,第一次实现可能会无从下手,因为 Google 或者百度搜索几乎找不到相关接入的博客,而且 Alexa 的英文文档也是比较难理解的,最重要的是在实现的过程中还会遇到很多坑,所以这里记录一下。

一、“链接” 流程

1.1 界面交互流程

分成是否安装 Alexa App。

  • 已安装 Alexa App:打开 Alexa App,跳转到一个是否同意 “链接” 的页面,点击 “链接” 则返回到你的 App。 image.png

  • 未安装 Alexa App:打开浏览器加载 Alexa 登录页面,登录后加载一个是否同意 “链接” 的页面,点击 “链接” 则返回到你的 App。 image.png

1.2 底层交互流程

这里贴一张文档中的流程图: image.png

从流程图上可以看到步骤是这样的:
(1)如果用户没有登录那么需要先登录,因为后面后端与 Alxea 交互的时候是需要通过 token 唯一识别某一个用户的。
(2)客户端请求后端获取 Alexa app URL 和 LWA fallback URL。

(3)后端返回对应的 URL。
(4)在页面上点击绑定 Alexa 的时候,如果已安装 Alexa App,则打开 Alexa App,跳转到一个是否同意 “链接” 的页面。点击“链接” 后 Alexa App 会通过 Alexa app URL 中的 redirect_uri 打开你的 App 中指定的页面,并且返回亚马逊授权码;点击取消也是通过 redirect_uri 打开你的 App 中指定的页面。
(5)未安装 Alexa App,则打开浏览器加载 Alexa 登录页面,登录后加载一个是否同意 “链接” 的页面。点击 “链接” 后 Alexa App 会通过 LWA fallback URL 中的 redirect_uri 打开你的 App 中指定的页面,并且返回亚马逊授权码;点击取消也是通过 redirect_uri 打开你的 App 中指定的页面。
(6)客户端拿着亚马逊授权码请求后端,后端去请求亚马逊后端启用技能并 “链接” 账户。
(7)后端返回账户 “链接” 状态,也就是最终绑定成功还是失败。

二、实现

2.1 配置应用链接

Alexa App 打开你的 App 的时候需要通过应用链接跳转回来,所以这里需要先配置应用链接。

(1)添加 Intent 过滤器:

<activity 
    android:name=".xxx.LinkMiddleAppActivity">
    <intent-filter android:autoVerify="true"
        tools:targetApi="m">
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data
            android:scheme="https"
            android:host="www.example.com" />
    </intent-filter>
</activity>
  • android:autoVerify="true":在 Android 6.0 及更高版本的设备上安装应用,系统会去验证应用中的 host,如果与后面配置的 https://xxx/.well-known/assetlinks.json 中的 xxx 匹配,那么系统就会将你的应用指定为处理该 host 的默认程序。
  • scheme+host:组成应用链接 www.example.com,打开指定 Activity 的时候就是通过这两个来标记的。

(2)配置 assetlinks.json
通过在线网站 生成 assetlinks.json 内容: 4.png

  • Hosting site domain:存放 assetlinks.json 文件的域名,需要与 Intent 过滤器中设置的 host 保持一致,这个域名让后端提供即可。
  • App package name:App 的包名。
  • App package fingerprint (SHA256):App 的 SHA256。

填写完成后点击 “Generate statement” 按钮即可生成 assetlinks.json 内容。

或者手动生成,如下,更改 package_name、sha256_cert_fingerprints 即可:

[{	"relation": ["delegate_permission/common.handle_all_urls"],
	"target": {
		"namespace": "android_app",
		"package_name": "com.example.app",
		"sha256_cert_fingerprints": ["14:6D:E9:83:C5:73:06:50:D8:EE:B9:95:2F:34:FC:64:16:A0:83:42:E6:1D:BE:A8:8A:04:96:B2:3F:CF:44:E5"]
	}
}]

然后创建 assetlinks.json 文件,将上面的内容复制进去,将 assetlinks.json 文件发给后端同事,让他上传到 www.example.com 域名的 .well-known 目录下,然后打开 www.example.com/.well-known… 可以看到配置的内容即可。

最后点击在线网站的 “Test statement” 按钮,如果返回 success 那么就表示 assetlinks.json 文件配置成功了。

(3)测试应用链接
首先将应用安装到手机上,等待 20s 以上,让系统完成异步验证流程。然后在终端执行如下命令:

adb shell am start -a android.intent.action.VIEW \
    -c android.intent.category.BROWSABLE \
    -d "https://www.example.com"

如果可以打开你的应用,那么应用链接配置成功;如果弹框让你选择是使用应用打开还是浏览器打开,或者不弹框直接用浏览器打开,那么应用链接配置失败,需要回去检查上面的配置是否有误。

2.2 配置技能

即在 Alexa 开发者控制台配置技能的相关参数,例如 Alexa app URL、LWA fallback URL 中的一些参数就是在这里配置的,实际上这一步一般都是后端去完成,但是有些后端也没配置过,会导致客户端使用 Alexa app URL、LWA fallback URL 的时候各种报错,所以客户端还是要了解一些主要参数的配置,出现错误的时候才知道是哪里错了并提醒后端改过来。

(1)登录 Alexa Skills Kit 开发者控制台
(2)在技能列表中找到需要配置的技能,选择编辑。
(3)点击左侧栏的 “TOOLS”,然后再点击 “Account linking”。
(4)打开 ”Allow users to link their account to your skill from within your application or website“ 开关,”authorization grant type“ 选择 Auth Code Grant。如下图:
5.png

(5)Your Android App Authorization URI 填写 assetlinks.json 文件的地址
www.example.com/.well-known…
(6)Your Redirect URLs 填写应用链接 www.example.com。
(7)记住这里的 ”Your Client ID“ 和 ”Alexa Client Id“,后端返回的 Alexa app URL 和 LWA fallback URL 中的 client_id 使用的是后者,如果弄错了需要告诉后端改回来,否则打开 Alxea App 会报错。

2.3 获取用户的亚马逊授权码去启用技能并 “链接” 账户

(1)请求后端获取 Alexa app URL 和 LWA fallback URL。
(2)判断 Alexa App 是否安装,已安装打开 Alexa App,未安装打开浏览器加载 Alexa 登录页面(由于浏览器无法通过应用链接跳转回 App,所以这里通过应用内的 WebView 加载)。如下:

private void openAlexaAppToAppUrl() {
    boolean isAlexaInstalled = AppUtils.isAppInstalled("com.amazon.dee.app");
    if (isAlexaInstalled) {
        Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(alexaAppUrl));
        startActivity(intent);
    } else {
        CommonWebActivity.start(this, lwaFallbackUrl);
    }
}

com.amazon.dee.app 需要在清单文件中声明,否则在 targetSdkVersion 30 及以上 AppUtils#isAppInstalled() 无效。

<queries>
    <package android:name="com.amazon.dee.app" />
</queries>

如果是打开 Alexa App,用户同意 “链接” 后会通过 Alexa app URL 中的 redirect_uri 打开你的 App 中指定的页面,也就是上面配置了应用链接的 LinkMiddleAppActivity 页面,在该页面获取亚马逊授权码:

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Uri uri = getIntent().getData();
    String code = uri.getQueryParameter(”code“);
}

如果是打开 Web 页面,用户同意 “链接” 后会加载一个 Url,亚马逊授权码就在这个 Url 中,在 CommonWebActivity 页面获取到 Url 后将亚马逊授权码取出来即可:

private WebViewClient mWebViewClient = new WebViewClient() {
    ...
    @Override
    public void onPageStarted(WebView view, String url, Bitmap favicon) {
        if (url.contains("code")) {
            Uri uri = Uri.parse(url);
            String code = uri.getQueryParameter(”code“);
        }
    }
    ...
};

(3)拿着亚马逊授权码请求后端,后端去请求亚马逊后端启用技能并 “链接” 账户。然后后端返回账户 “链接” 状态,也就是最终绑定成功还是失败。

三、遇到的一些坑

3.1 无法在 Google Play 搜索到 Alexa App 进行下载

问题:
无法在 Google Play 搜索到 Alexa App。

原因:
在大陆地区下载 Alexa App 需要使用国外的应用市场账号。

解决:

  • 使用国外的应用市场账号进行下载。
  • 在电脑上下载再安装到手机上。

3.2 国内登录 Alexa App 报错

问题:
登录填写验证码的时候提示验证码不正确,或者登录成功后弹框报错: 6.png

原因:
国内使用应该是被限制了,Alexa App 判断地区是国内就不给使用。

解决:
更改手机系统地区为美国。

如果上面改了后还不行可以尝试以下操作:

  • 更改系统语言为英文。
  • 翻墙。
  • 关闭定位。
  • 拔掉 SIM 卡。

3.3 Unable to link account with Alexa

问题:
跳转到 Alexa App 后显示 Unable to link account with Alexa,如下:
7.png

原因:
后端返回的 Alexa app URL 中的 skill_stage 设置错了。

解决:
技能发布之前 stage 需要设置成 development,发布之后设置成 live。

3.4 跳转到 Alexa app 后不显示提示文字

问题:
跳转到 Alexa app 后不显示提示文字,如图:
8.png

原因:
账号被限制了,可能是手机号注册的原因,也可能是识别到是国内登录的原因,总之后面这个账号虽然能登录,但是 Alexa App 中很多功能用不了了,很坑,找了很久原因。

解决:
重新注册一个账号。

四、参考资料

关于我

我是 wildmaCSDN 认证博客专家简书程序员优秀作者,擅长屏幕适配
如果文章对你有帮助,点个赞就是对我最大的认可!