Lala Code

Lala 的前端大補帖,歡迎一起鑽研前端技術😊

0%

LINE LIFF 功能介紹教學,綁定用戶資料,傳送分享訊息

Imgur

什麼是LINE LIFF?

LIFF 是一種可以在 Line 中直接操作網頁的平台,全名為 LINE Front-end Framework,是 LINE 的前端框架。能取得用戶的唯一辨識碼 UserId、公開資料,這讓用戶可以不必手動輸入資料,就可以直接綁定用戶在 LINE 的個人資料,除此之外,還有傳送訊息、分享訊息給好友的功能,下面將會一一介紹

使用 LIFF 前請先在 LINE LIFF 後台 建立 LINE Login



安裝 LIFF SDK

依自己喜好引入 LIFF SDK

CDN

1
<script src="https://static.line-scdn.net/liff/edge/2/sdk.js"></script>

NPM

1
npm i @line/liff


LIFF 初始化

init

開始寫 LIFF 的程式時,第一步要先 init 初始化,需要帶入 LIFF ID,LIFF ID 預設為 null

在 LIFF 後台的地方會顯示 LIFF ID

liffID.jpg

init 後才可以開始使用 LIFF 的各項函式

由於需要 init 後才能執行其他動作,所以是使用 Promise,之後要執行的程式再寫在 then 裡面

1
2
3
4
5
6
7
8
9
10
11
12
13
import liff from '@line/liff';
const liffId = '1657706202-XXXXXXXX';

liff.init({
liffId: liffId
}).then(function() {
console.log('LIFF init');

// 這邊開始寫使用其他功能

}).catch(function(error) {
console.log(error);
});

或是也可使用 ready 來執行接下來的動作,liff.ready 為 LIFF SDK 提供的屬性,也是一個 Promise 物件,會在 liff.init 完成後執行

1
2
3
4
5
6
7
liff.init({
liffId: liffId
})

liff.ready.then(function() {
// 這邊開始寫使用其他功能
})

當然,你也可以使用 async await 的方式,並用 try catch 除錯

1
2
3
4
5
6
7
8
9
10
11
12
const liffInit = async () => {
const liffId = '1657706202-XXXXXXXX';

try {
await liff.init({ liffId: liffId });

// 這邊開始寫使用其他功能

} catch (err) {
alert(err);
}
}

LIFF 取得環境資訊

liff.getOS()

取得使用者作業系統:ios (iOS 或 iPadOS)、android、web(非 ios、android 的作業系統)

1
2
const OS = liff.getOS();
// ios || android || web

liff.getLanguage()

頁面中的語系(lang)

1
const language = liff.getLanguage();

liff.getVersion()

LIFF SDK 的版本

1
const version = liff.getVersion();

liff.getLineVersion()

使用者的 LINE 版本

1
const lineVersion = liff.getLineVersion();

liff.getContext()

使用者功能相關資訊、liffId

1
const context = liff.getContext();

liff.isInClient()

目前 LIFF 是否在 LINE App 中開啟

1
2
const isInClient = liff.isInClient();
// true || false

liff.isLoggedIn()

使用者是否登入 LINE 帳號

1
2
const isLoggedIn = liff.isLoggedIn();
// true || false

liff.isApiAvailable()

確認目前環境是否可以使用 API

1
2
3
4
5
6
7
8
9
10
11
12
13
if (liff.isApiAvailable('shareTargetPicker')) {
liff.shareTargetPicker([
{
type: "text",
text: "Hello, World!"
}
])
.then(
console.log("ShareTargetPicker was launched")
).catch(function(res) {
console.log("Failed to launch ShareTargetPicker")
})
}

LIFF 驗證

liff.login()

登入 LIFF

登入、登出 LINE 的功能只能在外部瀏覽器時有作用,

在 LIFF 瀏覽器中,liff.init 後會自動登入

1
liff.login();

登入成功後會導向 LIFF 後台的 Endpoint URL

endpoint.jpg

liff.logout()

登出 LIFF

1
liff.logout();

liff.getAccessToken()

取得 access token

access token 在發出後 12 小時內有效。 當用戶關閉應用程序時,access token 將被撤銷。

1
2
3
4
5
6
7
8
9
10
const accessToken = liff.getAccessToken();
if (accessToken) {
fetch("https://api...", {
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${accessToken}`,
},
//...
});
}

liff.getIDToken()

取得 LIFF ID token

1
2
3
4
5
6
7
liff.init({
liffId: "123456-abcedfg", // Use own liffId
})
.then(() => {
const idToken = liff.getIDToken();
console.log(idToken); // print raw idToken object
});

liff.getDecodedIDToken()

解碼 ID token 的資料

可取得使用者的 email、token 到期日、暱稱、頭像

後台 Basic settings 的 Email address permission 需 Applied

LIFF 的設定,Scopes 的「email*」要打勾

1
2
3
4
5
6
7
8
liff
.init({
liffId: "123456-abcedfg", // Use own liffId
})
.then(() => {
const idToken = liff.getDecodedIDToken();
console.log(idToken); // print decoded idToken object
});

liff.permission.query()

1
2
3
liff.permission.query("profile").then((permissionStatus) => {
// permissionStatus = { state: 'granted' }
});

liff.permission.requestAll()

1
2
3
4
5
liff.permission.query("profile").then((permissionStatus) => {
if (permissionStatus.state === "prompt") {
liff.permission.requestAll();
}
});

LIFF 取得使用者公開資料

liff.getProfile()

可取得 userId、暱稱、頭像路徑、狀態消息。

LIFF 後台的「Scopes」要設定開啟 profile, openid

1
const profile = liff.getProfile()

回應的值有以下:

  • userId: “123456789…”
  • displayName: “Lala”
  • pictureUrl: “https://xxxx.com”
  • statusMessage: “LIFF is great!”

liff.getFriendship()

獲取用戶與 LINE 官方帳號是否為好友狀態

1
2
3
4
5
liff.getFriendship().then((data) => {
if (data.friendFlag) {
// something you want to do
}
});

開啟、關閉 LIFF 視窗

liff.openWindow()

開啟 LIFF 視窗

1
2
3
4
liff.openWindow({
url: "https://line.me",
external: true,
});
  • url:網址連結,必填
  • external:是否允許外部瀏覽器開啟,預設 false

liff.closeWindow()

關閉 LIFF 視窗

關閉 LIFF 的功能只能在 LINE App 開啟 LIFF 的狀況下才有作用。

1
liff.closeWindow();

LIFF 傳送訊息

liff.sendMessages()

傳給打開這個 LIFF 的當下群組、好友、機器人、LINE@

這個傳訊息功能,後台的「chat_message.write」必須要打勾才能使用。

在外部瀏覽器無法使用此功能,要用 LINE App 內開啟 LIFF 才能用。

使用者在登入 LINE 帳號時,「傳送訊息至聊天室」這項必須要是「許可」的才能使用。

1
2
3
4
5
6
7
8
9
10
11
liff.sendMessages([
{
type: 'text',
text: 'Hello, World!'
}
]).then(function(res) {
console.log(res)
})
.catch(function(error) {
console.log(error);
});

liff.shareTargetPicker()

傳給指定好友、群組

這個傳訊息功能,後台的「shareTargetPicker」必須要打勾才能使用。

使用者在登入 LINE 帳號時,「傳送訊息至聊天室」這項必須要是「許可」的才能使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
liff.shareTargetPicker(
[
{
type: "text",
text: "Hello, World!",
},
],
{
isMultiple: true,
}
)
.then(function (res) {

// 發送成功後要做的事

}).catch(function (error) {
console.log('something wrong happen')
})
}
  • isMultiple:是否可以多選

不管是 sendMessages 或 shareTargetPicker 訊息的表現都支援多種方式

  • 文字訊息 (Text message)
  • 貼圖訊息 (Sticker message)
  • 圖片訊息 (Image message)
  • 影片訊息 (Video message)
  • 音檔訊息 (Audio message)
  • 位置訊息 (Location message)
  • 模板訊息 (Template message)
  • Flex 訊息 (Flex Message)

文字訊息 (Text message)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{
"type": "text",
"text": "Hello, world"
},
{
"type": "text",
"text": "$ LINE emoji $",
"emojis": [
{
"index": 0,
"productId": "5ac1bfd5040ab15980c9b435",
"emojiId": "001"
},
{
"index": 13,
"productId": "5ac1bfd5040ab15980c9b435",
"emojiId": "002"
}
]
}
  • type(String) :類型 (必填)
  • text(String) :文字 (必填),最多5000字可包含 emojis
  • emojis :最多 20 個
    • index:位置索引
    • productId(String):Product ID
    • emojiId(String):Emoji ID

productIdemojiId 可參考List of available LINE emojis


貼圖訊息 (Sticker message)

1
2
3
4
5
{
"type": "sticker",
"packageId": "446",
"stickerId": "1988"
}
  • type (String):類型 (必填)
  • packageId(String) :Package ID (必填)
  • stickerId (String):Sticker ID (必填)

packageIdstickerId 可參考 List of available stickers


圖片訊息 (Image message)

1
2
3
4
5
{
"type": "image",
"originalContentUrl": "https://example.com/original.jpg",
"previewImageUrl": "https://example.com/preview.jpg"
}
  • type(String):類型 (必填)
  • originalContentUrl(String) :圖片路徑 JPG、JPEG、PNG,文件最大 10 MB (必填)
  • previewImageUrl(String):縮圖路徑 JPG、JPEG、PNG,文件最大 1 MB (必填)

影片訊息 (Video message)

1
2
3
4
5
6
{
"type": "video",
"originalContentUrl": "https://example.com/original.mp4",
"previewImageUrl": "https://example.com/preview.jpg",
"trackingId": "track-id"
}
  • type(String):類型 (必填)
  • originalContentUrl(String):影片路徑 mp4,文件最大 200 MB (必填)
  • previewImageUrl(String):縮圖路徑 JPG、JPEG、PNG,文件最大 1 MB (必填)
  • trackingId(String):用戶播完影片後,用於識別影片的 ID

音檔訊息 (Audio message)

1
2
3
4
5
{
"type": "audio",
"originalContentUrl": "https://example.com/original.m4a",
"duration": 60000
}
  • type(String):類型 (必填)
  • originalContentUrl(String):音檔路徑 m4a,文件最大 200 MB (必填)
  • duration:音檔長度毫秒(必填)

位置訊息 (Location message)

1
2
3
4
5
6
7
{
"type": "location",
"title": "my location",
"address": "1-6-1 Yotsuya, Shinjuku-ku, Tokyo, 160-0004, Japan",
"latitude": 35.687574,
"longitude": 139.72922
}
  • type(String):類型 (必填)
  • title(String):標題,最多 100 字元
  • address(String):地址,最多 100 字元
  • latitude(Decimal**)**:緯度
  • longitude(Decimal**)**:經度

模板訊息 (Template message)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
{
"type": "template",
"altText": "This is a buttons template",
"template": {
"type": "buttons",
"thumbnailImageUrl": "https://example.com/bot/images/image.jpg",
"imageAspectRatio": "rectangle",
"imageSize": "cover",
"imageBackgroundColor": "#FFFFFF",
"title": "Menu",
"text": "Please select",
"defaultAction": {
"type": "uri",
"label": "View detail",
"uri": "http://example.com/page/123"
},
"actions": [
{
"type": "uri",
"label": "View detail",
"uri": "http://example.com/page/123"
}
]
}
}

actions 僅能使用 uri 類型


Flex 訊息 (Flex Message)

可自行客製版型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
{
"type": "flex",
"altText": "this is a flex message",
"contents": {
"type": "bubble",
"body": {
"type": "box",
"layout": "vertical",
"contents": [
{
"type": "text",
"text": "hello"
},
{
"type": "text",
"text": "world"
}
]
}
}
}
  • type(String):類型 (必填)
  • altText:通知推播文字,最多 400 字元 (必填)
  • contents:Flex Message container

可於 FLEX MESSAGE SIMULATOR 製作


LIFF 連結

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// For example, if the endpoint URL of the LIFF app
// is https://example.com/path1?q1=v1
// and its LIFF ID is 1234567890-AbcdEfgh
liff.permanentLink
.createUrlBy("https://example.com/path1?q1=v1")
.then((permanentLink) => {
// https://liff.line.me/1234567890-AbcdEfgh
console.log(permanentLink);
});

liff.permanentLink
.createUrlBy("https://example.com/path1/path2?q1=v1&q2=v2")
.then((permanentLink) => {
// https://liff.line.me/1234567890-AbcdEfgh/path2?q=2=v2
console.log(permanentLink);
});

liff.permanentLink
.createUrlBy("https://example.com/")
.catch((error) => {
// Error: currentPageUrl must start with endpoint URL of LIFF App.
console.log(error);
});

取得當下的網址

1
const myLink = liff.permanentLink.createUrl();

網址上要加入其他參數

1
2
liff.permanentLink.setExtraQueryParam("user_tracking_id=8888");
const myLink = liff.permanentLink.createUrl();

LIFF 打開 QR Code 掃描器

liff.scanCodeV2()

打開掃描器

後台的 Scan QR 要開啟才能使用

1
2
3
4
5
6
liff.scanCodeV2().then((result) => {
// result = { value: "" }
})
.catch((error) => {
console.log("error", error);
});

結語

常常在生活中會開啟 LINE 的瀏覽器,原來很多都是用 LIFF 做到的,玩起來滿有趣的!
LINE 還有好多其他功能,改天有機會再來研究看看😀


REFERENCE

LIFF v2 API reference
LIFF v2 基本使用筆記及範例



Hey!想學習更多前端知識嗎?

最近 Lala 開了前端課程 👉【實地掌握RWD - 12小時新手實戰班】👈
無論您是 0 基礎新手,又或是想學 RWD 的初學者,
我們將帶你從零開始,深入了解並掌握 RWD 響應式網頁設計的核心技術,快來一起看看吧 😊



🚀線上課程分享

線上課程可以加速學習的時間,省去了不少看文件的時間XD,以下是我推薦的一些課程
想學習更多關於前後端的線上課程,可以參考看看。

Hahow

Hahow 有各式各樣類型的課程,而且是無限次數觀看,對學生或上班族而言,不用擔心被時間綁住



六角學院

如果你是初學者,非常推薦六角學院哦!
剛開始轉職也是上了六角的課,非常的淺顯易懂,最重要的是,隨時還有線上的助教幫你解決問題!


Udemy

Udemy 裡的課程非常的多,品質普遍不錯,且價格都滿實惠的,CP值很高!
也是很多工程師推薦的線上課程網站。
❤️