Java SDK 提供了 RegisterApp.register 方法,基于 OAuth 2.0 Device Authorization Grant(RFC 8628)协议实现一键创建应用。
调用该方法会返回一个验证链接,用户在飞书或 Lark 中打开该链接(或扫码)完成授权后,即可自动注册应用并获取凭据(App ID 和 App Secret),无需手动前往开发者后台创建。
查看源码:oapi-sdk-java
前提条件
- 安装
oapi-sdk,且 SDK 版本为 2.6.1 及以上。
Maven:
<dependency>
<groupId>com.larksuite.oapi</groupId>
<artifactId>oapi-sdk</artifactId>
<version>2.6.1</version>
</dependency>
快速开始示例
import com.lark.oapi.scene.registration.AppPreset;
import com.lark.oapi.scene.registration.RegisterApp;
import com.lark.oapi.scene.registration.RegisterAppException;
import com.lark.oapi.scene.registration.RegisterAppOptions;
import com.lark.oapi.scene.registration.RegisterAppResult;
public class Sample {
public static void main(String[] args) {
try {
RegisterAppResult result = RegisterApp.register(
RegisterAppOptions.newBuilder()
.source("test")
.appPreset(AppPreset.newBuilder()
.avatars(
"https://s1-imfile.feishucdn.com/static-resource/v1/v3_00cj_d6bebede-c56b-40a2-b767-8e9da07f3b3g",
"https://s1-imfile.feishucdn.com/static-resource/v1/v2_bc5d2075-fcbd-41f8-bfe3-5a5ecbf0f7dg"
)
.name("{user}的应用")
.desc("由业务平台自动生成")
.build())
.onQRCode(info -> {
System.out.println("Please scan the QR code:");
System.out.println(info.getUrl());
System.out.println(String.format("Link expires in %s seconds", info.getExpireIn()));
})
.onStatusChange(info -> System.out.println(
"status: " + info.getStatus()
+ (info.getInterval() > 0
? String.format(" (Interval: %s seconds)", info.getInterval())
: "")
))
.build()
);
System.out.println("App ID: " + result.getClientId());
System.out.println("App Secret: " + result.getClientSecret());
System.out.println("User Info: " + result.getUserInfo());
} catch (RegisterAppException e) {
System.err.println("fail: " + e.getCode() + " " + e.getDescription());
}
}
}
真实可运行示例:
自定义权限/事件/回调与更新已有应用
创建应用时,可以通过 addons 在平台基础模板上增量申请权限、事件订阅和回调。这些配置会预填到用户打开验证链接后的确认页中,用户确认后生效:
import com.lark.oapi.scene.registration.AppAddons;
// 创建:增量申请权限/事件/回调,且只允许创建新应用。
RegisterApp.register(RegisterAppOptions.newBuilder()
.addons(AppAddons.newBuilder()
.tenantScopes("im:message:send_as_bot")
.userScopes("calendar:calendar:read")
.tenantEvents("im.message.receive_v1")
.callbacks("card.action.trigger")
.build())
.createOnly(true)
.onQRCode(info -> System.out.println(info.getUrl()))
.build());
// 更新:传入已有应用的 appId,让用户确认增量配置变更。
RegisterApp.register(RegisterAppOptions.newBuilder()
.appId("cli_xxx")
.addons(AppAddons.newBuilder()
.tenantScopes("drive:drive.metadata:readonly")
.build())
.onQRCode(info -> System.out.println(info.getUrl()))
.build());
// 最小底座:preset(false) 把底座切换为最小基础模板,确认页只展示 addons 中显式声明的配置。
// 此时增量项可以为空。
RegisterApp.register(RegisterAppOptions.newBuilder()
.addons(AppAddons.newBuilder()
.preset(false)
.tenantScopes("im:message:send_as_bot")
.build())
.onQRCode(info -> System.out.println(info.getUrl()))
.build());
addons仅支持增量叠加,不能删减基础模板里的权限。addons.preset控制底座模板:缺省或true保留平台默认模板(含默认权限/事件/回调);false切换为最小基础模板(仅机器人能力,无业务权限),最终配置完全由addons声明。preset(false)时增量项可以全部为空。- 仅支持 5 类公开配置:应用/用户身份权限、应用/用户身份事件、回调。事件请求 URL、
security.*、加密 key 等敏感配置不能通过addons传入,需要使用更新应用开发配置 OpenAPI。 - SDK 校验数据形状和非空值,不校验权限点/事件/回调名称是否存在于平台目录。
RegisterAppOptions 参数
| 参数 | 描述 | 类型 | 必须 | 默认 |
|---|---|---|---|---|
source |
来源标识,拼入二维码 URL 的 source 参数,格式为 java-sdk/{source} |
String |
否 | - |
domain |
自定义飞书认证基地址 | String |
否 | https://accounts.feishu.cn |
larkDomain |
自定义 Lark 认证基地址,检测到 Lark 租户时自动切换 | String |
否 | https://accounts.larksuite.com |
appPreset |
预设应用信息,用于初始化应用创建页。所有字段都是可选的,用户扫码后仍可在页面手动修改。SDK 会自动对原始值做 URL Encode。 | AppPreset |
否 | - |
appPreset.avatar |
应用头像候选 URL,支持 1-6 个;传多个时默认选中第一个。图片格式、GIF 截帧、裁切和展示由页面/服务端处理。 | String / String[] / List<String> |
否 | - |
appPreset.name |
应用名称,支持 {user} 占位符,由应用创建页替换为扫码用户名称。 |
String |
否 | - |
appPreset.desc |
应用描述,支持 {user} 占位符。 |
String |
否 | - |
addons |
增量权限/事件/回调配置,预填到确认页。 | AppAddons |
否 | - |
addons.preset |
底座模板开关。缺省或 true 保留平台默认模板;false 切换为最小基础模板,确认页只展示 addons 中显式声明的配置。 |
boolean |
否 | 平台默认模板 |
addons.scopes.tenant |
应用身份权限列表,例如 im:message:send_as_bot。 |
String[] / List<String> |
否 | - |
addons.scopes.user |
用户身份权限列表,例如 calendar:calendar:read。 |
String[] / List<String> |
否 | - |
addons.events.items.tenant |
应用身份事件列表,例如 im.message.receive_v1。 |
String[] / List<String> |
否 | - |
addons.events.items.user |
用户身份事件列表,例如 calendar.calendar.event.changed_v4。 |
String[] / List<String> |
否 | - |
addons.callbacks.items |
回调列表,例如 card.action.trigger。 |
String[] / List<String> |
否 | - |
createOnly |
为 true 时落地页仅允许创建新应用,并隐藏选择已有应用入口。 |
boolean |
否 | false |
appId |
已有应用的 App ID(cli_ 前缀)。传入后流程会让用户确认 addons 带来的配置 diff。createOnly 为 true 时页面会忽略该参数。 |
String |
否 | - |
onQRCode |
验证链接就绪时的回调,参数为 QRCodeInfo,包含 url 和 expireIn |
Consumer<QRCodeInfo> |
是 | - |
onStatusChange |
轮询状态变化时的回调,参数为 StatusChangeInfo |
Consumer<StatusChangeInfo> |
否 | - |
返回值
| 字段 | 类型 | 描述 |
|---|---|---|
clientId |
String |
App ID |
clientSecret |
String |
App Secret |
userInfo |
UserInfo |
扫码用户信息 |
userInfo.openId |
String |
用户的 open_id |
userInfo.tenantBrand |
String |
"feishu" 或 "lark" |
状态回调
| 状态 | 描述 |
|---|---|
polling |
仍在等待用户授权 |
slow_down |
服务端要求降低轮询频率,interval 为新的轮询间隔(秒) |
domain_switched |
SDK 检测到 Lark 租户并切换到 larkDomain 继续轮询 |
错误处理
RegisterAppException 包含 code 和 description 字段:
| code | 描述 |
|---|---|
access_denied |
用户拒绝了授权 |
expired_token |
二维码过期或轮询超时 |
abort |
通过线程中断取消了注册流程 |
invalid_response |
服务端返回了不符合预期的响应 |