Cocos Creator Android 原生啟動優化系列 2 —— 自定義啟動頁

本系列教程指引:

  1. Cocos Creator Android 原生啟動優化系列 1 —— 黑屏原因分析
  2. Cocos Creator Android 原生啟動優化系列 2 —— 自定義啟動頁

1. 前情回顧

在上一篇文章 Cocos Creator Android 原生啟動優化系列 1 —— 黑屏原因分析 中,我們大概分析了一下 Android 黑屏的原因,共有3個階段,主要在前兩個原生階段

AndriodStartupBooster.png

第三階段黑屏時長,實際上會和游戲首場景復雜度掛鉤。越簡單的首場景加載越快。本篇我們著重解決Android原生前兩個階段的黑屏問題。因此為了減少可變因子,我們直接以一個簡單場景作為第三階段要加載場景。

image.png

然后構建一個 Android 工程出來,這里特別需要注意一點:因為我們是探索測試,所以強烈建議采用基于 default 模板去進行操作(default 和 link 的區別可以查看官方文檔

default templete

OK,準備好了,Let's go!

使用主題前_320x568_6s.gif

2. 基于 Android Theme 做體驗優化

一種簡單的解決方案就是直接設置 AppActivity 的 主題Theme(官方文檔介紹,需翻墻),以下為摘自文檔的兩段說明,方便大家簡單理解。

樣式是指為 View 或窗口指定外觀和格式的屬性集合。樣式可以指定高度、填充、字體顏色、字號、背景色等許多屬性。 樣式是在與指定布局的 XML 不同的 XML 資源中進行定義。

主題是指對整個 Activity 或應用而不是對單個 View(如上例所示)應用的樣式。 以主題形式應用樣式時,Activity 或應用中的每個視圖都將應用其支持的每個樣式屬性。 例如,您可以 Activity 主題形式應用同一 CodeFont 樣式,之后該 Activity 內的所有文本都將具有綠色固定寬度字體。

OK,那么現在我們試試將我們的 AppActivity 主題修改一下。

比如:設置游戲開屏顏色為其他顏色,又或者將一張游戲圖片作為游戲開屏背景

2.1 設置其他顏色作為開屏背景

  1. 創建一個自定義顏色(app/res/values/colors.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!-- 這里我們取主場景的背景色 -->
    <color name="splashBg">#DA8020</color>
</resources>
  1. 創建一個主題 (app/res/values/colors.xml)
<?xml version="1.0" encoding="utf-8"?>
<resources >
    <!--這里為繼承 CCC 默認說采用的主題 Theme.NoTitleBar.Fullscreen -->
    <style name="SplashStyle"
           parent="@android:style/Theme.NoTitleBar.Fullscreen" >
        
        <!--自定義主題背景為我們剛剛創建的顏色-->
        <item name="android:windowBackground" >@color/splashBg</item >
        
        <!--令主題無標題-->
        <item name="android:windowNoTitle" >true</item >
    </style >
</resources >
  1. 修改主 Activity 的主題為我們剛剛創建的主題(app/AndroidManifest.xml
<activity
    android:name="org.cocos2dx.javascript.AppActivity"
    ...  
    android:theme="@style/SplashStyle"
    ...
    >
    ...
</activity >

整體修改大概如下:

image.png

現在我們跑一下

使用主題后_1_320x568_6s.gif

嗯?一開始看起來比黑屏好多了,但是之后又黑屏了,然后才進入到我們的主場景,那么這是為什么呢?這里面發生了什么呢?這里我們需要再次看回黑屏的三個階段

AndriodStartupBooster.png

從上面這個圖,我們不難得到答案。

  1. 首先我們設置的主題在第一個階段生效了,所以一打開游戲就是我們期望的背景顏色
  2. 然后一段時間之后,進入到第二個階段,觸發了 setContentView ,因此 AppActivity 擁有了 ContentView 了,從而會擋住主題,而又因為之前我們分析過,這里的 setContentView 是沒有背景的,所以就出現黑屏了
  3. 然后黑屏一直持續到我們的主場景加載成功,最后出現我們的主場景

OK,所有現象,完美符合代碼運行(多看源碼)。

那么這里的黑屏我們又該怎么解決呢?

在不大改源碼的情況下,我們可以這樣子來:

  1. 在第二個階段再次添加新的 純色背景ImageView 放到最上層,那么第二個階段也就是我們期望的顏色了
  2. 然后在第三階段結束,也就是我們主場景加載后,我們在通過 JSB 通知原生 Activity 該隱藏這個 純色背景ImageView

Android 原生代碼如下:

public class AppActivity extends Cocos2dxActivity {
    
    private static Cocos2dxActivity sCocos2dxActivity;
    
    private static ImageView sSplashBgImageView = null;
    
    private static void showSplash() {
        sSplashBgImageView = new ImageView(sCocos2dxActivity);
        sSplashBgImageView.setBackgroundColor(
            sCocos2dxActivity.getResources().getColor(R.color.splashBg)
        );
        sSplashBgImageView.setScaleType(ImageView.ScaleType.FIT_XY);
        sCocos2dxActivity.addContentView(sSplashBgImageView,
                new WindowManager.LayoutParams(
                        FrameLayout.LayoutParams.MATCH_PARENT,
                        FrameLayout.LayoutParams.MATCH_PARENT
                )
        );
    }
    
    /**
     * 這是給 CC JS 調用的隱藏原生開屏背景的方法
     */
    public static void hideSplash() {
        sCocos2dxActivity.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                if (sSplashBgImageView != null) {
                    sSplashBgImageView.setVisibility(View.GONE);
                }
            }
        });
    }
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        ...
        // DO OTHER INITIALIZATION BELOW
        SDKWrapper.getInstance().init(this);

        // 第一步:在第二階段加入我們的背景View
        sCocos2dxActivity = this;
        showSplash();
    }

    ...
}

主場景掛一個腳本:

@ccclass
export default class MainSceneCtrl extends cc.Component {

    start() {
        // 第二步:場景加載之后,隱藏原生純色背景View
        // 這里延遲1秒是為了更好的體驗,實際可以不用
        this.scheduleOnce(() => {
            this._hideNativeSplash();
        }, 1);
    }

    private _hideNativeSplash() {
        if (CC_JSB) {
            if (cc.sys.os == cc.sys.OS_ANDROID) {
                // 反射調用原生的隱藏方法
                jsb.reflection.callStaticMethod(
                    "org/cocos2dx/javascript/AppActivity",
                    "hideSplash",
                    "()V"
                );
            }
        }
    }
}

那么,再跑一下?

使用主題后_2_320x568_6s.gif

現在,我們成功地把黑屏給切換為一個有顏色的啟動頁了,原生和JS完美切換,看起來比黑屏好多了

2.2 設置圖片作為開屏背景

當然,上一章,我們更多是一種驗證和測試,而事實上,這個方法可行,并且 我們實現了使用任意純色背景作為啟動頁!

但實際我們更有可能在啟動頁放的是一個帶背景的游戲LOGO、游戲插圖等圖片,比如這樣子:

圖片啟動頁_480x853_8s.gif

那么這個又應該怎么實現呢?其實有了上一章基礎之后,我們只需要極小的改動就可以實現了

  1. 首先我們簡單修改下游戲場景,恩,其實就是一個圖片背景加點Label
  2. 然后,第一階段黑屏處理:
    2.1 將啟動頁圖片加入到Android工程的 drawable 中
    2.2 然后修改我們剛剛的主題(或者新建一個主題)背景為啟動頁圖片
    2.3 設置 app/AndroidManifest.xml 中的 Activity 主題為第2步的主題
    theme
  3. 最后,第二階段黑屏處理:
    3.1 基于上一章代碼,修改ImageView的背景顏色為背景圖片即可
-- sSplashBgImageView.setBackgroundColor(
--     sCocos2dxActivity.getResources().getColor(R.color.splash_bg)
-- );

++ sSplashBgImageView.setImageResource(R.drawable.splash);

OK,恭喜你又收獲一個技能。

當然,這里還有其他一些問題需要關注的。比如:

我們一直在設置的主題背景,如果是純色背景,那么很容易理解它的填充方式,就是全屏填充。但是,如果背景換成了圖片,那么圖片是怎么填充到屏幕的呢?拉伸?縮放?九宮格?保持尺寸不變?

要知道,我們上述步驟,本質上,給第一階段黑屏設置一個(主題)背景,給第二階段設置一個背景,而如果這兩個階段的背景都是圖片(第三階段就是場景了,不同游戲不一致,這里我們不討論),那么我們假設一種情況如下:

  • 第一個階段是 拉伸圖片 以達到全屏
  • 第二個階段是 縮放圖片 以達到全屏

那么顯然在部分分辨率上是達不到上面我們圖示那樣子的無縫原生與JS切換的UI體驗的。那么圖示為什么又那么完美呢?其實只是因為啟動頁圖寬高比和手機分辨率寬高比恰好一致,要是不一致就會很難看

所以,理解不同階段的圖片填充方式,對于這個啟動過程無縫切換很重要。

可以確定的是,第二階段,其實我們可以隨便控制填充方式,比如:例子代碼中我們用的是 FIT_XY ,當然還有其他很多 ImageView.ScaleType。但遺憾的是,我們第一階段的 windowBackground 是采用拉伸圖片的方式去適配的,那么只用一張固定尺寸的圖片,那么肯定會出現在部分手機上有拉伸的問題。

此時,這種設置單一全屏圖片的方式已經存在缺陷了,所以這也有可能是大部分游戲開屏沒有全屏圖片啟動頁的一個成因

2.3 設置 Slogan + 背景色 作為啟動頁

那么大部分游戲的啟動頁長什么樣子呢?一般都是一個 Slogan + 背景色 作為啟動頁,比如這樣子:

Slogan+背景色啟動頁_480x853_8s.gif

同樣在上面章節的基礎上,我們只需要改動幾個地方就可以實現了

第一階段黑屏處理:

  1. 將你的 Slogan 圖片加入到Android工程的 drawable 中(假設文件名字為 splash_slogan_small.png),同時建立一個背景色
<?xml version="1.0" encoding="utf-8"?>
<resources >
    ...
    <color name="splash_slogan_bg" >#FFCC00</color >
</resources >
  1. 創建一個DrawableXML文件(如:app/res/drawable/splash_slogan_with_bg.xml ),然后使用 Android 的圖層列表 LayerList【需翻墻】 生成一個 Drawable,這個 Drawable 由一個純色的矩形作為背景色,以及在這之上放置一個 Slogan 的 Bitmap 圖片
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
    <!--矩形 黃色作為背景色-->
    <item >
        <shape android:shape="rectangle" >
            <solid android:color="@color/splash_slogan_bg" />
        </shape >
    </item >
    
    <!--單獨的slogan圖片居中顯示-->
    <item >
        <bitmap
            android:gravity="center"
            android:src="@drawable/splash_slogan_small" />
    </item >
</layer-list >
  1. 修改我們剛剛的主題(或者新建一個主題)背景為剛剛的圖層列表文件
  2. 設置 app/AndroidManifest.xml 中的 Activity 主題為第3步的主題

第一階段操作結果預覽:

setting

第二階段黑屏處理:

  1. 基于上一章代碼,修改ImageView的背景圖片為我們剛剛創建的Drawable
-- sSplashBgImageView.setImageResource(R.drawable.splash);

++ sSplashBgImageView.setImageResource(R.drawable.splash_slogan_with_bg);

OK,大功告成。

現在我們來盤點一下,比如:

為什么我們要用 Android 的圖層列表 LayerList【需翻墻】

這是因為比起上一章單純的圖片可能存在在部分機器上出現拉伸的問題,使用 LayerList 能更好適配,同時比起單純一張圖片,LayerList也更加做多層級組合(背景+Slogan+...)的啟動頁。

如果你想在此基礎上實現貼底部的 Slogan 其實也是可以的,但是篇幅問題,我這里就不在詳述,可以詳細閱讀 Android 的圖層列表 LayerList【需翻墻】

3. 總結

當然,這個系列沒完,這篇只是在不改源碼的基礎上提升UI體驗,實際并沒有給減少啟動時間,下一篇我們會嘗試修改底層源碼以減少啟動時長。

4. 題外話

寫這個系列的文章的時候,我可能更多地傾向于 fishing

Not only the fish, but fishing!

我不知道我是否還能堅持寫這類型文章。因為每一篇都需要開項目驗證,進行大量錄屏,截圖,組織思路,寫過程,畫圖,摘錄官方文獻等等,一套操作下來,十分耗時,就像這個系列,我斷斷續續寫了兩個多月。當然,這也有可能是因為我懶 ╮( ̄▽ ̄)╭ 。

5. 參考資料

本系列教程指引:

  1. Cocos Creator Android 原生啟動優化系列 1 —— 黑屏原因分析
  2. Cocos Creator Android 原生啟動優化系列 2 —— 自定義啟動頁
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,156評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,401評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,069評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,873評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,635評論 6 408
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,128評論 1 323
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,203評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,365評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,881評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,733評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,935評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,475評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,172評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,582評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,821評論 1 282
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,595評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,908評論 2 372

推薦閱讀更多精彩內容