更新记录

1.0.0(2026-01-19)

  • 初始版本:LINE Login(Android / iOS),默认优先 LINE App,未安装走 Web
  • 提供 lineLogin / lineLogout / lineGetProfile / lineGetCredential / lineRefreshAccessToken / lineVerifyToken
  • 提供 setLogEnabled / isLogEnabled 与统一错误码

平台兼容性

uni-app(4.87)

Vue2 Vue3 Chrome Safari app-vue app-nvue Android iOS 鸿蒙
- - - - - - -
微信小程序 支付宝小程序 抖音小程序 百度小程序 快手小程序 京东小程序 鸿蒙元服务 QQ小程序 飞书小程序 快应用-华为 快应用-联盟
- - - - - - - - - - -

uni-app x(4.87)

Chrome Safari Android iOS 鸿蒙 微信小程序
- - - -

hans-line(LINE Login)

基于 UTS 的 LINE 登录插件:支持 Android / iOS,默认「优先 LINE App,未安装则走网页登录」。可通过 onlyLineApp 强制只用 App(未安装则失败)。

支持平台

运行环境 Android iOS Harmony Web
uni-app App -
uni-app-x App -

Harmony/Web/小程序等未实现:会走通用实现并返回 9010701 unsupported platform

依赖 SDK 版本

  • Android:com.linecorp.linesdk:linesdk:5.11.1utssdk/app-android/config.json
  • iOS:CocoaPods LineSDKSwift 5.14.0(模块名 LineSDKutssdk/app-ios/config.json),最低 iOS 13.0+

安装(插件市场 / uni_modules)

将本插件安装到你的项目 uni_modules/hans-line/ 后,即可直接在业务代码中使用:

import { lineLogin } from '@/uni_modules/hans-line'

本插件仅在 App 端有效(Android/iOS)。Web/小程序/Harmony 等平台会返回不支持错误码。

快速使用

import {
  lineLogin,
  lineGetProfile,
  lineGetCredential,
  lineRefreshAccessToken,
  lineVerifyToken,
  lineLogout,
  setLogEnabled
} from '@/uni_modules/hans-line'

setLogEnabled(true)

lineLogin({
  channelId: '你的 LINE Channel ID',
  scopes: ['profile', 'openid', 'email'],
  onlyLineApp: false,
  success: async (res) => {
    console.log('login ok', res)
    lineGetProfile({ success: (r) => console.log('profile', r.profile) })
    lineGetCredential({ success: (r) => console.log('credential', r.credential) })
    lineVerifyToken({ success: (r) => console.log('verify', r.credential) })
    lineRefreshAccessToken({ success: (r) => console.log('refresh', r.credential) })
    // lineLogout({ success: () => console.log('logout ok') })
  },
  fail: (err) => console.error('login fail', err)
})

直接可用的页面示例(不依赖 Demo 工程)

下面给出两个“可直接复制粘贴”的调用片段,发布到插件市场时也能单独阅读使用(无需引用本仓库 demo 文件)。

uni-app(Vue 页面示例:pages/index/index.vue

<template>
  <view class="page">
    <view class="row">
      <text>Channel ID</text>
      <input v-model="channelId" placeholder="请输入 LINE Channel ID" />
    </view>

    <view class="row">
      <text>onlyLineApp</text>
      <switch :checked="onlyLineApp" @change="onOnlyLineAppChange" />
    </view>

    <view class="btns">
      <button type="primary" @click="onLogin">LINE 登录</button>
      <button @click="onProfile">获取 Profile</button>
      <button @click="onCredential">获取 Credential</button>
      <button @click="onVerify">Verify Token</button>
      <button @click="onRefresh">Refresh Token</button>
      <button type="warn" @click="onLogout">Logout</button>
    </view>

    <view class="log">
      <text selectable>{{log}}</text>
    </view>
  </view>
</template>

<script>
import {
  lineLogin,
  lineLogout,
  lineGetProfile,
  lineGetCredential,
  lineRefreshAccessToken,
  lineVerifyToken,
  setLogEnabled
} from '@/uni_modules/hans-line'

export default {
  data() {
    return {
      channelId: '',
      onlyLineApp: false,
      log: ''
    }
  },
  onLoad() {
    setLogEnabled(true)
  },
  methods: {
    append(obj) {
      const text = typeof obj === 'string' ? obj : JSON.stringify(obj, null, 2)
      this.log = `${text}\n\n${this.log}`
      console.log(obj)
    },
    onOnlyLineAppChange(e) {
      this.onlyLineApp = !!e.detail.value
    },
    onLogin() {
      lineLogin({
        channelId: this.channelId,
        scopes: ['profile', 'openid', 'email'],
        onlyLineApp: this.onlyLineApp,
        success: (res) => this.append(res),
        fail: (err) => this.append(err)
      })
    },
    onProfile() {
      lineGetProfile({
        success: (res) => this.append(res),
        fail: (err) => this.append(err)
      })
    },
    onCredential() {
      lineGetCredential({
        success: (res) => this.append(res),
        fail: (err) => this.append(err)
      })
    },
    onVerify() {
      lineVerifyToken({
        success: (res) => this.append(res),
        fail: (err) => this.append(err)
      })
    },
    onRefresh() {
      lineRefreshAccessToken({
        success: (res) => this.append(res),
        fail: (err) => this.append(err)
      })
    },
    onLogout() {
      lineLogout({
        success: (res) => this.append(res),
        fail: (err) => this.append(err)
      })
    }
  }
}
</script>

<style>
.page { padding: 24rpx; }
.row { display: flex; align-items: center; margin-bottom: 16rpx; }
input { flex: 1; margin-left: 16rpx; border: 1px solid #ddd; padding: 12rpx; border-radius: 8rpx; }
.btns button { margin: 12rpx 0; }
.log { margin-top: 24rpx; padding: 16rpx; background: #f7f7f7; border-radius: 8rpx; }
</style>

uni-app-x(uvue 页面示例:pages/index/index.uvue

<template>
  <view class="page">
    <view class="row">
      <text>Channel ID</text>
      <input v-model="channelId" placeholder="请输入 LINE Channel ID" />
    </view>

    <view class="row">
      <text>onlyLineApp</text>
      <switch :checked="onlyLineApp" @change="onOnlyLineAppChange" />
    </view>

    <view class="btns">
      <button type="primary" @click="onLogin">LINE 登录</button>
      <button @click="onProfile">获取 Profile</button>
      <button @click="onCredential">获取 Credential</button>
      <button @click="onVerify">Verify Token</button>
      <button @click="onRefresh">Refresh Token</button>
      <button type="warn" @click="onLogout">Logout</button>
    </view>

    <view class="log">
      <text selectable>{{log}}</text>
    </view>
  </view>
</template>

<script lang="uts">
import {
  lineLogin,
  lineLogout,
  lineGetProfile,
  lineGetCredential,
  lineRefreshAccessToken,
  lineVerifyToken,
  setLogEnabled
} from '@/uni_modules/hans-line'

export default {
  data() {
    return {
      channelId: '',
      onlyLineApp: false,
      log: ''
    }
  },
  onLoad() {
    setLogEnabled(true)
  },
  methods: {
    append(obj: any) {
      const text = (typeof obj == 'string') ? obj : JSON.stringify(obj, null, 2)
      this.log = `${text}\n\n${this.log}`
      console.log(obj)
    },
    onOnlyLineAppChange(e: any) {
      this.onlyLineApp = !!e.detail.value
    },
    onLogin() {
      lineLogin({
        channelId: this.channelId,
        scopes: ['profile', 'openid', 'email'],
        onlyLineApp: this.onlyLineApp,
        success: (res) => this.append(res),
        fail: (err) => this.append(err)
      })
    },
    onProfile() {
      lineGetProfile({
        success: (res) => this.append(res),
        fail: (err) => this.append(err)
      })
    },
    onCredential() {
      lineGetCredential({
        success: (res) => this.append(res),
        fail: (err) => this.append(err)
      })
    },
    onVerify() {
      lineVerifyToken({
        success: (res) => this.append(res),
        fail: (err) => this.append(err)
      })
    },
    onRefresh() {
      lineRefreshAccessToken({
        success: (res) => this.append(res),
        fail: (err) => this.append(err)
      })
    },
    onLogout() {
      lineLogout({
        success: (res) => this.append(res),
        fail: (err) => this.append(err)
      })
    }
  }
}
</script>

<style>
.page { padding: 24rpx; }
.row { display: flex; align-items: center; margin-bottom: 16rpx; }
input { flex: 1; margin-left: 16rpx; border-width: 1px; border-style: solid; border-color: #ddd; padding: 12rpx; border-radius: 8rpx; }
.btns button { margin: 12rpx 0; }
.log { margin-top: 24rpx; padding: 16rpx; background-color: #f7f7f7; border-radius: 8rpx; }
</style>

API 说明

  • lineLogin(options):登录并返回 profile/credential(按 scope & SDK 能力返回;可能为 null
    • channelId:必填(会缓存;后续 lineGetProfile/lineGetCredential/... 可不传)
    • scopes:默认 ['profile','openid'];插件会自动补齐 profile,当包含 email/address/... 等 openid 子 scope 时会自动补齐 openid
    • nonce:可选(用于 OpenID Connect)
    • onlyLineApptrue 强制 App;false 优先 App,未安装走 Web
  • lineGetProfile(options):读取当前登录用户 profile
  • lineGetCredential(options):读取当前 token(access token / id token / scopes / 过期信息)
  • lineRefreshAccessToken(options):刷新 access token
  • lineVerifyToken(options):校验 access token(成功会返回最新 credential 结构)
  • lineLogout(options):登出(同时清理插件缓存的 channelId/profile/token)
  • setLogEnabled(true|false) / isLogEnabled():插件内部日志开关(默认关闭)

scopes(常用)

  • profile
  • openid
  • email

更多 scope 请参考 LINE Developers / LINE SDK 文档(Android/iOS SDK 都支持自定义 scope 字符串)。

平台配置要点

插件已提供必要的 AndroidManifest / iOS Info.plist 注入;但你仍需要在 LINE Developers Console 侧完成包名/Bundle ID 等配置,否则会出现登录失败或回跳失败。

uni-app / uni-app-x:URL Scheme(回调)配置(重要)

LINE App/Web 登录完成后需要通过自定义 Scheme 回跳到你的 App。通常规则是:

  • Android:line3rdp.<Android 包名(applicationId)>
  • iOS:line3rdp.<iOS Bundle ID>

在 uni-app(5+App)项目中建议在 manifest.json 配置(HBuilderX 可视化界面对应“Android Scheme / iOS URL Types”):

{
  "app-plus": {
    "distribute": {
      "android": { "schemes": "line3rdp.com.example.app" },
      "ios": { "urltypes": "line3rdp.com.example.app" }
    }
  }
}

注意:

  • 上面的 com.example.app 需要替换为你实际打包出来的 Android 包名 / iOS Bundle ID(两端不一定相同,按各自实际值填写)。
  • 调试如果使用不同的包名/Bundle ID(例如自定义基座 vs 发行包),Scheme 也必须跟着变化;否则会出现“登录后不回跳/回跳失败”。

Android

  • 依赖:com.linecorp.linesdk:linesdk:5.11.1utssdk/app-android/config.json
  • Manifest:已包含 INTERNET / ACCESS_NETWORK_STATE,以及 Android 11+ queries(用于检测 LINE 是否安装)
  • 仍需在 LINE Developers Console 配置 Android 包名;如要上线发布版,请同时配置 release 签名摘要(SHA-1)

iOS

  • 依赖:CocoaPods LineSDKSwift 5.14.0(模块名为 LineSDK
  • 最低系统:iOS 13.0+(插件已设置 deploymentTarget: 13.0
  • Info.plist:已注入
    • URL Scheme:line3rdp.$(PRODUCT_BUNDLE_IDENTIFIER)
    • LSApplicationQueriesSchemes: lineauth2
  • 回调转发:已通过 UTSiOSHookProxy 转发 openURL/UniversalLink(无需手动改 AppDelegate)
  • 仍需在 LINE Developers Console 配置 iOS Bundle ID

错误码

errCode 含义
9010101 参数错误(如 channelId 为空)
9010102 未初始化/缺少 channelId
9010201 用户取消
9010202 未安装 LINE(onlyLineApp=true
9010301 登录进行中
9010401 网络错误
9010402 服务端错误
9010403 授权代理错误(Android AUTHENTICATION_AGENT_ERROR
9010404 SDK 内部错误
9010501 API 调用失败(profile/token 等)
9010601 无可用 token(未登录)
9010701 平台不支持

参考

  • LINE SDK Android:https://github.com/line/line-sdk-android
  • LINE SDK iOS Swift:https://github.com/line/line-sdk-ios-swift
  • UTS 插件开发:https://doc.dcloud.net.cn/uni-app-x/plugin/uts-plugin.html

隐私、权限声明

1. 本插件需要申请的系统权限列表:

Android: INTERNET, ACCESS_NETWORK_STATE;iOS: URL Scheme line3rdp.<BundleID> + LSApplicationQueriesSchemes(lineauth2)。

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

插件本身不收集数据;登录态/token 由 LINE SDK 存储在本地(随系统/应用环境而定)。

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

暂无用户评论。