本文带您了解WhatsApp新的身份验证模板。
背景信息
自2023年5月1日起,WhatsApp推出了包含一次性密码按钮的身份验证模板(Authentication),自2023年5月29日起,所有新建的身份验证模板都必须包含一次性密码按钮。更多关于身份验证模板的信息请参见WhatsApp模板类型说明。
身份验证模板
模板组成
包含一次性密码按钮的身份验证模板由以下部分组成:
身份验证模板的预设固定文本:
<VERIFICATION_CODE> 是您的验证码。
安全免责声明(可选):为安全起见,请勿共享该验证码。
过期警告(可选):这组验证码将在<NUM_MINUTES>分钟后过期。
按钮:复制验证码按钮(Copy code)或一键自动填写按钮(Autofill)。
示例图:
模板规则限制
包含一次性密码按钮的身份验证模板仅由预设文本和按钮组成。
身份验证模板的内容或参数不允许使用网址、媒体(图片、音频、视频、文件等)和表情符号。
身份验证模板使用参数最多支持15 个字符,即验证码最大长度为15位。
按钮
身份验证模板必须包含复制验证码按钮(Copy code)或一键自动填写按钮(Autofill)。当用户点击按钮时,不同按钮的工作方式不同:
复制验证码按钮:会将一次性密码或验证码复制到用户的剪贴板。然后,用户可以手动切换到您的应用,将一次性密码或验证码粘贴到应用界面。
一键自动填写按钮:会自动加载您的应用,并向该应用传递一次性密码或验证码。
一键自动填写按钮可提供最佳用户体验,所以是首选的解决方案。但是,目前仅安卓系统手机(Android)支持一键自动填写按钮,并且此类按钮需要更改您应用的代码,才能执行“握手”,另外还需要更改应用的签名密钥哈希值。请参阅下方握手和 应用签名密钥哈希值部分。
最佳实践
在发送一次性密码或验证码前,先确认用户的WhatsApp电话号码,再向该号码发送一次性密码或验证码。
明确告知用户,一次性密码或验证码将发送至他们的WhatsApp电话号码,尤其是当您为用户提供多种方式来接收一次性密码或验证码时。
当用户将一次性密码或验证码粘贴到您的应用中时,或应用在一键自动填写按钮流程中收到一次性密码或验证码时,请明确告知用户应用已获取一次性密码或验证码。
参数说明
参数名 | 描述 | 示例值 |
COMPONENTS | 该数组包含描述模板内容和元数据的单个对象。 | - |
LANGUAGE | 模板的语言代码。 | en_US |
NAME | 模板的名称。 仅支持小写字母、下划线、数字。 名称长度不超过60个字符。 | verification_code |
WHATSAPP_BUSINESS_ACCOUNT_ID | 要与模板关联的WABA ID。 | 106***********06 |
ADD_SECURITY_RECOMMENDATION | 可选。 布尔值。 如需在模板中加入以下字符串,请将此占位符设为true:为安全起见,请勿共享该验证码。 否则,请设为false。 说明 字符串内容为固定内容。 | true |
CODE_EXPIRATION_MINUTES | 可选。 整数。 表示一次性密码或验证码的有效期(以分钟为单位)。 如果忽略此占位符,则发送的消息不会显示一次性密码或验证码的过期警告。 最小值为1,最大值为90。 | 5 |
COPY_CODE_BUTTON_TEXT | 字符串。 复制验证码按钮的文本。 重要 即使模板使用一键自动填写按钮,您仍须提供此值。如果我们无法验证您的握手,身份验证模板消息会显示一个包含此文本的复制验证码按钮。 不超过 25 个字符。 | Copy Code |
ONE_TAP_BUTTON_TEXT | 仅适用于一键自动填写按钮。 字符串。 一键自动填写按钮的文本。 不超过 25 个字符。 | Autofill |
OTP_TYPE | 枚举。 表示按钮类型。 如需让模板使用复制验证码按钮,请将此占位符设为 COPY_CODE; 如需让模板使用一键自动填写按钮,则设为 ONE_TAP。 请参阅上方按钮部分。 | ONE_TAP |
PACKAGE_NAME | Android应用的应用包名。 | com.example.myapplication |
SIGNATURE_HASH | 应用签名密钥哈希值。 请参阅下方应用签名密钥哈希值。 | K8a%2FAINcGX7 |
应用签名密钥哈希值
如要创建使用一键自动填写按钮的身份验证模板,您必须在components数组中加入应用签名密钥哈希值。
如要计算您的哈希值,请遵循Google有关计算应用的哈希字符串的说明。
或者,如果您按照Google说明下载了应用签名密钥证书,您可以结合使用该证书和sms_retriever_hash_v9.sh shell脚本来计算哈希值。
握手
如果您应用中的用户请求获取一次性密码或验证码,并选择将其发送到他们的WhatsApp电话号码,您首先应执行“握手”,然后调用我们的API来发送身份验证模板消息。在收到该消息后,WhatsApp应用将执行资格检查。如果没有错误,WhatsApp将启动意图并向用户显示该消息。最后,当用户点击该消息的一键自动填写按钮时,WhatsApp应用会自动加载您的应用并向传递一次性密码或验证码。
如果您在发送消息之前不执行“握手”,或消息未通过资格检查,则发送的消息将显示复制验证码按钮(Copy code),而不是一键自动填写按钮(Autofill)。
资格检查
在收到身份验证模板消息之后,WhatsApp应用会执行以下检查。如果任意检查失败,一键自动填写按钮将被替换为复制验证码按钮。
“握手”是在发送消息前的10分钟内发起。
消息中的应用包名(创建模板时在components数组的package_name属性中定义)与意图上设置的应用包名匹配。WhatsApp应用将使用您的应用程序提供的PendingIntent对象中调用的getCreatorPackage方法判断项目包名称是否匹配。
消息中的应用签名密钥哈希值(创建模板时在components数组的signature_hash属性中定义)与您所安装应用的签名密钥哈希值匹配。
消息包含一键自动填写按钮的文本。
您的应用已定义用于接收一次性密码或验证码的活动。请参阅下方活动(Activity)部分。
Android通知
仅在以下情况下,表示已收到WhatsApp身份验证模板消息的Android通知才会显示在用户的Android设备上:
用户使用所发送消息的接收电话号码(账户)登录WhatsApp应用。
用户登录您的应用。
Android操作系统是 KitKat(Android 4.4,API 19)或更高版本。
WhatsApp应用已启用显示通知(设置>通知)。
已为WhatsApp应用启用设备层级通知。
在WhatsApp应用中,用户与您的企业之间过去的消息对话未设为静音。
客户端实现
在您的应用中实现以下活动(activity)和类(class)。
活动(Activity)
声明可接收一次性密码或验证码的活动和意图筛选条件。意图筛选条件必须具有操作名称 com.whatsapp.otp.OTP_RETRIEVED。
在收到身份验证模板消息(且该消息已通过所有资格检查)后,WhatsApp应用将立即开始执行此活动。
公共类(Public Class)
定义在一次性密码或验证码传递到您的应用后,可接受该一次性密码或验证码的活动公共类。
发起“握手”
以下示例展示了使用WhatsApp应用发起“握手”的一种方法。
public void sendOtpIntentToWhatsApp() {
// Send OTP_REQUESTED intent to both WA and WA Business App
sendOtpIntentToWhatsApp("com.whatsapp");
sendOtpIntentToWhatsApp("com.whatsapp.w4b");
}
private void sendOtpIntentToWhatsApp(String packageName) {
/**
* Starting with Build.VERSION_CODES.S, it will be required to explicitly
* specify the mutability of PendingIntents on creation with either
* (@link #FLAG_IMMUTABLE} or FLAG_MUTABLE
*/
int flags = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S ? FLAG_IMMUTABLE : 0;
PendingIntent pi = PendingIntent.getActivity(
getApplicationContext(),
0,
new Intent(),
flags);
// Send OTP_REQUESTED intent to WhatsApp
Intent intentToWhatsApp = new Intent();
intentToWhatsApp.setPackage(packageName);
intentToWhatsApp.setAction("com.whatsapp.otp.OTP_REQUESTED");
// WA will use this to verify the identity of the caller app.
Bundle extras = intentToWhatsApp.getExtras();
if (extras == null) {
extras = new Bundle();
}
extras.putParcelable("_ci_", pi);
intentToWhatsApp.putExtras(extras);
getApplicationContext().sendBroadcast(intentToWhatsApp);
}
错误信号
如果您的消息未通过WhatsApp的任意一项资格检查,一键自动填写按钮将被替换为复制验证码按钮。此外,还可能有设备、WhatsApp应用设置阻止消息通知。为帮助调试,WhatsApp应用会通过传递com.whatsapp.OTP_ERROR意图来显示一些错误信息。在这种情况下,您将收到错误密钥和消息,而不是用户的一次性密码或验证码。
请注意,其中某些错误信号只有在Android模拟器中运行WhatsApp应用时才会出现。
键 | 描述 |
incompatible_os_version | Android 版本不兼容。 如果发起“握手”(发送 com.whatsapp.otp.OTP_REQUESTED 意图),但设备所运行的 Android 版本低于 v19,则会出现此情况。 |
incorrect_signature_hash 说明 仅限模拟器 | 签名哈希不正确。 如果发起“握手”(发送 com.whatsapp.otp.OTP_REQUESTED 意图),并且WhatsApp应用收到使用一键自动填写按钮的身份验证模板消息,而消息中的包名未生成消息的签名哈希,则会出现此情况。 |
missing_handshake_or_disorder | 缺少“握手”/操作指令。 如果WhatsApp应用收到带有一键自动填写按钮的身份验证模板消息,但未发起“握手”,则会出现此情况。 |
otp_request_expired | 一次性密码请求过期。 如果使用一键自动填写按钮的身份验证模板已送达用户,但此时距您发起握手已超过 10 分钟,则会出现此情况。在此情况下,会改为显示复制验证码按钮。 |
whatsapp_message_notification_disabled 说明 仅限模拟器 | WhatsApp应用中设置了禁用消息通知。 如果发起“握手”(发送 com.whatsapp.otp.OTP_REQUESTED 意图),但用户已在WhatsApp应用中禁用通知,则会出现此情况。 |
whatsapp_notification_disabled 说明 仅限模拟器 | 已在设备层级禁用WhatsApp通知。 如果发起“握手”(发送 com.whatsapp.otp.OTP_REQUESTED 意图),但用户已在WhatsApp(设备层级设置)中禁用应用通知,则会出现此情况。 |
集成
错误信号通过广播意图送达,因此必须运行BroadcastReceiver才能收到错误信号。
使用 manifest.xml
<receiver
android:name=".app.otp.OtpErrorReceiver"
android:enabled="true"
android:exported="true" >
<intent-filter>
<action android:name="com.whatsapp.otp.OTP_ERROR"/>
</intent-filter>
</receiver>
使用接收器类
<![CDATA[ public class OtpErrorReceiver extends BroadcastReceiver { public static final String OTP_ERROR_KEY = "error"; public static final String OTP_ERROR_MESSAGE_KEY = "error_message"; @Override public void onReceive(Context context, Intent intent) { try { PendingIntent pendingIntent = intent.getParcelableExtra("_ci_"); if (pendingIntent != null) { String packageName = pendingIntent.getCreatorPackage(); if (packageName.equalsIgnoreCase("com.whatsapp") || packageName.equalsIgnoreCase("com.whatsapp.w4b")) { String otpErrorKey = intent.getStringExtra(OTP_ERROR_KEY);String otpErrorMessage = intent.getStringExtra(OTP_ERROR_MESSAGE_KEY); // Handle errors } } } catch (BadParcelableException e) { Log.e("OtpErrorReceiver", e.getLocalizedMessage()); } } } ]]>
应用示例
请访问Github网站,参阅适用于Android平台的WhatsApp一次性密码 (OTP) 应用示例。该应用示例展示了如何通过 API 发送和接收一次性密码和验证码、如何集成一键自动填写按钮和复制验证码按钮、如何创建模板以及如何启动示例服务器。