iT邦幫忙

第 11 屆 iT 邦幫忙鐵人賽

1

今天要介紹的是 Line Bot 的邀請處理,LINE 提供了一些 Webhook 事件,讓我們可以在機器人被加好友、被封鎖、或被加入群組時,做一些相應的處理。

前兩項雖然和邀請無關,不過很常用到就一起介紹。

Webhook event:

  • Message event 訊息事件
  • Postback event 回呼事件
  • Follow event 追蹤事件
  • Unfollow event 封鎖事件
  • Join event 加入事件
  • Leave event 離開事件
  • Member join event 成員加入事件
  • Member leave event 成員離開事件

Webhook event 共用屬性

  • type: 事件類型。
  • mode: 通道狀態。
    active 通道處於活動狀態,Line Bot 可以正常發送訊息。
    standby (開發中) 通道處於等待狀態,Line Bot 不應回覆訊息。
  • timestamp: 事件發生的時間戳記 (milliseconds)。
  • source: # 事件來源 usergrouproom

# 事件來源

  • User 使用者

    • type: user
    • userId: 使用者代碼。
  • Group 群組

    • type: group
    • groupId: 群組代碼。
    • userId: 使用者代碼,只包含在 Message event 中
  • Room 聊天室

    • type: room
    • roomId: 聊天室代碼。
    • userId: 使用者代碼,只包含在 Message event 中

來源官方文件: #common-properties


1. Message event 訊息事件

  • type: 類型 message
  • replyToken: 回覆訊息用的 token。
  • message: 訊息物件,[Day15] 有詳細介紹。

來源官方文件: #message-event

程式碼:

protected override async Task OnMessageAsync(MessageEvent ev)
{
    await _messagingClient.ReplyMessageAsync(ev.ReplyToken,
        $"OnMessage 訊息事件\n" +
        $"類型: {ev.Type.ToString()}\n" +
        $"時間: {ev.Timestamp}\n" +
        $"來源類型: {ev.Source.Type.ToString()}\n" +
        $"頻道 ID: {ev.Source.Id}\n" +
        $"用戶 ID: {ev.Source.UserId}");
}

結果:

  • 一對一聊天

https://ithelp.ithome.com.tw/upload/images/20200118/20106865wMl92cegWh.jpg

  • 群組

https://ithelp.ithome.com.tw/upload/images/20200118/20106865z4bcWq4Snt.jpg

  • 聊天室

https://ithelp.ithome.com.tw/upload/images/20200118/20106865tYYmtt0DoC.jpg


2. Postback event 回呼事件

  • type: 類型 postback
  • replyToken: 回覆訊息用的 token。
  • postback.data: 事件附帶的資料。
  • postback.params: 時間選擇器附帶的資料,[Day14] 有詳細介紹。

來源官方文件: #postback-event

程式碼:

protected override async Task OnPostbackAsync(PostbackEvent ev)
{
    await _messagingClient.ReplyMessageAsync(ev.ReplyToken,
        $"OnPostback 回呼事件\n" +
        $"類型: {ev.Type.ToString()}\n" +
        $"時間: {ev.Timestamp}\n" +
        $"來源類型: {ev.Source.Type.ToString()}\n" +
        $"頻道 ID: {ev.Source.Id}\n" +
        $"用戶 ID: {ev.Source.UserId}\n" + 
        $"資料: {ev.Postback.Data}");
}

結果:

  • 一對一聊天

https://ithelp.ithome.com.tw/upload/images/20200118/20106865hrl11zUiw2.jpg

  • 群組

https://ithelp.ithome.com.tw/upload/images/20200118/20106865ynFzgRwPuG.jpg

  • 聊天室

https://ithelp.ithome.com.tw/upload/images/20200118/20106865KrIXEmsAh3.jpg


3. Follow event 追蹤事件

使用者加 Line Bot 好友時觸發,可以用來發送問候語。

  • type: 類型 follow
  • replyToken: 回覆訊息用的 token。

來源官方文件: #follow-event

程式碼:

protected override async Task OnFollowAsync(FollowEvent ev)
{
    await _messagingClient.ReplyMessageAsync(ev.ReplyToken,
        $"OnFollow 追蹤事件\n" +
        $"類型: {ev.Type.ToString()}\n" +
        $"時間: {ev.Timestamp}\n" +
        $"來源類型: {ev.Source.Type.ToString()}\n" +
        $"頻道 ID: {ev.Source.Id}\n" +
        $"用戶 ID: {ev.Source.UserId}");
}

結果:

https://ithelp.ithome.com.tw/upload/images/20200118/20106865lgwTDUFTim.jpg


4. Unfollow event 封鎖事件

  • type: 類型 unfollow

來源官方文件: #unfollow-event

程式碼:

protected override Task OnUnfollowAsync(UnfollowEvent ev)
{
    throw new Exception(
        $"OnUnfollow 封鎖事件\n" +
        $"類型: {ev.Type.ToString()}\n" +
        $"時間: {ev.Timestamp}\n" +
        $"來源類型: {ev.Source.Type.ToString()}\n" +
        $"頻道 ID: {ev.Source.Id}\n" +
        $"用戶 ID: {ev.Source.UserId}");
}

結果:

封鎖和離開事件沒有 replyToken,不能回覆訊息。

{
  "ClassName": "System.Exception",
  "Message": 
    "OnUnfollow 封鎖事件
     類型: Unfollow
     時間: 1579238219795
     來源類型: User
     頻道 ID: Ua2e462c39f1ca8490***************
     用戶 ID: Ua2e462c39f1ca8490***************"
}

5. Join event 加入事件

Line Bot 加入群組或聊天室時觸發,可以用來發送問候語。

觸發時機分別是:

  • 群組: 用戶邀請 Line Bot 加入時馬上觸發。
  • 聊天室: Line Bot 加入聊天室後,在第一個事件觸發時,例如: 第一個用戶發送訊息或其他使用者加入。

如果聊天室本來已經存在,這時加入 Line Bot 也會馬上觸發加入事件。


  • type: 類型 join
  • replyToken: 回覆訊息用的 token。

來源官方文件: #leave-event

程式碼:

protected override async Task OnJoinAsync(JoinEvent ev)
{
    await _messagingClient.ReplyMessageAsync(ev.ReplyToken,
        $"OnJoin 加入事件\n" +
        $"類型: {ev.Type.ToString()}\n" +
        $"時間: {ev.Timestamp}\n" +
        $"來源類型: {ev.Source.Type.ToString()}\n" +
        $"頻道 ID: {ev.Source.Id}\n" +
        $"用戶 ID: {ev.Source.UserId}");
}

結果:

  • 加入群組

https://ithelp.ithome.com.tw/upload/images/20200118/20106865BsDykUqxkQ.jpg

  • 加入聊天室

https://ithelp.ithome.com.tw/upload/images/20200118/20106865etV3Emv5GO.jpg

  • 聊天室已存在的情況加入

https://ithelp.ithome.com.tw/upload/images/20200118/201068655EYFTeD5ie.jpg


6. Leave event 離開事件

Line Bot 離開群組或聊天室時觸發。

  • type: 類型 leave

來源官方文件: #leave-event

程式碼:

protected override Task OnLeaveAsync(LeaveEvent ev)
{
    throw new Exception(
        $"OnLeave 離開事件\n" +
        $"類型: {ev.Type.ToString()}\n" +
        $"時間: {ev.Timestamp}\n" +
        $"來源類型: {ev.Source.Type.ToString()}\n" +
        $"頻道 ID: {ev.Source.Id}\n" +
        $"用戶 ID: {ev.Source.UserId}");
}

結果:

  • 離開群組
{
  "ClassName": "System.Exception",
  "Message": 
    "OnLeave 離開事件
     類型: Leave
     時間: 1579239093329
     來源類型: Group
     頻道 ID: C98a80cf5620b0b199***************
     用戶 ID: "
}
  • 離開聊天室
{
  "ClassName": "System.Exception",
  "Message": 
    "OnLeave 離開事件
     類型: Leave
     時間: 1579247615402
     來源類型: Room
     頻道 ID: Rf1fe692e16a6bab6cf**************
     用戶 ID: "
}

7. Member join event 成員加入事件

用戶加入群組或聊天室時觸發。

  • type: 類型 memberJoined
  • replyToken: 回覆訊息用的 token。
  • joined.members: # 事件來源 User 陣列。

來源官方文件: #member-joined-event

程式碼:

protected override async Task OnMemberJoinAsync(MemberJoinEvent ev)
{
    await _messagingClient.ReplyMessageAsync(ev.ReplyToken,
        $"OnMemberJoin 成員加入事件\n" +
        $"類型: {ev.Type.ToString()}\n" +
        $"時間: {ev.Timestamp}\n" +
        $"來源類型: {ev.Source.Type.ToString()}\n" +
        $"頻道 ID: {ev.Source.Id}\n" +
        $"用戶 ID: {ev.Source.UserId}\n" +
        $"加入用戶ID: {string.Join(",\n", ev.Joined.Members.Select(it => it.UserId))}");
}

結果:

  • 成員加入群組

https://ithelp.ithome.com.tw/upload/images/20200118/20106865l0yAj4MILG.jpg

  • 成員加入聊天室

https://ithelp.ithome.com.tw/upload/images/20200118/201068659QQENuKnll.jpg


8. Member leave event 成員離開事件

用戶離開群組或聊天室時觸發。

  • type: 類型 memberLeft
  • left.members: # 事件來源 User 陣列。

來源官方文件: #member-left-event

程式碼:

protected override Task OnMemberLeaveAsync(MemberLeaveEvent ev)
{
    throw new Exception(
        $"OnMemberLeave 成員離開事件\n" +
        $"類型: {ev.Type.ToString()}\n" +
        $"時間: {ev.Timestamp}\n" +
        $"來源類型: {ev.Source.Type.ToString()}\n" +
        $"頻道 ID: {ev.Source.Id}\n" +
        $"用戶 ID: {ev.Source.UserId}\n" +
        $"離開用戶ID: {string.Join(",\n", ev.Left.Members.Select(it => it.UserId))}");
}

結果:

  • 成員離開群組
{
  "ClassName": "System.Exception",
  "Message": 
    "OnMemberLeave 成員離開事件
     類型: MemberLeft
     時間: 1579316642116
     來源類型: Group
     頻道 ID: C98a80cf5620b0b199***************
     用戶 ID: 
     離開用戶ID: Ua2e462c39f1ca8490***************"
}
  • 成員離開聊天室

{
  "ClassName": "System.Exception",
  "Message": 
    "OnMemberLeave 成員離開事件
     類型: MemberLeft
     時間: 1579317849823
     來源類型: Room
     頻道 ID: Rf1fe692e16a6bab6cf**************
     用戶 ID: 
     離開用戶ID: Ua2e462c39f1ca8490***************"
}

# 如何讓 Line Bot 自己退出群組或聊天室

因為聊天室不能把機器人退出,所以通常會實作這個功能。

var regex = new Regex(@"^離開$", RegexOptions.IgnoreCase);
if (regex.IsMatch(textMessage.Text))
{
    await _messagingClient.ReplyMessageAsync(ev.ReplyToken, "掰掰~");

    if (ev.Source.Type == EventSourceType.Group)
        //離開群組
        await _messagingClient.LeaveFromGroupAsync(ev.Source.Id);
    if (ev.Source.Type == EventSourceType.Room)
        //離開聊天室
        await _messagingClient.LeaveFromRoomAsync(ev.Source.Id);
}

結果:

https://ithelp.ithome.com.tw/upload/images/20200118/20106865YfpTfbU4q9.jpg


# 取得用戶個人資訊

可以取得 Line Bot 好友的個人資訊。

  • displayName: 用戶名稱。
  • statusMessage: 狀態資訊。
  • pictureUrl: 照片網址。

來源官方文件: #get-profile

//參數 userId
//回傳 UserProfile
Task<UserProfile> GetUserProfileAsync(string userId);
if (ev.Source.Type == EventSourceType.User)
{
    var userProfile = await _messagingClient
        .GetUserProfileAsync(ev.Source.UserId);

    await _messagingClient.ReplyMessageAsync(ev.ReplyToken,
        $"DisplayName: {userProfile.DisplayName}\n" +
        $"StatusMessage: {userProfile.StatusMessage}\n" +
        $"PictureUrl: {userProfile.PictureUrl}");
}

結果:

https://ithelp.ithome.com.tw/upload/images/20200118/20106865bUS0xvwmnq.jpg


# 取得群組內用戶個人資訊

可以取得群組內用戶的個人資訊,被封鎖或未加好友的用戶資訊也可以取得,
get-profile 只能取得好友的。

  • displayName: 用戶名稱。
  • statusMessage: 狀態資訊。
  • pictureUrl: 照片網址。

來源官方文件: #get-group-member-profile

//參數 groupId
//參數 userId
//回傳 UserProfile
Task<UserProfile> GetGroupMemberProfileAsync(string groupId, string userId);
if (ev.Source.Type == EventSourceType.Group)
{
    var userProfile = await _messagingClient
        .GetGroupMemberProfileAsync(ev.Source.Id, ev.Source.UserId);

    await _messagingClient.ReplyMessageAsync(ev.ReplyToken,
        $"DisplayName: {userProfile.DisplayName}\n" +
        $"StatusMessage: {userProfile.StatusMessage}\n" +
        $"PictureUrl: {userProfile.PictureUrl}");
}

# 取得聊天室內用戶個人資訊

可以取得聊天室內用戶的個人資訊,被封鎖或未加好友的用戶資訊也可以取得,
get-profile 只能取得好友的。

  • displayName: 用戶名稱。
  • statusMessage: 狀態資訊。
  • pictureUrl: 照片網址。

來源官方文件: #get-room-member-profile

//參數 roomId
//參數 userId
//回傳 UserProfile
Task<UserProfile> GetRoomMemberProfileAsync(string roomId, string userId);
if (ev.Source.Type == EventSourceType.Room)
{
    var userProfile = await _messagingClient
        .GetRoomMemberProfileAsync(ev.Source.Id, ev.Source.UserId);

    await _messagingClient.ReplyMessageAsync(ev.ReplyToken,
        $"DisplayName: {userProfile.DisplayName}\n" +
        $"StatusMessage: {userProfile.StatusMessage}\n" +
        $"PictureUrl: {userProfile.PictureUrl}");
}

# 取得群組或聊天室內所有用戶的 ID

此功能需要 Premium 帳號才能使用

可以取得群組或聊天室內所有用戶的 ID。

  • memberIds: 用戶 ID,一次最多只能取得 100 筆資料。
  • next: 用來取得下一組資料的 token,如果 memberIds 未被取完,會附帶此參數。

來源官方文件: #get-group-member-user-ids

  • 群組
//參數 groupId
//參數 continuationToken <- 代入上方的 next 參數
//回傳 GroupMemberIds
Task<GroupMemberIds> GetGroupMemberIdsAsync(string groupId, string continuationToken);
//取得群組內所有用戶的 ID
if (ev.Source.Type == EventSourceType.Group)
{
    var userIds = new List<string>();
    var continuationToken = null as string;
    do
    {
        var groupMemberIds = await _messagingClient
            .GetGroupMemberIdsAsync(ev.Source.Id, continuationToken);

        continuationToken = groupMemberIds.Next;
        userIds.AddRange(groupMemberIds.MemberIds);

    } while (continuationToken != null);
}
  • 聊天室
//參數 roomId
//參數 continuationToken <- 代入上方的 next 參數
//回傳 GroupMemberIds
Task<GroupMemberIds> GetRoomMemberIdsAsync(string roomId, string continuationToken);
//取得群組內所有用戶的 ID
if (ev.Source.Type == EventSourceType.Room)
{
    var userIds = new List<string>();
    var continuationToken = null as string;
    do
    {
        var groupMemberIds = await _messagingClient
            .GetRoomMemberIdsAsync(ev.Source.Id, continuationToken);

        continuationToken = groupMemberIds.Next;
        userIds.AddRange(groupMemberIds.MemberIds);

    } while (continuationToken != null);
}

作者也有寫好可以直接取得所有用戶資訊的方法

//取得群組內所有用戶的個人資訊
var userProfiles = await _messagingClient
    .GetGroupMemberProfilesAsync(ev.Source.Id);
//取得聊天室內所有用戶的個人資訊
var userProfiles = await _messagingClient
    .GetRoomMemberProfilesAsync(ev.Source.Id);

結語

Line Bot 的基本功能介紹在這裡告一段落,接下來會玩一些比較複雜的 API,例如 Notify、Login、LIFF、等等...

下一篇要製作語音機器人,今天就到這裡,感謝大家觀看。 (´・ω・`)


上一篇
[Day15] LINE Bot 取得用戶上傳的內容 - Message Event
下一篇
[Day17] 如何製作 LINE Bot 語音機器人 - Azure 語音服務
系列文
Line Bot 心得分享 LineMessagingApi + LUIS + BotFramework27

尚未有邦友留言

立即登入留言