游戏优化系列一:海外谷歌应用适配相关

作者

大家好,我叫Jack冯;
本人20年硕士毕业于广东工业大学,于2020年6月加入37手游安卓团队;目前主要负责海外游戏发行安卓相关开发。

系列目录

 游戏优化系列一:海外谷歌应用适配相关 (本章讲解)

游戏优化系列二:Android Studio制作图标教程

 游戏优化系列三:Unity游戏的黑屏问题解决方法

本文目录

  1. 谷歌应用图标

  2. 状态栏消息推送

  3. 系统主题风格

  4. 导航键

  5. 屏幕适配

  6. 返回按钮

背景

游戏上架谷歌申请推荐时,谷歌会给予一些优化建议。这些建议实际上都是比较不错的游戏体验优化方向。以下根据app上架谷歌应用商店的标准,列举需要适配的地方并提供了修改样例。

1. 谷歌应用图标

游戏icon:
5个不同尺寸的icon,4848, 7272, 9696, 144144, 192*192
分别放在mdpi,hdpi,xhdpi,xxhdpi,xxxhdpi下面。

推送icon(只能由白色+透明组成): (白底透明字)
5个不同尺寸的icon,2424, 3636, 4848, 7272, 96*96
分别放在mdpi,hdpi,xhdpi,xxhdpi,xxxhdpi下面。

Android Studio制作icon的教程,详见《游戏优化系列二-Android Studio制作图标教程

示例:

2. 状态栏消息推送

在游戏应用中进行版本迭代时,如果游戏本身有消息推送,且SDK中也有推送的情况下,发送消息的notify方法中,id有可能不同,此时会出现两条消息(游戏的和SDK的),有可能会被Google应用商店拒绝推荐。

NotificationManager.notify(int id, Notification notification)
NotificationManager.notify(int id, Notification notification)
NotificationManager.notify(int id, Notification notification)

出现两条消息:

需要做到的效果–同一个应用的消息堆叠

展开后:

修改示例:

private void mergeNotifications(){
int mergeId = 0;
String groupKey = "com.android.example.WORK_EMAIL";
String channelId = "1";
Notification notification1 = new NotificationCompat.Builder(MainActivity.this, channelId)
.setSmallIcon(R.drawable.ic_launcher_background)
.setContentTitle("推送需要堆叠")
.setContentText("这是一条SDK的通知")
.setGroup(groupKey)
.build();
Notification notification2 = new NotificationCompat.Builder(MainActivity.this, channelId)
.setSmallIcon(R.drawable.ic_launcher_background)
.setContentTitle("推送需要堆叠")
.setContentText("这是一条游戏的通知")
.setSmallIcon(R.drawable.ic_stat_name)
.setGroup(groupKey)
.build();
Notification mergeNotification = new NotificationCompat.Builder(MainActivity.this, channelId)
.setContentTitle("推送需要堆叠")
.setContentText("2条未读信息")
.setSmallIcon(R.drawable.ic_stat_name)
.setStyle(new NotificationCompat.InboxStyle()
.addLine("这是一条游戏的通知")
.addLine("这是一条SDK的通知")
.setBigContentTitle("2条未读信息")
.setSummaryText("推送测试"))
.setGroup(groupKey)
.setGroupSummary(true)
.build();
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
notificationManager.notify(1, notification1);
notificationManager.notify(2, notification2);
notificationManager.notify(mergeId, mergeNotification);
}
private void mergeNotifications(){
    int mergeId = 0;
    String groupKey = "com.android.example.WORK_EMAIL";
    String channelId = "1";
    Notification notification1 = new NotificationCompat.Builder(MainActivity.this, channelId)
        .setSmallIcon(R.drawable.ic_launcher_background)
        .setContentTitle("推送需要堆叠")
        .setContentText("这是一条SDK的通知")
        .setGroup(groupKey)
        .build();

    Notification notification2 = new NotificationCompat.Builder(MainActivity.this, channelId)
        .setSmallIcon(R.drawable.ic_launcher_background)
        .setContentTitle("推送需要堆叠")
        .setContentText("这是一条游戏的通知")
        .setSmallIcon(R.drawable.ic_stat_name)
        .setGroup(groupKey)
        .build();

    Notification mergeNotification = new NotificationCompat.Builder(MainActivity.this, channelId)
        .setContentTitle("推送需要堆叠")
        .setContentText("2条未读信息")
        .setSmallIcon(R.drawable.ic_stat_name)
        .setStyle(new NotificationCompat.InboxStyle()
            .addLine("这是一条游戏的通知")
            .addLine("这是一条SDK的通知")
            .setBigContentTitle("2条未读信息")
            .setSummaryText("推送测试"))
        .setGroup(groupKey)
        .setGroupSummary(true)
        .build();

    NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
    notificationManager.notify(1, notification1);
    notificationManager.notify(2, notification2);
    notificationManager.notify(mergeId, mergeNotification);
}
private void mergeNotifications(){ int mergeId = 0; String groupKey = "com.android.example.WORK_EMAIL"; String channelId = "1"; Notification notification1 = new NotificationCompat.Builder(MainActivity.this, channelId) .setSmallIcon(R.drawable.ic_launcher_background) .setContentTitle("推送需要堆叠") .setContentText("这是一条SDK的通知") .setGroup(groupKey) .build(); Notification notification2 = new NotificationCompat.Builder(MainActivity.this, channelId) .setSmallIcon(R.drawable.ic_launcher_background) .setContentTitle("推送需要堆叠") .setContentText("这是一条游戏的通知") .setSmallIcon(R.drawable.ic_stat_name) .setGroup(groupKey) .build(); Notification mergeNotification = new NotificationCompat.Builder(MainActivity.this, channelId) .setContentTitle("推送需要堆叠") .setContentText("2条未读信息") .setSmallIcon(R.drawable.ic_stat_name) .setStyle(new NotificationCompat.InboxStyle() .addLine("这是一条游戏的通知") .addLine("这是一条SDK的通知") .setBigContentTitle("2条未读信息") .setSummaryText("推送测试")) .setGroup(groupKey) .setGroupSummary(true) .build(); NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this); notificationManager.notify(1, notification1); notificationManager.notify(2, notification2); notificationManager.notify(mergeId, mergeNotification); }

3. 系统主题风格

在应用里面弹出的Dialog、Loading框,需要适配系统风格!

例如在5.0以上的系统,出现这种风格是不行的:

这种风格才是符合要求的:

如果这些Dialog、Loading框不是使用系统风格,而是自行设计,则可以继续使用,不必进行额外处理; 例如:

具体实现方法有两种:

 第一种,在Androidmanifest的application和activity标签下,不要设定android:theme,即可适配系统风格。

修改示例1:

<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.game37.themeapplication">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true">
<activity
android:name=".MainActivity"
android:screenOrientation="sensorLandscape">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application></manifest>
<manifest 
    xmlns:android="http://schemas.android.com/apk/res/android"    
    package="com.game37.themeapplication">    
<application
       android:allowBackup="true"
       android:icon="@mipmap/ic_launcher" 
       android:label="@string/app_name" 
       android:roundIcon="@mipmap/ic_launcher_round" 
       android:supportsRtl="true">
       <activity
         android:name=".MainActivity"
         android:screenOrientation="sensorLandscape">
         <intent-filter> 
               <action android:name="android.intent.action.MAIN" /> 
               <category android:name="android.intent.category.LAUNCHER" /> 
          </intent-filter>
        </activity>
</application></manifest>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.game37.themeapplication"> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true"> <activity android:name=".MainActivity" android:screenOrientation="sensorLandscape"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application></manifest>

示例效果1:

第二种,可保留android:theme,但需要引用Google库工程appcompat_v7,使用系统自带主题或者自定义主题。 其中,在自定义的style里面,继承Theme.AppCompat(还有很多子风格可以选择,如Theme.AppCompat.Light和Theme.AppCompat.NoActionBar等)。

修改示例2:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.game37.themeapplication">
<application
...
android:theme="@style/Theme.AppCompat">
<activity
android:name=".MainActivity"
android:screenOrientation="sensorLandscape"
//使用自定义主题
android:theme="@style/testStyle">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
//使用系统自带主题
android:name=".MainActivity2"
android:theme="@style/Theme.AppCompat.NoActionBar" />
</application>
</manifest>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.game37.themeapplication">
    <application
        ...
        android:theme="@style/Theme.AppCompat">
        <activity
            android:name=".MainActivity"
            android:screenOrientation="sensorLandscape"
            //使用自定义主题
            android:theme="@style/testStyle">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <activity
            //使用系统自带主题
            android:name=".MainActivity2"
            android:theme="@style/Theme.AppCompat.NoActionBar" />
    </application>
</manifest>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.game37.themeapplication"> <application ... android:theme="@style/Theme.AppCompat"> <activity android:name=".MainActivity" android:screenOrientation="sensorLandscape" //使用自定义主题 android:theme="@style/testStyle"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity //使用系统自带主题 android:name=".MainActivity2" android:theme="@style/Theme.AppCompat.NoActionBar" /> </application> </manifest>

其中,自定义主题样式如下:(设置全屏、背景色等)

<style name="testStyle" parent="Theme.AppCompat">
<item name="android:actionBarStyle">@style/FullscreenActionBarStyle</item>
<item name="android:windowActionBarOverlay">true</item>
<item name="android:windowBackground">@null</item>
</style>
<style name="FullscreenActionBarStyle" parent="Widget.AppCompat.ActionBar">
<item name="android:background">@color/colorAccent</item>
</style>
<style  name="testStyle" parent="Theme.AppCompat">
    <item name="android:actionBarStyle">@style/FullscreenActionBarStyle</item>
    <item name="android:windowActionBarOverlay">true</item>
    <item name="android:windowBackground">@null</item>
</style>

<style name="FullscreenActionBarStyle" parent="Widget.AppCompat.ActionBar">
    <item name="android:background">@color/colorAccent</item>
</style>
<style name="testStyle" parent="Theme.AppCompat"> <item name="android:actionBarStyle">@style/FullscreenActionBarStyle</item> <item name="android:windowActionBarOverlay">true</item> <item name="android:windowBackground">@null</item> </style> <style name="FullscreenActionBarStyle" parent="Widget.AppCompat.ActionBar"> <item name="android:background">@color/colorAccent</item> </style>

示例效果2:

在Androidmanifest的相关android:theme设置上述继承Theme.AppCompat风格的主题即可。

【常见问题】

游戏工程接入SDK的过程中,如果主Activity继承的是androidx.appcompat.app.AppCompatActivity,需要使用Theme.AppCompat类主题,因此建议游戏工程的主题设置不留空,即采用第二种方式设定相关主题!

【注意】

如果修改主题后,输入框等显示异常(eg:角色的名称输入框,背景白色、字体白色,会影响玩家体验),可使用推荐主题来修复android:theme=”@style/Theme.AppCompat.Light.DarkActionBar”

4.导航键

系统导航键不能挡住功能,最好能够使用IMMERSIVE_STICKY模式(即完全全屏,通知栏和导航键都自动隐藏,需要API-19以上支持)。

覆盖功能情景:

修改示例:

getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                    | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                    | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                    | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                    | View.SYSTEM_UI_FLAG_FULLSCREEN
                    | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);

修改效果:

5. 屏幕适配

(1)屏幕方向

在某些应用程序中偶尔会出现180度左右的倒挂现象。为了获得更好的用户体验,我们建议您保持总体方向与原始方向一致。

由于某些横屏的游戏,可以根据重力自动转换屏幕(转换后还是横屏,只是方向不同),所以修改androidmanifest中Activity属性,android:screenOrientation设置为sensorLandscape即可。

(2)适配多种屏幕

在androidmanifest加入下面配置

<supports-screens
android:anyDensity="true"
android:largeScreens="true"
android:xlargeScreens="true"
android:normalScreens="true"
android:resizeable="true"
android:smallScreens="true" />
<supports-screens
        android:anyDensity="true"
        android:largeScreens="true"
        android:xlargeScreens="true"
        android:normalScreens="true"
        android:resizeable="true"
        android:smallScreens="true" />
<supports-screens android:anyDensity="true" android:largeScreens="true" android:xlargeScreens="true" android:normalScreens="true" android:resizeable="true" android:smallScreens="true" />

6.返回按钮

返回按钮需具有返回功能,应具有返回上一级内容、取消当前处理中的事务、退出游戏等作用。

返回键功能的官方解释:

1.具有与屏幕上任何后退或关闭按钮相同的功能

2.暂停和取消暂停游戏(如果适用)

3.关闭所有对话框窗口

4.导航到菜单堆栈中的上一个位置(如果适用)

5.第一次登录时,在主菜单中按下退出应用程序,在服务器选择和字符选择页面中,Android后退按钮出现错误行为。

具体情境:

(1)在游戏启动、资源加载过程,点击系统返回按钮要求能够后退,或者弹框提示用户是否退出游戏;(部分应用在这过程屏蔽了系统按钮,出现被谷歌应用商店拒绝的情况)

(2)活动弹窗显示时,点击返回系统按钮要求能够关闭弹窗。

示例说明:点击返回按钮无法关闭弹窗

结束语

过程中有问题或者需要交流的同学,可以扫描二维码加好友,然后进群进行问题和技术的交流等;

© 版权声明
THE END
喜欢就支持一下吧
点赞0

Warning: mysqli_query(): (HY000/3): Error writing file '/tmp/MY772fGN' (Errcode: 28 - No space left on device) in /www/wwwroot/583.cn/wp-includes/class-wpdb.php on line 2345
admin的头像-五八三
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

图形验证码
取消
昵称代码图片