Android LibGDX 应用程序在本地运行但在 alpha 测试时崩溃

Android LibGDX application works locally but crashes on alpha testing

我有一个 libGDX 应用程序,现在我已经在 Google Play 商店发布了很多版本。但是现在我遇到了一个问题,我一直没有解决。

当我在 android 设备上启动该应用程序时,该应用程序在 Eclipse 中运行良好,但是当我导出 APK 并将其上传到 Play 商店并下载 Alpha 测试版本时,它崩溃并出现以下错误:

08-27 13:01:39.000: E/AndroidRuntime(16968): FATAL EXCEPTION: GLThread 6159
08-27 13:01:39.000: E/AndroidRuntime(16968): Process: com.xaoilin.soloshape, PID: 16968
08-27 13:01:39.000: E/AndroidRuntime(16968): com.badlogic.gdx.utils.bf: Error reading file: data/scroller/uiskin.json
08-27 13:01:39.000: E/AndroidRuntime(16968):    at com.badlogic.gdx.f.a.a.j.a(Unknown Source)
08-27 13:01:39.000: E/AndroidRuntime(16968):    at com.badlogic.gdx.f.a.a.j.<init>(Unknown Source)
08-27 13:01:39.000: E/AndroidRuntime(16968):    at com.xaoilin.a.a.j(Unknown Source)
08-27 13:01:39.000: E/AndroidRuntime(16968):    at com.xaoilin.a.a.<init>(Unknown Source)
08-27 13:01:39.000: E/AndroidRuntime(16968):    at com.xaoilin.c.a.b(Unknown Source)
08-27 13:01:39.000: E/AndroidRuntime(16968):    at com.xaoilin.c.a.<init>(Unknown Source)
08-27 13:01:39.000: E/AndroidRuntime(16968):    at com.xaoilin.f.a.<init>(Unknown Source)
08-27 13:01:39.000: E/AndroidRuntime(16968):    at com.xaoilin.f.c.a(Unknown Source)
08-27 13:01:39.000: E/AndroidRuntime(16968):    at a.a.a.b(Unknown Source)
08-27 13:01:39.000: E/AndroidRuntime(16968):    at a.a.a.l(Unknown Source)
08-27 13:01:39.000: E/AndroidRuntime(16968):    at a.a.a.a(Unknown Source)
08-27 13:01:39.000: E/AndroidRuntime(16968):    at a.a.k.a(Unknown Source)
08-27 13:01:39.000: E/AndroidRuntime(16968):    at com.xaoilin.f.b.a(Unknown Source)
08-27 13:01:39.000: E/AndroidRuntime(16968):    at com.badlogic.gdx.f.b(Unknown Source)
08-27 13:01:39.000: E/AndroidRuntime(16968):    at com.badlogic.gdx.backends.android.m.onDrawFrame(Unknown Source)
08-27 13:01:39.000: E/AndroidRuntime(16968):    at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1531)
08-27 13:01:39.000: E/AndroidRuntime(16968):    at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1248)
08-27 13:01:39.000: E/AndroidRuntime(16968): Caused by: com.badlogic.gdx.utils.bf: Error reading file: data/scroller/uiskin.json
08-27 13:01:39.000: E/AndroidRuntime(16968):    at com.badlogic.gdx.utils.o.a(Unknown Source)
08-27 13:01:39.000: E/AndroidRuntime(16968):    ... 17 more
08-27 13:01:39.000: E/AndroidRuntime(16968): Caused by: com.badlogic.gdx.utils.bf: 
08-27 13:01:39.000: E/AndroidRuntime(16968):    at com.badlogic.gdx.f.a.a.l.a(Unknown Source)
08-27 13:01:39.000: E/AndroidRuntime(16968):    at com.badlogic.gdx.f.a.a.l.b(Unknown Source)
08-27 13:01:39.000: E/AndroidRuntime(16968):    at com.badlogic.gdx.utils.o.a(Unknown Source)
08-27 13:01:39.000: E/AndroidRuntime(16968):    at com.badlogic.gdx.f.a.a.k.a(Unknown Source)
08-27 13:01:39.000: E/AndroidRuntime(16968):    ... 18 more
08-27 13:01:39.000: E/AndroidRuntime(16968): Caused by: com.badlogic.gdx.utils.b.f: Class not found: com.badlogic.gdx.graphics.g2d.BitmapFont
08-27 13:01:39.000: E/AndroidRuntime(16968):    at com.badlogic.gdx.utils.b.b.a(Unknown Source)
08-27 13:01:39.000: E/AndroidRuntime(16968):    ... 22 more
08-27 13:01:39.000: E/AndroidRuntime(16968): Caused by: java.lang.ClassNotFoundException: com.badlogic.gdx.graphics.g2d.BitmapFont
08-27 13:01:39.000: E/AndroidRuntime(16968):    at java.lang.Class.classForName(Native Method)
08-27 13:01:39.000: E/AndroidRuntime(16968):    at java.lang.Class.forName(Class.java:251)
08-27 13:01:39.000: E/AndroidRuntime(16968):    at java.lang.Class.forName(Class.java:216)
08-27 13:01:39.000: E/AndroidRuntime(16968):    ... 23 more
08-27 13:01:39.000: E/AndroidRuntime(16968): Caused by: java.lang.NoClassDefFoundError: com/badlogic/gdx/graphics/g2d/BitmapFont
08-27 13:01:39.000: E/AndroidRuntime(16968):    ... 26 more
08-27 13:01:39.000: E/AndroidRuntime(16968): Caused by: java.lang.ClassNotFoundException: Didn't find class "com.badlogic.gdx.graphics.g2d.BitmapFont" on path: DexPathList[[zip file "/data/app/com.xaoilin.soloshape-1.apk"],nativeLibraryDirectories=[/data/app-lib/com.xaoilin.soloshape-1, /vendor/lib, /system/lib]]
08-27 13:01:39.000: E/AndroidRuntime(16968):    at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:67)
08-27 13:01:39.000: E/AndroidRuntime(16968):    at java.lang.ClassLoader.loadClass(ClassLoader.java:497)
08-27 13:01:39.000: E/AndroidRuntime(16968):    at java.lang.ClassLoader.loadClass(ClassLoader.java:457)
08-27 13:01:39.000: E/AndroidRuntime(16968):    ... 26 more

如您所见,我遇到的第一个错误是读取文件:data/scroller/uiskin.json

这是试图在我的代码中读取此文件的行:

// Loads the ui's skin to be used on this example:
    uiSkin = new Skin(Gdx.files.internal("data/scroller/uiskin.json"),
            assetManager.get("data/scroller/uiskin.atlas", TextureAtlas.class));

重要的是要注意此文件从未导致实时发布崩溃,事实上,它与我的新功能完全无关正在应用程序中实施。我正在实施 GdxPay as in the Gdx-Wiki 并离线测试结果,一切都按预期进行。

然而,如前所述,由于某种原因上传到 Play 商店时,在我的代码库 完全独立的区域 中加载随机 json 文件时,它会崩溃。

正在启动

这是通过 Eclipse在我的设备上启动应用程序时发生的情况:应用程序使用 Tween Engine 加载启动画面,然后自动成功加载游戏画面。

这是启动应用 通过 Google Play 商店发布的 Alpha 测试时发生的情况:应用成功加载启动画面,然后因错误而崩溃上面关于无法读取 json 文件的消息。

我唯一的猜测是 导出的 APK 与我在使用 Eclipse 时安装的 APK 不同。我已经在 samsung Tablet 和 Smart Phone 上进行了测试,两者都产生了与上述相同的结果。

我知道 proguard 配置 会影响导出的 APK,我已经更改了几次配置设置,但在下载和 运行 从Play 商店。

供参考

我的核心游戏Class

package com.xaoilin.soloshape;

import com.badlogic.gdx.Game;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.pay.Offer;
import com.badlogic.gdx.pay.OfferType;
import com.badlogic.gdx.pay.PurchaseManagerConfig;
import com.badlogic.gdx.pay.PurchaseObserver;
import com.badlogic.gdx.pay.Transaction;
import com.badlogic.gdx.utils.GdxRuntimeException;
import com.xaoilin.SSHelpers.AssetLoader;
import com.xaoilin.Screens.SplashScreen;

public class SSGame extends Game {

    // ----- app stores -------------------------
    public static final int APPSTORE_UNDEFINED  = 0;
    public static final int APPSTORE_GOOGLE     = 1;
    public static final int APPSTORE_OUYA       = 2;
    public static final int APPSTORE_AMAZON     = 3;
    public static final int APPSTORE_DESKTOP    = 4;

    private int isAppStore = APPSTORE_UNDEFINED;

    public final static String productID_fullVersion = "fullversion";
    public static PlatformResolver m_platformResolver;
    public PurchaseManagerConfig purchaseManagerConfig;

    public PurchaseObserver purchaseObserver = new PurchaseObserver() {
        @Override
        public void handleRestore (Transaction[] transactions) {
            for (int i = 0; i < transactions.length; i++) {
                if (checkTransaction(transactions[i].getIdentifier(), true) == true) break;
            }
        }
        @Override
        public void handleRestoreError (Throwable e) {
            throw new GdxRuntimeException(e);
        }
        @Override
        public void handleInstall () {  }

        @Override
        public void handleInstallError (Throwable e) {
            Gdx.app.log("ERROR", "PurchaseObserver: handleInstallError!: " + e.getMessage());
            throw new GdxRuntimeException(e);
        }
        @Override
        public void handlePurchase (Transaction transaction) {
            checkTransaction(transaction.getIdentifier(), false);
        }
        @Override
        public void handlePurchaseError (Throwable e) { //--- Amazon IAP: this will be called for cancelled
            throw new GdxRuntimeException(e);
        }
        @Override
        public void handlePurchaseCanceled () { //--- will not be called by amazonIAP
        }
    };

    protected boolean checkTransaction (String ID, boolean isRestore) {
        boolean returnbool = false;

        if (productID_fullVersion.equals(ID)) {
            Gdx.app.log("checkTransaction", "full version found!");

            //----- put your logic for full version here!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

            returnbool = true;
        }
        return returnbool;
    }

    public SSGame () {
        setAppStore(APPSTORE_GOOGLE);   // change this if you deploy to another platform        

        // ---- IAP: define products ---------------------
        purchaseManagerConfig = new PurchaseManagerConfig();
        purchaseManagerConfig.addOffer(new Offer().setType(OfferType.CONSUMABLE).setIdentifier(productID_fullVersion));
    }

    @Override
    public void create() {
        getPlatformResolver().requestPurchaseRestore(); // check for purchases in the past
        AssetLoader.load();

        setScreen(new SplashScreen(this));
        // setScreen(new GameScreen());
    }



    @Override
    public void dispose() {
        super.dispose();
        AssetLoader.dispose();
    }

    public PlatformResolver getPlatformResolver() {
        return m_platformResolver;
    }
    public static void setPlatformResolver (PlatformResolver platformResolver) {
        m_platformResolver = platformResolver;
    }

    public int getAppStore () {
        return isAppStore;
    }
    public void setAppStore (int isAppStore) {
        this.isAppStore = isAppStore;
    }
}

我的 Android 启动器 Activity

package com.xaoilin.soloshape;

import com.badlogic.gdx.backends.android.AndroidApplication;
import com.badlogic.gdx.backends.android.AndroidApplicationConfiguration;
import android.content.Intent;
import android.os.Bundle;

public class AndroidLauncher extends AndroidApplication {
    SSGame game;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        AndroidApplicationConfiguration config = new AndroidApplicationConfiguration();
        game = new SSGame();
        initialize(game, config);

        if (game.getAppStore() == SSGame.APPSTORE_GOOGLE) {
            SSGame.setPlatformResolver(new GooglePlayResolver(game));
        }

        game.getPlatformResolver().installIAP();
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();

        // InApp: dispose payment system(s)
        game.getPlatformResolver().dispose();
    }
}

如果有人知道是什么导致应用程序在实时崩溃但在本地运行良好,那将是一个巨大的帮助。提前致谢!

Tldr; Android LibGDX 应用程序在 android 设备上启动时在本地运行良好,但当上传到 Play 商店并从 Play 商店启动时,它会因无法在我的代码的随机区域加载随机文件而崩溃在我以前的任何版本中都没有给我带来问题。

编辑

Proguard 文件

-verbose

-dontwarn javax.annotation.Nullable
-dontwarn android.support.**
-dontwarn com.badlogic.gdx.backends.android.AndroidFragmentApplication
-dontwarn com.badlogic.gdx.utils.GdxBuild
-dontwarn com.badlogic.gdx.physics.box2d.utils.Box2DBuild
-dontwarn com.badlogic.gdx.jnigen.BuildTarget*
-dontwarn com.badlogic.gdx.graphics.g2d.freetype.FreetypeBuild

-keep class com.badlogic.gdx.controllers.android.AndroidControllers

-keepclassmembers class com.badlogic.gdx.backends.android.AndroidInput* {
   <init>(com.badlogic.gdx.Application, android.content.Context, java.lang.Object, com.badlogic.gdx.backends.android.AndroidApplicationConfiguration);
}

-keepclassmembers class com.badlogic.gdx.physics.box2d.World {
   boolean contactFilter(long, long);
   void    beginContact(long);
   void    endContact(long);
   void    preSolve(long, long);
   void    postSolve(long, long);
   boolean reportFixture(long);
   float   reportRayFixture(long, float, float, float, float, float);
}

-keep class com.android.vending.billing.**
-keep class com.amazon.** {*;}
-keep class com.sec.android.iap.**
-keep class com.nokia.payment.iap.aidl.**
-keep class org.onepf.oms.appstore.**
-dontwarn org.onepf.oms.appstore.**

-keep public class com.badlogic.gdx.Gdx {
  public protected *;
}

-keep public class com.badlogic.gdx.Application {
  public protected *;
}

-keep public class com.badlogic.gdx.pay.android.IAP {
  public protected *;
}

-keep public class com.badlogic.gdx.backends.android.AndroidEventListener {
  public protected *;
}

-keep public class com.badlogic.gdx.backends.android.AndroidApplication {
  public protected *;
}

-keep public class com.badlogic.gdx.pay.android.openiab.PurchaseManagerAndroidOpenIAB {
  public protected *;
}

-keep public class com.badlogic.gdx.pay.android.googleplay.AndroidGooglePlayPurchaseManager {
  public protected *;
}

正如@Polarbear0106 所说,libGDX 的组件未包含在 APK 中。对我有用的修复是在 proguard-project.txt 文件中添加这一行:

"-保持 class com.badlogic.** {*;}"

然后正确导出并上传到 Play 商店,实时版本不再崩溃!