2023年11月1日水曜日

Plurk Custom EmotionIcon : Chrome / Firefox web extension 開發筆記 / oAuth流程與參數解說

Plurk的自訂表符,未使用噗幣的帳號,上限是60個,筆者覺得不夠用。當然是建議購買噗幣支持官方營運,就可以擴充上限至600個。
不過管理表符的功能還是需要的。嗯嗯...
原本是打算修改小耀博士開發的噗浪卡卡,之前有改出一版,不過後來因為chrome擋掉一些之前能做的動作(像是動態插入程式碼然後執行),評估後覺得修改困難,決定寫新的。


進入點:manifest.json與javascript相關

第一步:先看入門文件。

https://developer.chrome.com/docs/extensions/mv3/getstarted/

筆者覺得相當合用。下面只列出需要注意的部分。

manifest v3跟v2 有參數的差異。像是最難處理的permissions,v3分成「optional_permissions」與「host_permissions」。

「browser_action」在v3改為「action」。api也從v2的「browser.browserAction」改名為「browser.action」。
要注意的是api文字定義不通用。宣告v2只能用v2的定義「browser.browserAction」,宣告v3只能用v3的定義「browser.action」。

firefox跟chrome也有參數的差異。像是firefox用「background.scripts = [...]」的格式,chrome卻是用「backgound.service_worker = “filename.js”」的格式。
加上雙方都不允許自身未定義的keyword存在,
例如chrome不允許「browser_specific_settings」的參數,
導致manifest不能一份通用兩邊。

這次開發遇到最大的困難是firefox的檔案儲存功能。
firefox的可用程式碼分成下面幾種:

  • content_script:可以注入正在使用的網頁。browser api的限制比較多。
  • background_script:沒有browser api的限制,但是不能對正在使用的網頁進行html tag操作。也不能使用alert / confirm / prompt等等預設對話框。因此基本的設計方式就是在content_script裡面進行ui操作,需要突破browser api限制的動作丟到背景執行。

    背景執行的動作雖然會被瀏覽器暫停,有定義addlistener()等等event driven的設計的話,只要有event送過去,背景動作就會被喚醒。不用擔心會有重啟或是初始化的問題
  • action popup / sidebar:可在瀏覽頁面時同時顯示。可以使用script,但是需遵循content security policy。基本上就是不能使用script tag,所以網頁常用的load script手段都需要把程式碼下載之後跟套件一起打包,記述在manifest的content_scripts.js 參數裡面讓瀏覽器幫你載入。在html記述<script>也會直接無效。
  • options_ui(在擴充套件的設定頁,以html load script),也沒有browser api限制。但是「要使用者點擊打開」之後才會執行。

「content_script」可用的browser api:

https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Content_scripts#webextension_apis

「background_script」「options_ui」可用的browser api:

https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Background_scripts

搜尋了幾十頁,大概是關鍵字不對,得不到正確答案。跑去stack overflow才找到。
其實是列在mozilla的擴充套件介紹的一開始concepts的地方。算筆者沒有從頭讀吧。因為先讀了chrome的介紹,就懶了...

在firefox的擴充套件開發遇到的限制:

  • content_script不可使用downloads api(就算有允許權限也一樣)
  • content_script不可使用permissions api(就算是經由form的submit也一樣)。
  • browser.permissions.request() 雖然在sidebar / popup / option-ui 可以使用,但是「只允許經由使用者操作啟動」。
    而且「必須使用<form>tag的submit功能實作」,不能使用html tag event,例如onclick實作...
    會獲得錯誤訊息「permissions.request may only be called from a user input handler」
    另外,以submit實作的時候,一定要記得在event function的第一行指定「ev.preventDefault();」。不然預設的頁面重刷動作會導致下載失敗。

    例外:可以用在「browser.action.onClicked.addListener」的定義。感覺有條件限制有點複雜。應該要有文件list會比較好。也許還有其他地方可以...
  • background_script可以使用session / local storage。但是跟網頁的資料是各自獨立的。與content_script(網頁的ui注入的script)溝通,需要使用browser.runtime.onMessage()做溝通。也許有其他方式,這邊不研究。

 

chrome的檔案儲存相對簡單。使用以下的一連串動作就解決了:

window.showSaveFilePicker(filePickerOpt)
    .then((newHandle) => newHandle.createWritable())
    .then((writableStream) => writableStream.write(JSON.stringify(data, null, 2)))
    .then((writableStream) => writableStream.close())
    .then((_) => {
        alert('ok');
    })
    .catch((e) => {
        alert('canceled');
    });

 

如何在正在操作的網頁插入擴充套件的icon/image:似乎是沒有直接的方法。
目前是採用把icon轉成base64 data string的方式處理。
參考網址: https://www.atatus.com/tools/image-to-url