第12 屆iT邦幫忙鐵人賽系列文章 (Day14)
在 Line 的官方帳號可以設定進入時的選單,讓使用者快速點選,設定方式可以從官方帳號後台(有既定的範本可以參考),或者是用程式自己指定(可以自己控制圖片的座標&設定點選區塊),以下分別介紹
從官方帳號後台
這應該是最方便的方式了,Line 已經提供了一些範本和設計規範,只要照著範本製作一個圖片,並設定每個區塊要觸發的事件,即可完成一個圖文選單
進入 https://manager.line.biz/ 選擇圖文選單 => 建立 => 設計規範 => 下載範本,(或者直接點此下載),下載後會是一個壓縮檔,今天來用這個範例做修改

我們用 PhotoShop 改成我們要的圖片 (這就不介紹啦) https://imgur.com/ev4LQzp.jpg
上傳圖片,並設定 A.B.C 所要觸發的文字

這樣就完成了,是不是很方便阿

從程式指定 Rich Menu
程式就沒有用 Business 後台直接上傳圖片來得那麼方便,但程式可以做到極彈性,它可以自訂圖片的座標來設定 click 的範圍,可以針對使用者來動態的切換 Rich Menu 等等…。Rich Menu 所牽扯的 Api 有點多,故先整理今天會實作的 Api 清單如下
Get rich menu list:取得此 chatbot 已註冊的 Rich Menu 清單 Upload rich menu image:設定 Rich Menu 的圖片 Set default rich menu:設定所檢視的 Rich Menu
新增 LineRichMenuUtility.cs
之前 Message API 我們做了 一個 Utility ,Rich Menu 我們也新增一個
    public class LineRichMenuUtility
    {
    private readonly string accessToken;
    private static string lineMessageApiBaseUrl = "https://api.line.me/v2/bot/richmenu";
    private static string lineMessageApiBaseUrlForAllUser = "https://api.line.me/v2/bot/user/all/richmenu";
    public LineRichMenuUtility(IOptions<LineSetting> lineSetting)
    {
    accessToken = lineSetting.Value.ChannelAccessToken;
    }
    ....
    }
Get rich menu list:取得此 chatbot 已註冊的 Rich Menu 清單
RichMenuResponse 這個 class 內容來自於這個文件
    public async Task<RichMenuResponse> GetRichMenuListAsync()
    {
    using (var httpClient = new HttpClient())
    {
    using (var request = new HttpRequestMessage(new HttpMethod("GET"), $"{lineMessageApiBaseUrl}/list"))
    {
    request.Headers.TryAddWithoutValidation("Authorization", $"Bearer {accessToken}");
    var response = await httpClient.SendAsync(request);
    var result = await response.Content.ReadAsStringAsync();
    var richMenuRes = JsonConvert.DeserializeObject<RichMenuResponse>(result);
    return richMenuRes;
    }
    }
    }
Upload rich menu image:設定 Rich Menu 的圖片
    public async Task UploadRichMenuImage(string imgUrl, string richMenuId)
    {
    using (var httpClient = new HttpClient())
    {
    using (var request = new HttpRequestMessage(new HttpMethod("POST"), $"lineMessageApiBaseUrl/{richMenuId}/content"))
    {
    request.Headers.TryAddWithoutValidation("Authorization", $"Bearer {accessToken}");
    var imgBytes = GetImage(imgUrl);
    request.Content = new ByteArrayContent(imgBytes);
    request.Content.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json");
    var response = await httpClient.SendAsync(request);
    var results = await response.Content.ReadAsStringAsync();
    };
    }
    }
    private byte[] GetImage(string url)
    {
    var request = (HttpWebRequest)WebRequest.Create(url);
    var response = (HttpWebResponse)request.GetResponse();
    using (Stream dataStream = response.GetResponseStream())
    {
    if (dataStream == null)
    return null;
    using (var sr = new BinaryReader(dataStream))
    {
    byte[] bytes = sr.ReadBytes(100000000);
    return bytes;
    }
    }
    }
Set default rich menu:設定預設的 Rich Menu
CreateRichmenu 這個 class 內容來自於這個文件
自己用程式定義的麻煩點就在這,要設長寬和這種座標與Action,但未來可以考慮將一些常用範本用程式封裝起來,直接使用
    public async Task<Richmenu> SetDefaultRichMenuAsync()
    {
    using (var httpClient = new HttpClient())
    {
    using (var request = new HttpRequestMessage(new HttpMethod("POST"), lineMessageApiBaseUrl))
    {
    request.Headers.TryAddWithoutValidation("Authorization", $"Bearer {accessToken}");
    var defaultRichMenu = new CreateRichmenu();
    defaultRichMenu.size = new CreateSize(1200, 810);
    defaultRichMenu.selected = true;
    defaultRichMenu.name = "Default RichMenu";
    defaultRichMenu.chatBarText = "Kyle's Wedding";
    defaultRichMenu.areas = new List<CreateArea>()
    {
    new CreateArea(boundx:0,boundy:0,width:800,height:810, _action: new MessageAction("婚紗輪播"))
    };
    var postJson = JsonConvert.SerializeObject(defaultRichMenu, new JsonSerializerSettings
    {
    NullValueHandling = NullValueHandling.Ignore,
    ContractResolver = new DefaultContractResolver
    {
    NamingStrategy = new CamelCaseNamingStrategy()
    }
    });
    request.Content = new StringContent(postJson);
    request.Content.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json");
    var response = await httpClient.SendAsync(request);
    var results = await response.Content.ReadAsStringAsync();
    var richmenu = JsonConvert.DeserializeObject<Richmenu>(results);
    return richmenu;
    };
    }
    }
Set default rich menu:設定所"指定"的 Rich Menu
    public async Task SetDefaultRichMenuAsync(string richId)
    {
    using (var httpClient = new HttpClient())
    {
    using (var request = new HttpRequestMessage(new HttpMethod("POST"), $"{lineMessageApiBaseUrlForAllUser}/{richId}"))
    {
    request.Headers.TryAddWithoutValidation("Authorization", $"Bearer {accessToken}");
    var response = await httpClient.SendAsync(request);
    var results = await response.Content.ReadAsStringAsync();
    }
    }
    }
回到 Api Controller,我們在 app 啟動的時候給設定 Rich Menu

InitRichMenu 實作
    public async Task InitRickMenu()
    {
    var rickResponse = await lineRichMenuUtility.GetRichMenuListAsync();
    if(rickResponse.richmenus.Count == 0)
    {
    // 沒有取到任何 Rich Menu,設定預設
    var richMenu = await lineRichMenuUtility.SetDefaultRichMenuAsync();
    await lineRichMenuUtility.UploadRichMenuImage("https://i.imgur.com/ev4LQzp.jpg", richMenu.richMenuId);
    }
    else
    {
    // 取得預設並設定該 Rich Menu
    var defaultRich = rickResponse.richmenus.First(c => c.name == "Default RichMenu");
    await lineRichMenuUtility.SetDefaultRichMenuAsync(defaultRich.richMenuId);
    }