Stark Wong 的個人開發網站
 


 此頁面:更新於 2019 年 5 月 2 日 12 時 04 分 09 秒,頁面處理需時 0.0009 秒
 網站內容版權所有(C)Stark Wong。頁面(不包括檔案)可自由連結。網站系統版本 1.90-AngularJSBase (2015/9/27)
 
網站地圖

Notice: Undefined variable: row in /var/www/html/blog.inc.php on line 22
iOS + Android 的 IMA SDK 與 Safe Area Insets

最近在為某個播放程式加入 VAST 支援,由於目前使用第三方播放器的 VAST 支援並不能完全支援 Google Ads Manager,所以決定使用官方的 IMA SDK。不過官方的 IMA SDK 有一個缺點,就是不讓開發者自行定義界面 (可以設定是否隱藏或顯示某些項目,但不能自行作出其他調整。雖然官方說明中有可搜尋但沒有列出的頁面說明如何修改,但官方有解釋並不支援:https://groups.google.com/g/ima-sdk/c/yVBKLyO9jfY/m/dzYerQH-AQAJ),所以我們會使用自帶的廣告界面。

然而,在 QA 測試時發現無論是 iOS 或是 Android,當裝置螢幕為圓角 (例如 iPhone X, Samsung A70) 的時候,在左下角顯示的倒數時間及右上角的 “瞭解更多” 字樣均超出了圓角的範圍而導致無法完全顯示。

我們的設計其實比較簡單,播放器的容器就只會放第三方播放器和 IMA SDK 的控制項:

  • 根容器 (佔全螢幕包括所有安全區域)
    • PlayerContainer (UIView / FrameLayout)
      • IMA SDK 控制項 (IMA SDK 會自動放在最頂端)
      • 第三方播放器
    • 播放器控制
    • 其他重疊顯示

iOS 的處理相對簡單,只需要在 PlayerContainer 與 IMA SDK 之間加一個左右邊符合 playerContainer.safeAreaLayoutGuide 的 UIView 就可以。

Android 就麻煩得多,Google 在 API level 20 (Android 4.4W) 的時候加入了 View.setOnApplyWindowInsetsListener(),理論上可以接收到系統要求特定 View 套用所要求的 WindowInsets,但經測試後發現在全螢幕 (作為播放器,當然會用 SYSTEM_UI_FLAG_FULLSCREEN 及 SYSTEM_UI_FLAG_IMMERSIVE) 時,就算設定了 WindowInsetsListener 系統根本不會呼叫,所以沒用。

然後改為試用 API level 23 (Android 6) 加入的 View.getRootWindowInsets(),但只有在 View.onAttachedToWindow() 的時候呼叫時,WindowInsets.displayCutout 才不是 null,也就是我不能在初始化 IMA SDK 的時候就已經設定好 Margins。

最後,我從 stackoverflow 找到這篇方法 (https://stackoverflow.com/questions/61241255/windowinsets-getdisplaycutout-is-null-everywhere-except-within-onattachedtowindo)。

透過 Activity.getWindowManager().getDefaultDisplay().getCutout() 的確可以正確地取得不包括圓角區域的顯示範圍,不過最大的缺點是這是 API Level 29 (Android 10) 的 API,然而只有這個方法能正確取得可用的數值,所以也只能這樣了。

不過使用時有一點要留意,估計由於計算預設 Cutout 的時候並不假定 Immersive Mode,所以機頂向左的橫屏時只有 getSafeInsetLeft() 會傳回有效數值而 getSafeInsetRight() 會傳回 0,而機頂向右的時候則剛好相反,所以我們在套用 Margin 的時候會在左右兩邊同時套用任何一邊的有效數值,由於目前應該沒有裝置會在橫屏時是左圓角右方角,這個假定應該暫時還是可接受的。


撰寫於:2021/8/1 13:53:46 / 回應已關閉
正在讀取回響內容...
其他內容請回到主頁