2023-01-22

【Kotlin】以 Mozilla GeckoView 取代 webview

參考資料 ----


Android 內建的 webview 元件在顯示的體驗上不是很好,某些網頁版面的顯示結果就是不像真正的瀏覽器,而 Mozilla Gecko View 是真正的瀏覽器引擎。

GeckoView Maven Repository 尋找您要的版本號;在本筆記,選擇穩定版 100.0.20220425210429


開發工具:Android Studio Chipmunk 2021.2.1 Patch 2


Project 層級 build.gradle
 
buildscript {
    ext.kotlin_version = "1.7.10"
    repositories {
        google()
        mavenCentral()
    }

    dependencies {
        classpath 'com.android.tools.build:gradle:7.2.2'
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }
}


allprojects {
    repositories {
        google()
        mavenCentral()
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}
 


app 層級 build.gradle
 
plugins {
    id 'com.android.application'
    id 'kotlin-android'
}

ext {
    geckoviewChannel="arm64-v8a"
    geckoviewVersion="100.0.20220425210429"
}

...
...

android {
    compileSdkVersion 33
    
    ...
    ...
    
    // Note: compileOptions is only required for minSdkVersion < 24
    compileOptions {
        // sourceCompatibility JavaVersion.VERSION_1_8
        // targetCompatibility JavaVersion.VERSION_1_8
        sourceCompatibility JavaVersion.VERSION_11  // 若採用這個, 則 compileSdkVersion 要指定 33(含) 以上
        targetCompatibility JavaVersion.VERSION_11
    }
}

...
...

repositories {
    maven {
        url "https://maven.mozilla.org/maven2/"
    }
}

...
...

dependencies {

    ...
    ...
    
    // mozilla geckoview
    implementation "org.mozilla.geckoview:geckoview-${geckoviewChannel}:${geckoviewVersion}"
}

 

如果有出現類似

Build was configured to prefer settings repositories over project repositories but repository '???' was added by build file 'build.gradle' 

的錯誤訊息,可能是您的專案套用了 Gradle6.8 的新規定,那就修改 settings.gradle ,將 dependencyResolutionManagement 這個區塊 註解 或 刪除,我是去參照其他舊專案,只留下 2 列,如下:

settings.gradle
 
rootProject.name = "專案名"
include ':app'
 



AndroidManifest.xml
 
<manifest ... >
    <uses-permission android:name="android.permission.INTERNET" />
        ...
</manifest>
 


activity_main.xml
 
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity" >

    <org.mozilla.geckoview.GeckoView
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/geckoview"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        tools:context=".MainActivity" />

</RelativeLayout>
 


MainActivity.kt
 
...
...

import org.mozilla.geckoview.GeckoRuntime;
import org.mozilla.geckoview.GeckoSession;
import org.mozilla.geckoview.GeckoView;

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        var view:GeckoView = findViewById(R.id.geckoview)
        val session = GeckoSession()
        val runtime = GeckoRuntime.create(this)
        session.open(runtime)
        view.setSession(session)
        session.loadUri("https://tw.yahoo.com")
    }
}
 


ZenFon5 跑的反應速度有點慢,且編譯出來的 apk 頗大 -- 139MB !! 不過呈現的畫面的確較 webview 細緻。

2022-12-17

【WEB程式】Apache ECharts -- 圓餅圖(Pie Chart)

參考資料 ----

Apache ECharts 教程


再來試試 圓餅圖

 
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Pie Chart</title>
    <!-- 引入 echarts.js -->
    <script src="https://cdn.jsdelivr.net/npm/echarts@5.0.2/dist/echarts.min.js"></script>
    <!-- 引入 vitage 樣式 js -->
    <script src="https://cdn.jsdelivr.net/npm/echarts@5.0.2/theme/vintage.js"></script>
</head>
<body>
    <!-- 為 ECharts 準備一個具備大小(寬高)的 DOM -->
    <div id="main" style="width:600px; height:400px;"></div>
    
    <script type="text/javascript">
        <?php
            $aExam = [  ['name' => '初等考試', 'value' => 7],
                        ['name' => '大學指考', 'value' => 15],
                        ['name' => '高考護理師', 'value' => 26],
                        ['name' => '國中會考', 'value' => 1],
                        ['name' => '機車駕照', 'value' => 17],
                        ['name' => '汽車駕照', 'value' => 32]
                    ];

            // 如果是從資料庫撈出來的, 做法如下:
            // $aExam = array();
            // ...
            // ...
            // foreach($rs => $row)
            //    array_push($aExam, ['name' => $row['考試科目'], 'value' => $row['下載次數']]);


            echo 'var aExam = '.json_encode($aExam,JSON_NUMERIC_CHECK).";\n";    // 將 PHP 陣列轉出成 javascript 陣列
                                                                                   // 要注意 json_encode() 的第 2 個參數
                                                                                   // 若沒有第 2 個參數, json_encode 預設會轉出成 字串 陣列, 每個數字會以雙引號包住
                                                                                   // 這樣會造成圖表的顯示出現無法預期的結果,ex: 線亂畫、座標點錯誤...
        ?>
        // 基於準備好的 DOM,初始化 echarts 實體
        var myChart = echarts.init(document.getElementById('main'), 'vintage');    // 第 2 個參數 是 樣式 選項: 預設, light(內建), dark(內建), vintage, macarons, infographic, shine, roma
                                                                                   // 如果沒有 "樣式" 參數,就是預設樣式
                                                                                   // light樣式 與 預設樣式 的差異在 light 的顏色比預設更淡
                                                                                   // 若要採用不同樣式, 除了內建的 light/dark,其他樣式則上面也要引入相應的 js
 
        // 指定圖表的配置項和數據
        var option = {
                        title: {
                                text: '考試下載比例',
                                left: 'center'
                            },
                        tooltip: {
                                    trigger: 'item'
                                },
                        legend: {
                                    orient: 'vertical',
                                    left: 'left'
                                },
                        series: [{
                                    name: '考試科目',
                                    type: 'pie',
                                    data: aExam,
                                },
                                ],
                    };
 
        // 使用剛才指定的配置項和數據顯示圖表。
        myChart.setOption(option);
    </script>
</body>
</html>

 



滑鼠移至某個考試科目時,就會顯示該科考試的下載數,這是參數 tooltip 的效果。
點擊左上角(legend 區域) 的考試科目,該科考試的色塊就會隱藏,再點擊一次會再出現。


相關筆記 ----


2022-12-06

【Delphi7】限制自己的執行中程式只有一個

Project → Options 設定 Appcalition → Title,在本例為 myApp

 

 


 
procedure TfrmIsRunMain.FormCreate(Sender: TObject);
var
    Mutex: HWND;
    gt: Integer;
begin
    Mutex := CreateMutex(nil,false,'myApp');
    gt := GetLastError;
    if (gt=Error_ALREADY_EXISTS) then
    begin
        ShowMessage('app is running!');
        Application.Terminate;
    end;
end;
 

2022-11-28

【Metabase】同步/更新 資料庫

有時我們異動了資料庫中的某些資料表,尤其當 Metabase 有使用到表中的欄位時,我們就必須 同步/更新,不然  Metabase 會無法正確顯示圖表。

 

登入 Metabase ,點擊右上角的 齒輪 → 系統管理

 

點擊上方功能表的 "資料庫"



點擊要 同步/更新 的資料庫


點擊 "開始同步資料庫綱要",這樣就完成了。


2022-11-20

【jQuery】簡單好用的表格元件 EasyUI datagrid

參考資料 ----


EsayUI datagrid 元件可以造出功能強大又好看的表格,只要添加自己撰寫對應的程式碼,甚至可以做到直接在表格內 新增/修改/刪除 的功能;非商業用途的可用免費版。

因為我的資料來源為網站上的資料庫,所以需要 server 端的程式以回應 client 端傳來的請求,又因為只做瀏覽用,如果看倌有要在表格內直接 新增/修改/刪除 數據的需要,請自行另外研究囉~。

先到 EasyUI 下載壓縮包,解壓後,找到名為 locale 的目錄,裡面有個 easyui-lang-zh_TW.js ,這是正體中文語言檔,將它上傳至您網站指定目錄,在本例為 /js/


前端的程式 client.php
 
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta name="keywords" content="" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>datagrid demo</title>
<meta name="description" content="datagrid demo" />
<link rel="shortcut icon" href="/image/icon.png" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.10.3/jquery-ui.min.js"></script>

<link rel="stylesheet" type="text/css" href="https://www.jeasyui.com/easyui/themes/default/easyui.css">
<link rel="stylesheet" type="text/css" href="https://www.jeasyui.com/easyui/themes/icon.css">
<link rel="stylesheet" type="text/css" href="https://www.jeasyui.com/easyui/themes/color.css">
<link rel="stylesheet" type="text/css" href="https://www.jeasyui.com/easyui/demo/demo.css">
<script type="text/javascript" src="https://www.jeasyui.com/easyui/jquery.easyui.min.js"></script>
<script type="text/javascript" src="/js/easyui-lang-zh_TW.js"></script><!-- 正體中文語言包-->
</head>
<body>
    <!-- <table id="table1" class="easyui-datagrid" style="width:1000px;height:auto"   auto 表示 表格的高度自動調整 -->
    <!-- 若屬性中設了 fixColumns="true" 欄寬就被固定住了, 並且表格底部不會顯示橫向捲軸 -->
    <table id="table1" class="easyui-datagrid" style="width:100%;height:400px"<!-- 可以用 px 設定表格 寬/高, 也可以用 % 螢幕比例 -->
        url="uber_rec.php"  <!-- 指定 server 端程式 -->
        pagination="true"   <!-- 要有頁數導覽元件 -->
        rownumbers="true"   <!-- 最左邊顯示列號 -->
        noWrap="true"       <!-- 欄位內的文字不折行 -->
        striped="true"      <!-- 單偶列不同背景色 -->
        singleSelect="true" <!-- 滑鼠點擊的列會高亮度顯示 -->
        pageList=[30,60,90] <!-- 每頁顯示的列數選項 -->
        pageSize=30 >       <!-- 預設每頁顯示 30 筆記錄 -->
        <thead>
            <tr>
                <th field="欄位1" width="180">欄位1 在 datagrid 的顯示名稱</th>
                <th field="欄位2" width="200">欄位2 在 datagrid 的顯示名稱</th>
                ...
                ...
            </tr>
        </thead>
    </table>
</div>
</body>
</html>

 


server 端的程式 get_rec.php
 
<?php
// 建立 PDO
$dsn = 'mysql:dbname=資料庫名;host=localhost;charset=utf8;';
$user = 'MySQL帳戶名';
$password = '密碼';
$options = array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8'); 
try
    {   // 建立資料連線
        $pdo = new PDO($dsn, $user, $password, $options);
    }
catch (PDOException $e)
    {
        echo 'connection failed';
        exit;
    }

$result = array();

// 撈記錄總筆數
$sql = "SELECT COUNT(*) cnt FROM 資料表A";
$pdoStat = $pdo->prepare($sql);
$pdoStat->execute();
$rs = $pdoStat->fetch();
$result["total"] = $rs['cnt'];   // EasyUI 規定的 jason 元素名


$iRows = isset($_POST['rows']) ? intval($_POST['rows']) : 30;   // client 端傳來的一頁要顯示的記錄筆數, 預設 30
$iOffset = isset($_POST['page']) ? (intval($_POST['page'])-1)*$iRows : 0;   // client 端傳來的一頁要顯示第幾頁, 預設 0
$sql = "SELECT * FROM 資料表A ORDER BY 排序欄位 LIMIT $iRows OFFSET $iOffset";
$pdoStat = $pdo->prepare($sql);
$pdoStat->execute();
$rs = $pdoStat->fetchAll();

$recs = array();

if(count($rs)>0)
{
    foreach($rs as $row)
    {
        array_push($recs, ['欄位1'=>$row['欄位1'], '欄位2'=>$row['欄位2'], ...]);
    }
    $result["rows"] = $recs;  // EasyUI 規定的 jason 元素名
}
echo json_encode($result);
?>
 


2022-11-06

【PHP】Google Maps API -- 將地址轉換成經緯度座標

參考資料 ----

建立類別 GMap,用地址轉換經緯度

GMap.php
 
class GMap
{
    function getPageData($url)
    { 
        $ch = curl_init(); 
        curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);  
        curl_setopt($ch, CURLOPT_HTTPHEADER, array('Expect: '));
        curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); 
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_NOBODY, false);
        curl_setopt($ch, CURLOPT_FILETIME, true);
        curl_setopt($ch, CURLOPT_REFERER, $url);
         
        curl_setopt($ch, CURLOPT_BINARYTRANSFER, true);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 4);
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
        curl_setopt($ch, CURLOPT_TIMEOUT, 10);
        curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)");
        //取得原始碼
        $result['data'] = curl_exec($ch);
        //$info_tmp = curl_getinfo($ch);
        //取得info資訊
        //$result['info'] = $info_tmp;
        unset($info_tmp);
        curl_close($ch);
          
        return $result;
    }


    /** 
     * 初始化 
     * @param $apikey 金鑰 
     */ 
    function __construct()
    {
        $this->apikey = '填入金鑰';
    } 


    /* 
     * 獲取地址經緯度 - 從google map
     */  
    public function getLatLng($addr='',$apikey='')
    {
        $apikey = ($apikey=='') ? $this->apikey : $apikey;
        $url = "https://maps.googleapis.com/maps/api/geocode/json?address=$addr&key=$apikey";
        $geocode = $this->getPageData($url);
        if(isset($geocode['data']))
            $geocode = $geocode['data'];
        else
            // 當 Google map 解析不了時,回應虛擬的經緯度
            $geocode = '{"results":[{"geometry":{"location":{"lat":-1,"lng":-1}}}]}';

        $output = json_decode($geocode); 
        $latitude = $output->results[0]->geometry->location->lat;
        $longitude = $output->results[0]->geometry->location->lng; 
     
        return array('lat'=>$latitude,'lng'=>$longitude);
    }
}
 


主程式 main.php
 
<?php
date_default_timezone_set('Asia/Taipei');
include('gmap.php');

$gmap = new GMap();
// 填入地址(高雄捷運美麗島站, 22.631754649712416, 120.30137231318399)
// 像美麗島站這類大地標,像上面明確的描述,通常也解析的出來
// 注意:地址字串內不要有空白
$data = $gmap->getLatLng('高雄市新興區中山一路115號');
echo "經度:".$data['lng'].",緯度:".$data['lat'];
?>
 




2022-10-23

【Kotlin】AdMob(API20(含)↑) 自適應橫幅 Adaptive Banner, 適 Android R(API30↑)

參考資料 ----


Smart Banner 將停用,全面以 Adaptive Banner 取代!

因應 Java 的改版, AdMob 也跟著更新,並改變了 取得 AdSize 的寫法

app 層級build.gradle 要使用最新版的 play-services-ads,目前(2022.10.23) 是 21.3.0

 
...
...
dependencies {
    ...
    ...
    
    implementation 'com.google.android.gms:play-services-ads:21.3.0'
    
    ...
    ...
}    
 


strings.xml
 
...
...

    < 測試的 AdMob app id -->
    <string name="app_id">ca-app-pub-3940256099942544~3347511713</string>
    < 測試的 AdMob 橫幅 id -->
    <string name="banner">ca-app-pub-3940256099942544/6300978111</string>

...
...
 


AndroidManifest.xml
 
    <application
        ...
        ... >

        <!-- App ID -->
        <meta-data
            android:name="com.google.android.gms.ads.APPLICATION_ID"
            android:value="@string/app_id" />
            
        ...
        ...
        <activity
                ...
                ...
        
 


原本的 layout.xml 是在佈局中直接放一個 adview,因為要動態決定 adview 的尺寸,就不這麼做了。
 
...
...

<com.google.android.gms.ads.adview
    ads:adsize="SMART_BANNER"
    ads:adunitid="@string/banner_ad_unit_id"
    android:id="@+id/adView"
    android:layout_alignparentbottom="true"
    android:layout_alignparentend="true"
    android:layout_alignparentleft="true"
    android:layout_alignparentright="true"
    android:layout_alignparentstart="true"
    android:layout_height="wrap_content"
    android:layout_width="match_parent" />

...
...
 

改成以 framelayout 做為 AdView 的容器(container)
 
...
...

<!-- 只要是 ViewGroup 層級皆可,ex:FrameLayout...,視您的需要自行變化 -->
<LinearLayout
    android:id="@+id/ad_view_container"
    android:layout_alignParentBottom="true"
    android:layout_centerInParent="true"
    android:layout_height="wrap_content"
    android:layout_width="match_parent" />
...
...
 


MainActivity.kt
 
...
...

class MainActivity : AppCompatActivity() 
{
    private lateinit var adView: AdView

    override fun onCreate(savedInstanceState: Bundle?)
    {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        MobileAds.initialize(this) { }

        // 程式執行時,取得當時的螢幕寬度
        // 再動態決定 adView 的尺寸
        adView = AdView(this)
        ad_view_container.addView(adView)
        loadBanner()

    }


    // 取得螢幕尺寸
    private val adSize: AdSize
        get()
        {
            val iScreenWidth = getScreenWidth()
            val fDensity = getDensity()
            val adWidth = (iScreenWidth / fDensity).toInt()
            return AdSize.getCurrentOrientationAnchoredAdaptiveBannerAdSize(this, adWidth)
        }
        
        
    private fun getScreenWidth(): Int {
        val wm = application.getSystemService(WINDOW_SERVICE) as WindowManager
        return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            val windowMetrics = wm.currentWindowMetrics
            windowMetrics.bounds.width()
        } else {
            val displayMetrics = DisplayMetrics()
            wm.defaultDisplay.getMetrics(displayMetrics)
            displayMetrics.widthPixels
        }
    }

    private fun getDensity(): Float {
        return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            val config: Configuration = application.resources.configuration
            config.densityDpi / 160f
        } else {
            val metrics = application.resources.displayMetrics
            metrics.density
        }
    }

    // 載入橫幅
    private fun loadBanner()
    {
        adView.adUnitId = getString(R.string.banner)
        // adView.adSize = adSize
        mAdView.setAdSize(adSize)
        val adRequest = AdRequest.Builder().build()
        adView.loadAd(adRequest)
    }
 


相關筆記 ----


2022-10-22

【Kotlin】偵測 Android 裝置的螢幕尺寸

 
...
...
    
when(this.resources.configuration.screenLayout and Configuration.SCREENLAYOUT_SIZE_MASK) {
    Configuration.SCREENLAYOUT_SIZE_SMALL -> Toast.makeText(this, "320x426", Toast.LENGTH_LONG).show()
    Configuration.SCREENLAYOUT_SIZE_NORMAL -> Toast.makeText(this, "320x470", Toast.LENGTH_LONG).show()
    Configuration.SCREENLAYOUT_SIZE_LARGE -> Toast.makeText(this, "480x640", Toast.LENGTH_LONG).show()
    Configuration.SCREENLAYOUT_SIZE_XLARGE -> Toast.makeText(this, "720x960", Toast.LENGTH_LONG).show()
    Configuration.SCREENLAYOUT_SIZE_UNDEFINED -> Toast.makeText(this, "undefined", Toast.LENGTH_LONG).show()
    else -> Toast.makeText(this, "I don't know", Toast.LENGTH_LONG).show()
}


...
...
 

手機


平板




2022-10-19

【Linux】CentOS 7 安裝 Git2

CentOS 7Git 版本為 1.8.x,若想使用 Git2,(例如想開發學習 Flutter 就必須更新到 Git2)必須另尋第三方的套件庫。


先移除舊版 git
 
[root]# yum  remove  git*
 


引入套件庫,目前有 2 個較多人採用的套件庫, 1 個是社群(IUS),一個是美國的資訊顧問公司(Endpoint)
 
# IUS 套件庫
[root]# yum  install  install https://repo.ius.io/ius-release-el7.rpm

# Endpoint 套件庫
# 本筆記採用 Endpoint 套件庫
[root]# yum  install  https://packages.endpointdev.com/rhel/7/os/x86_64/endpoint-repo.x86_64.rpm
 

安裝 git2
 
# 很神奇,自動安裝 Endpoint 的,而不是 CentOS7 的 git
[root]# yum  install git
 


2022-10-10

【Kotlin】原始/陽春/樸實的 banner 橫幅廣告

參考資料 ----

AdMob 一直在變更 banner 的樣式, Smart Banner 即將棄用,取而代之的是 Adaptive Banners ,而 Adaptive Banners 因為要對應 Java 新版本 API 的因素也一直在變更寫法。

如果 不想 或 懶得 採用最新的廣告樣式,可以考慮 原始/陽春/樸實 的橫幅廣告。(本筆記結合了視圖綁定)

app 層級 build.gradle
 
...
...

android {
    
    buildFeatures {
        viewBinding true
    }
    
    ...
    ...
    
}

...
...

dependencies {

    // adMob
    implementation 'com.google.android.gms:play-services-ads:21.2.0'
    
}
 


strings.xml
 
<resources>
    
    ...
    ...

    <!-- adMob app id 測試 -->
    <string name="admob_app_id">ca-app-pub-3940256099942544~3347511713</string>
    <!-- 橫幅 測試 -->
    <string name="banner_ad_unit_id">ca-app-pub-3940256099942544/6300978111</string>

</resources>
 


AndroidManifest.xml
 
<manifest

    <!-- 存取網路連線 -->
    <uses-permission android:name="android.permission.INTERNET" />

    ...
    ...

    <application  ... >

        <meta-data
            android:name="com.google.android.gms.version"
            android:value="@integer/google_play_services_version" />
        <meta-data
            android:name="com.google.android.gms.ads.APPLICATION_ID"
            android:value="@string/admob_app_id" />

        ...
        ...

        <!-- AdMob 的 AdActivity -->
        <activity
            android:name="com.google.android.gms.ads.AdActivity"
            android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize"
            android:theme="@android:style/Theme.Translucent" />

        ...
        ...

    </application>

</manifest>
 


activity_main.xml
 
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:ads="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="0dp"
    android:paddingLeft="0dp"
    android:paddingRight="0dp"
    android:paddingTop="0dp"
    tools:context=".MainActivity">
        
    <com.google.android.gms.ads.AdView
        android:id="@+id/adView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentStart="true"
        android:layout_alignParentEnd="true"
        ads:adSize="BANNER"
        ads:adUnitId="@string/banner_ad_unit_id" />

    <TextView
        android:id="@+id/txtHello"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentStart="true"
        android:layout_alignParentTop="true"
        android:layout_alignParentEnd="true"
        android:text="Hello World!" />

</RelativeLayout>
 
adSize  除了 BANNER 外,另有其他值可填入
大小 (寬 x 高)說明適用裝置AdSize 常值
320x50標準橫幅廣告手機和平板電腦BANNER
320x100大横幅手機和平板電腦LARGE_BANNER
300x250IAB 中矩形廣告手機和平板電腦MEDIUM_RECTANGLE
468x60IAB 完整橫幅廣告平板電腦FULL_BANNER
728x90IAB 超級橫幅廣告平板電腦LEADERBOARD

                           


MainActivity.kt
 
class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        val view = binding.root
        setContentView(view)

        binding.txtHello.text = "大家好"

        // AdMob 初始化
        MobileAds.initialize(this)
        binding.adView.loadAd(AdRequest.Builder().build())
    }
}
 

採用陽春型橫幅,缺點當然就是外觀顯示不夠漂亮,使用者體驗不好,因為尺寸都是固定的。

(手機直) BANNER 標準尺寸 320×50



(手機橫) BANNER 標準尺寸 320×50



大橫幅(LARGE_BANNER) 320×100



IAB 中矩形(MEDIUM_RECTANGLE) 300×250



平板 IAB 完整橫幅(FULL_BANNER) 468×60




平板(直) IAB 超級橫幅(LEADERBOARD) 728×90


平板(橫) IAB 超級橫幅(LEADERBOARD) 728×90



若希望不同尺寸螢幕的設備展示相應的橫幅,可以複製 activity_main.xml
/layout-w480dp//layout-w740dp/ 並將 adSize 屬性對應不同的橫幅。


/layout-w480dp/
 
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    ...
    ...
    tools:context=".MainActivity">
        
    <com.google.android.gms.ads.AdView
        android:id="@+id/adView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentStart="true"
        android:layout_alignParentEnd="true"
        ads:adSize="FULL_BANNER"
        ads:adUnitId="@string/banner_ad_unit_id" />

    ...
    ...

</RelativeLayout>
 


/layout-w740dp/
 
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    ...
    ...
    tools:context=".MainActivity">
        
    <com.google.android.gms.ads.AdView
        android:id="@+id/adView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentStart="true"
        android:layout_alignParentEnd="true"
        ads:adSize="LEADERBOARD"
        ads:adUnitId="@string/banner_ad_unit_id" />

    ...
    ...

</RelativeLayout>
 


方法二:
想到...不然自己土砲打造 "類自適應橫幅" 好了...😁

activity_main.xml
 
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="0dp"
    android:paddingLeft="0dp"
    android:paddingRight="0dp"
    android:paddingTop="0dp"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/txtHello"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentStart="true"
        android:layout_alignParentTop="true"
        android:layout_alignParentEnd="true"
        android:text="Hello World!" />

    <!-- 做為 自適應橫幅的 container -->
    <LinearLayout
        android:id="@+id/ad_view_container"
        android:layout_alignParentBottom="true"
        android:layout_centerInParent="true"
        android:layout_height="wrap_content"
        android:layout_width="match_parent"
        android:orientation="horizontal" />

</RelativeLayout>
 


MainActivity.kt
 

...
...

class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        val view = binding.root
        setContentView(view)

        binding.txtHello.text = "大家好"

        // AdMob 初始化
        MobileAds.initialize(this)

        // 橫幅廣告
        // 依螢幕尺寸變更橫幅的樣式
        val adView = AdView(this)
        when(this.resources.configuration.screenLayout and Configuration.SCREENLAYOUT_SIZE_MASK) {
            Configuration.SCREENLAYOUT_SIZE_XLARGE -> adView.setAdSize(AdSize.LEADERBOARD)
            Configuration.SCREENLAYOUT_SIZE_LARGE -> adView.setAdSize(AdSize.FULL_BANNER)
            Configuration.SCREENLAYOUT_SIZE_NORMAL -> adView.setAdSize(AdSize.LARGE_BANNER)
            else -> adView.setAdSize(AdSize.BANNER)
        }
        val lp = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.MATCH_PARENT)
        lp.gravity = Gravity.CENTER
        adView.adUnitId = getString(R.string.banner_ad_unit_id)
        binding.adViewContainer.addView(adView,lp)     // 注意這裡 ad_view_container 的命名方式是 "駝峰式命名"
        adView.loadAd(AdRequest.Builder().build())

    }
}
 


相關筆記 ----