OneSignal / OneSignal-Android-SDK

OneSignal is a free push notification service for mobile apps. This plugin makes it easy to integrate your native Android or Amazon app with OneSignal. https://onesignal.com
Other
604 stars 368 forks source link

Trending issues: OSUtils.java line 300, com.onesignal.OSUtils.isHMSCoreInstalledAndEnabled #1085

Closed Peter-Warlock closed 4 years ago

Peter-Warlock commented 4 years ago

Description: Just updated to version 3.15.1 from 3.14.1 to fix issue OneSignalCacheCleaner.java and got a new trending issue.

Trending stability issues: OSUtils.java line 300 com.onesignal.OSUtils.isHMSCoreInstalledAndEnabled

Fatal Exception: java.lang.NoClassDefFoundError: Failed resolution of: Lcom/huawei/hms/api/HuaweiApiAvailability;
       at com.onesignal.OSUtils.isHMSCoreInstalledAndEnabled(OSUtils.java:300)
       at com.onesignal.OSUtils.supportsHMS(OSUtils.java:328)
       at com.onesignal.OSUtils.getDeviceType(OSUtils.java:360)
       at com.onesignal.OSUtils.isAndroidDeviceType(OSUtils.java:378)
       at com.onesignal.LocationController.isGooglePlayServicesAvailable(LocationController.java:286)
       at com.onesignal.LocationController.onFocusChange(LocationController.java:274)
       at com.onesignal.OneSignal.onAppLostFocus(OneSignal.java:1251)
       at com.onesignal.ActivityLifecycleHandler$AppFocusRunnable.run(ActivityLifecycleHandler.java:263)
       at android.os.Handler.handleCallback(Handler.java:873)
       at android.os.Handler.dispatchMessage(Handler.java:99)
       at android.os.Looper.loop(Looper.java:224)
       at android.os.HandlerThread.run(HandlerThread.java:65)
Caused by java.lang.ClassNotFoundException: Didn't find class "com.huawei.hms.api.HuaweiApiAvailability" on path: DexPathList[[zip file "/system/framework/org.apache.http.legacy.boot.jar", zip file "/data/app/com.warlockstudio.tank.combat.future.battles-gSXrXMlosLWnMqkC-0xKuw==/base.apk"],nativeLibraryDirectories=[/data/app/com.warlockstudio.tank.combat.future.battles-gSXrXMlosLWnMqkC-0xKuw==/lib/arm64, /data/app/com.warlockstudio.tank.combat.future.battles-gSXrXMlosLWnMqkC-0xKuw==/base.apk!/lib/arm64-v8a, /system/lib64]]
       at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:134)
       at java.lang.ClassLoader.loadClass(ClassLoader.java:379)
       at java.lang.ClassLoader.loadClass(ClassLoader.java:312)
       at com.onesignal.OSUtils.isHMSCoreInstalledAndEnabled(OSUtils.java:300)
       at com.onesignal.OSUtils.supportsHMS(OSUtils.java:328)
       at com.onesignal.OSUtils.getDeviceType(OSUtils.java:360)
       at com.onesignal.OSUtils.isAndroidDeviceType(OSUtils.java:378)
       at com.onesignal.LocationController.isGooglePlayServicesAvailable(LocationController.java:286)
       at com.onesignal.LocationController.onFocusChange(LocationController.java:274)
       at com.onesignal.OneSignal.onAppLostFocus(OneSignal.java:1251)
       at com.onesignal.ActivityLifecycleHandler$AppFocusRunnable.run(ActivityLifecycleHandler.java:263)
       at android.os.Handler.handleCallback(Handler.java:873)
       at android.os.Handler.dispatchMessage(Handler.java:99)
       at android.os.Looper.loop(Looper.java:224)
       at android.os.HandlerThread.run(HandlerThread.java:65)

I don't need and don't use any Huawei SDK and API. Is it possible to get some version of your SDK that will not cause a trending issue? There is exist some one version without a fatal bugs?

jkasten2 commented 4 years ago

@Peter-Warlock Thanks for reporting, this is odd you're seeing this crash since there is a class existent check just before attempting to use com.huawei.hms.api.HuaweiApiAvailability. hasHMSAvailabilityLibrary is called and returns early to prevent a call to isHMSCoreInstalledAndEnabled in supportsHMS.

My best guess is Proguard or R8 in your project is minifying extra code out of your app where these checks would have been.

Could you provide the following details so we can look into producing the issue?

  1. app/build.gradle
  2. Your project's proguard-rules.pro file if you have one.
    • Check for proguardFiles in your app/build.gradle as it might be a different name.
  3. Are you able to produce the issue?
    • As a debug build?
    • As a release build?
  4. Could you provide an APK here or to OneSignal support or a link to a public store link if it is happening in production right now?
Peter-Warlock commented 4 years ago

Maybe it's Proguard or R8, but I don't see proguard rule here: https://documentation.onesignal.com/docs/android-sdk-setup

  1. I used libGDX. I think it will too hard to reproduce it on your side. But as I understood you want check other libs and settings. Ok.

app/build.gradle

buildscript {
    repositories {
        mavenCentral()
        maven { url "https://plugins.gradle.org/m2/" }
        maven { url "https://oss.sonatype.org/content/repositories/snapshots/" }
        jcenter()
        google()
        maven {
            url 'https://maven.google.com/'
            name 'Google'
        }

    }
    dependencies {
      classpath 'org.wisepersist:gwt-gradle-plugin:1.0.6'
      classpath 'com.android.tools.build:gradle:4.0.0'
        classpath 'com.mobidevelop.robovm:robovm-gradle-plugin:2.3.9'

        // firebase
        classpath 'com.google.gms:google-services:4.3.3'

        // Add the Firebase Crashlytics Gradle plugin.
        classpath 'com.google.firebase:firebase-crashlytics-gradle:2.2.0'

        // one signal
        //https://github.com/OneSignal/OneSignal-Gradle-Plugin/releases
        classpath 'gradle.plugin.com.onesignal:onesignal-gradle-plugin:0.12.8'

    }
}

allprojects {
    apply plugin: "eclipse"
    apply plugin: "idea"

    version = '1.0'
    ext {
        appName = "game7"
        gdxVersion = '1.9.10'

        roboVMVersion = '2.3.9'
        roboVMGradleVersion = '2.3.9'
        robopodsVersion = "2.2.3"
      altpodsVersion = "1.3.0-SNAPSHOT" // https://github.com/dkimitsa/robovm-robopods
        box2DLightsVersion = '1.4'
        ashleyVersion = '1.7.0'
        aiVersion = '1.8.0'
    }

    repositories {
        mavenCentral()
        jcenter()
        maven { url "https://oss.sonatype.org/content/repositories/snapshots/" }
        maven { url "https://oss.sonatype.org/content/repositories/releases/" }
        maven { url "https://maven.google.com"        } // new Google support Library source
        maven { url "https://artifactory.appodeal.com/appodeal"     } // AppoDeal
        google()
        flatDir {
            dirs 'libs'
        }
    }
}

project(":desktop") {
    apply plugin: "java"

    dependencies {
        implementation project(":core")
        implementation "com.badlogicgames.gdx:gdx-backend-lwjgl:$gdxVersion"
        //compile "com.badlogicgames.gdx:gdx-backend-lwjgl3:$gdxVersion"
        implementation "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-desktop"
        implementation "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-desktop"

        //compile "com.badlogicgames.gdx:gdx-controllers-lwjgl3:$gdxVersion"
        implementation "com.badlogicgames.gdx:gdx-controllers-desktop:$gdxVersion"
        implementation "com.badlogicgames.gdx:gdx-controllers-platform:$gdxVersion:natives-desktop"
    }
}

project(":android") {
    apply plugin: 'com.android.application'

    // Add the Firebase Crashlytics plugin.
    apply plugin: 'com.google.firebase.crashlytics'

    // one signal
    apply plugin: 'com.onesignal.androidsdk.onesignal-gradle-plugin'

    configurations { natives }

    dependencies {
        implementation project(":core")
        implementation "com.badlogicgames.gdx:gdx-backend-android:$gdxVersion"
        natives "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-armeabi"
        natives "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-armeabi-v7a"
        natives "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-arm64-v8a"
        natives "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-x86"
        natives "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-x86_64"

        implementation "com.badlogicgames.gdx:gdx-freetype:$gdxVersion"
        natives "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-armeabi"
        natives "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-armeabi-v7a"
        natives "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-arm64-v8a"
        natives "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-x86"
        natives "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-x86_64"

        implementation "com.badlogicgames.gdx:gdx-controllers:$gdxVersion"
        implementation "com.badlogicgames.gdx:gdx-controllers-android:$gdxVersion"

      implementation 'androidx.multidex:multidex:2.0.1'

        implementation "com.googlecode.gwt-crypto:gwt-crypto:2.3.0"

    }

}

project(":core") {
    apply plugin: "java"

    dependencies {
        implementation "com.badlogicgames.gdx:gdx:$gdxVersion"
        implementation "com.badlogicgames.gdx:gdx-freetype:$gdxVersion"

        implementation "com.badlogicgames.gdx:gdx-controllers:$gdxVersion"

    }
}

tasks.eclipse.doLast {
    delete ".project"
}

app/android/build.gradle

android {
    buildToolsVersion "29.0.3"
    compileSdkVersion 29
    sourceSets {
        main {
            manifest.srcFile 'AndroidManifest.xml'
            java.srcDirs = ['src']
            aidl.srcDirs = ['src']
            renderscript.srcDirs = ['src']
            res.srcDirs = ['res']
            assets.srcDirs = ['assets']
            assets {
                exclude '**/data/*'
                exclude '**/.Backup/*'
                exclude '**/.backup/*'
                exclude '**/.test/*'
                exclude '**/com.warlockstudio/*'
            }

            jniLibs.srcDirs = ['libs']
        }

    }
    packagingOptions {
        exclude 'META-INF/robovm/ios/robovm.xml'
    }
    defaultConfig {
        minSdkVersion 16
        targetSdkVersion 29
        applicationId "com.warlockstudio.tank.combat.future.battles"
        multiDexEnabled true

        manifestPlaceholders = [
                onesignal_app_id: 'xxxxxxxxx__here-my-onesignal_app_id__xxxxxxxxxxx',
                // Project number pulled from dashboard, local value is ignored.
                onesignal_google_project_number: 'REMOTE'
        ]

        setProperty("archivesBaseName", "$project.ext.appName-"+new Date().format('yyyyMMdd-HHmmss'))
    }
    buildTypes {
        release {
            shrinkResources true // This must be first
            minifyEnabled true   // This must be after shrinkResources
            proguardFile 'D:/Android/asprojects/game7/android/proguard-project-new.cfg'

        }
    }
    aaptOptions {
        ignoreAssetsPattern '!*.Backup:!/data*:!data:!*.test:!/.test/*:!*com.warlockstudio:!/com.warlockstudio/*:'
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

}
// called every time gradle gets executed, takes the native dependencies of
// the natives configuration, and extracts them to the proper libs/ folders
// so they get packed with the APK.
task copyAndroidNatives {
    doFirst {
        file("libs/armeabi/").mkdirs()
        file("libs/armeabi-v7a/").mkdirs()
        file("libs/arm64-v8a/").mkdirs()
        file("libs/x86_64/").mkdirs()
        file("libs/x86/").mkdirs()

        configurations.natives.files.each { jar ->
            def outputDir = null
            if (jar.name.endsWith("natives-arm64-v8a.jar")) outputDir = file("libs/arm64-v8a")
            if (jar.name.endsWith("natives-armeabi-v7a.jar")) outputDir = file("libs/armeabi-v7a")
            if(jar.name.endsWith("natives-armeabi.jar")) outputDir = file("libs/armeabi")
            if(jar.name.endsWith("natives-x86_64.jar")) outputDir = file("libs/x86_64")
            if(jar.name.endsWith("natives-x86.jar")) outputDir = file("libs/x86")
            if(outputDir != null) {
                copy {
                    from zipTree(jar)
                    into outputDir
                    include "*.so"
                }
            }
        }
    }
}

tasks.whenTaskAdded { packageTask ->
    if (packageTask.name.contains("package")) {
        packageTask.dependsOn 'copyAndroidNatives'
    }
}

task run(type: Exec) {
    def path
    def localProperties = project.file("../local.properties")
    if (localProperties.exists()) {
        Properties properties = new Properties()
        localProperties.withInputStream { instr ->
            properties.load(instr)
        }
        def sdkDir = properties.getProperty('sdk.dir')
        if (sdkDir) {
            path = sdkDir
        } else {
            path = "$System.env.ANDROID_HOME"
        }
    } else {
        path = "$System.env.ANDROID_HOME"
    }

    def adb = path + "/platform-tools/adb"
    commandLine "$adb", 'shell', 'am', 'start', '-n', 'com.warlockstudio.game7/com.warlockstudio.game7.AndroidLauncher'
}
// sets up the Android Eclipse project, using the old Ant based build.
eclipse {
    // need to specify Java source sets explicitly, SpringSource Gradle Eclipse plugin
    // ignores any nodes added in classpath.file.withXml
    sourceSets {
        main {
            java.srcDirs "src", 'gen'
        }
    }

    jdt {
        sourceCompatibility = 1.6
        targetCompatibility = 1.6
    }

    classpath {
        plusConfigurations += [project.configurations.compile]
        containers 'com.android.ide.eclipse.adt.ANDROID_FRAMEWORK', 'com.android.ide.eclipse.adt.LIBRARIES'
    }

    project {
        name = appName + "-android"
        natures 'com.android.ide.eclipse.adt.AndroidNature'
        buildCommands.clear();
        buildCommand "com.android.ide.eclipse.adt.ResourceManagerBuilder"
        buildCommand "com.android.ide.eclipse.adt.PreCompilerBuilder"
        buildCommand "org.eclipse.jdt.core.javabuilder"
        buildCommand "com.android.ide.eclipse.adt.ApkBuilder"
    }
}
// sets up the Android Idea project, using the old Ant based build.
idea {
    module {
        sourceDirs += file("src");
        scopes = [COMPILE: [plus: [project.configurations.compile]]]

        iml {
            withXml {
                def node = it.asNode()
                def builder = NodeBuilder.newInstance();
                builder.current = node;
                builder.component(name: "FacetManager") {
                    facet(type: "android", name: "Android") {
                        configuration {
                            option(name: "UPDATE_PROPERTY_FILES", value: "true")
                        }
                    }
                }
            }
        }
    }
}
dependencies {
    implementation 'com.amplitude:android-sdk:2.25.2'
    implementation 'com.squareup.okhttp3:okhttp:3.12.2' // For minSDK lower than 21, change your OkHttp version to 3.12.2 in gradle like this

    // CONSENT SDK
    implementation 'com.google.android.ads.consent:consent-library:1.0.8'

    implementation 'com.android.installreferrer:installreferrer:1.1.2'

    // For Appodeal MyTarget
    implementation 'com.google.android.exoplayer:exoplayer-core:2.8.4'
    implementation 'com.google.android.exoplayer:exoplayer-hls:2.8.4'

    /////////////////////////////////////////////////////
    // SUPPORT LIBRARY
    /////////////////////////////////////////////////////
    // https://developers.google.com/android/guides/setup
    implementation 'androidx.appcompat:appcompat:1.1.0'

    //implementation 'com.google.firebase:firebase-core:17.4.1'
    implementation 'com.google.firebase:firebase-analytics:17.4.3'
    implementation 'com.google.firebase:firebase-ads:19.2.0'
    implementation 'com.google.firebase:firebase-crashlytics:17.1.0'

    implementation 'com.google.android.gms:play-services-games:19.0.0'
    implementation 'com.google.android.gms:play-services-analytics:17.0.0'

    implementation 'com.facebook.android:facebook-android-sdk:5.8.0'

    // one signal https://github.com/OneSignal/OneSignal-Android-SDK/releases
    implementation 'com.onesignal:OneSignal:3.15.1'

    implementation ('com.appodeal.ads:sdk:2.6.4.+') {
        exclude group: 'com.appodeal.ads.sdk.networks', module: 'amazon_ads'
        exclude group: 'com.appodeal.ads.sdk.networks', module: 'appodeal'
        exclude group: 'com.appodeal.ads.sdk.networks', module: 'facebook'
        exclude group: 'com.appodeal.ads.sdk.networks', module: 'nast'
        exclude group: 'com.appodeal.ads.sdk.networks', module: 'tapjoy'
        exclude group: 'com.appodeal.ads.sdk.networks', module: 'yandex'
        exclude group: 'com.appodeal.ads.sdk.networks', module: 'vungle'
    }
    implementation fileTree(include: ['*.jar', '*.aar'], dir: 'libs')
}

apply plugin: 'com.google.gms.google-services'
  1. proguard-project-new.cfg

    
    
    # To enable ProGuard in your project, edit project.properties
    # to define the proguard.config property as described in that file.
    #
    # Add project specific ProGuard rules here.
    # By default, the flags in this file are appended to flags specified
    # in ${sdk.dir}/tools/proguard/proguard-android.txt
    # You can edit the include path and order by changing the ProGuard
    # include property in project.properties.
    #
    # For more details, see
    #   http://developer.android.com/guide/developing/tools/proguard.html
    
    # Add any project specific keep options here:
    
    -verbose
    
    -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*
    
    ############################################
    -optimizationpasses 3
    -ignorewarnings
    -dontusemixedcaseclassnames
    -dontskipnonpubliclibraryclasses
    -dontpreverify
    -verbose
    -optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
    -printconfiguration
    ############################################
    
    ############################################
    #CrashlyticsCore
    ############################################
    -keep class com.crashlytics.** { *; }
    -keep class com.google.android.gms.measurement.** { *; }
    -keep class com.google.android.gms.measurement.AppMeasurement { *; }
    -keep class com.google.android.gms.measurement.AppMeasurement$OnEventListener { *; }
    -dontwarn com.google.android.gms.measurement.**
    
    ############################################
    # libGDX
    ############################################
    -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.badlogic.gdx.backends.** { *; }
    -keep class com.badlogic.gdx.math.** { *; }
    -keep class com.badlogic.gdx.Gdx.** { *; }
    -keep class com.badlogic.gdx.assets.** { *; }
    -keep class com.badlogic.gdx.audio.** { *; }
    -keep class com.badlogic.gdx.graphics.** { *; }
    -keep class com.badlogic.gdx.utils.** { *; }
    -keep class com.badlogic.gdx.Net.** { *; }
    -keep class com.badlogic.gdx.files.** { *; }
    -keep class com.badlogic.gdx.InputMultiplexer.** { *; }
    -keep class com.badlogic.gdx.controllers.** { *; }
    
    -keep class * implements com.badlogic.gdx.utils.Json*
    
    -keep class com.badlogic.gdx.jnigen.NativeCodeGenerator
    -keep class com.badlogic.gdx.jnigen.AntScriptGenerator
    -keep class com.badlogic.gdx.jnigen.BuildConfig
    -keep class com.badlogic.gdx.jnigen.AntScriptGenerator
    
    -keep class com.google.android.chimera.** { *; }
    
    -keep class com.google.android.apps.gmm.** { *; }
    -keep class android.app.job.** { *; }
    -keep class android.app.job.JobScheduler.** { *; }
    -keep class android.util.Rational.** { *; }
    -keep class javax.net.ssl.** { *; }
    -keep class com.google.android.gms.** { *; }
    -keep class android.graphics.drawable.RippleDrawable.** { *; }
    -keep class android.media.** { *; }
    -keep class android.content.ContextWrapper.** { *; }
    -keep class android.content.pm.** { *; }
    -keep class android.app.NotificationManager.** { *; }
    
    # FOR VUNGLE
    #-keep class android.support.v13.** { *; }
    -keep class com.vungle.publisher.FullScreenAdActivity { *; }
    
    # Preserve the special static methods that are required in all enumeration classes.
    -keepclassmembers enum * {
        public static **[] values();
        public static ** valueOf(java.lang.String);
    }
    
    #-keep class com.badlogic.gdx.** {
    #   *;
    #}
    
    #############################################
    # GOOGLE BILLING
    #############################################
    -keep class com.android.vending.billing.**
    
    #############################################
    # Amplitude SDK
    #############################################
    -keep class com.google.android.gms.ads.** { *; }
    -dontwarn okio.**
    
    #############################################
    # APPODEAL
    #############################################
    
    -dontwarn com.appodeal.ads.**
    -dontwarn com.chartboost.**
    -dontwarn com.mopub.**
    -dontwarn com.facebook.**
    -dontwarn com.jirbo.adcolony.**
    -dontwarn com.vungle.**
    -dontwarn com.startapp.**
    -dontwarn com.yandex.**
    -dontwarn com.inmobi.**
    -dontwarn com.appodeal.ads.utils.**
    -dontwarn com.google.android.gms.internal.**
    -dontwarn com.cmcm.adsdk.**
    
    # Cheetah
    -keep class com.cmcm.adsdk.** { *;}
  1. No. I don't see this bug at testing. But Firebase notify me about "trending issue" for a new build a day after I released a new version with 3.15.1. 43% of devices with that issue is HUAWEI, 21%=vivo, 19%=OPPO. As I said before, I don't have Huawai, I don't use any Huawei SDK or API. Also, Huawei is not most popular device for this game. Most popular as usual Samsung + Xiaomi, but as I see there is no crash with that devices. 28% of devices with Android 6, 70% of devices - device state = background.

  2. Here the link into Google Play: https://play.google.com/store/apps/details?id=com.warlockstudio.tank.combat.future.battles

Peter-Warlock commented 4 years ago

Do you have any news? Almost a hundred crashes every day! Is there any way to get rid of this bug? ASAP!

jkasten2 commented 4 years ago

Reproducing Issue

@Peter-Warlock Thanks for the details, I was not able to reproduce the issue by using your proguard-project-new.cfg and some of the basic settings from your build.gradle files. However I did take a look at your APK and found that the class exists checks for HMS were completely non-existent which will cause this issue. I believe the only thing that should be minifying code is Proguard and R8 as part of the normal Android Studio / Gradle build process, unless you have some else you run your app through?

Libraries can also their own consumer Proguard configuration changes, normally this is a safelist but one of them could be making other changes.

Providing Additional details

Please add the following to your proguard-project-new.cfg.

-printconfiguration proguard_printconfiguration.txt

This will generate a full Proguard file including settings from all libraries as well so we can attempt to reproduce the issue. The proguard_printconfiguration.txt should be located under you app folder, however if you have issues finding it then you can change this to a full path instead.

Workaround

As a quick fix you could add the following which will prevent Proguard and R8 from minifying the code. -keep class com.onesignal.** {*;} The only downside being an APK size increase of a few 100 KB

Peter-Warlock commented 4 years ago

I added -keep class com.onesignal.** {*;} in pro-guard. Build new build of the game. The size increased. Ok, I upload it into Google Play. Wait, and got the same

Trending issues. Issues rapidly gaining momentum OSUtils.java line 168com.onesignal.OSUtils.hasHMSAvailabilityLibrary

Right now this issue has 574 crashes affecting 175 users.

Fatal Exception: java.lang.NoClassDefFoundError: Failed resolution of: Lcom/huawei/hms/api/HuaweiApiAvailability; at com.onesignal.OSUtils.hasHMSAvailabilityLibrary(OSUtils.java:168) at com.onesignal.OSUtils.supportsHMS(OSUtils.java:324) at com.onesignal.OSUtils.getDeviceType(OSUtils.java:360) at com.onesignal.OSUtils.isAndroidDeviceType(OSUtils.java:378) at com.onesignal.LocationController.isGooglePlayServicesAvailable(LocationController.java:286) at com.onesignal.LocationController.onFocusChange(LocationController.java:274) at com.onesignal.OneSignal.onAppLostFocus(OneSignal.java:1251) at com.onesignal.ActivityLifecycleHandler$AppFocusRunnable.run(ActivityLifecycleHandler.java:263) at android.os.Handler.handleCallback(Handler.java:888) at android.os.Handler.dispatchMessage(Handler.java:100) at android.os.Looper.loop(Looper.java:213) at android.os.HandlerThread.run(HandlerThread.java:67)

Caused by java.lang.ClassNotFoundException: com.huawei.hms.api.HuaweiApiAvailability at com.onesignal.OSUtils.hasHMSAvailabilityLibrary(OSUtils.java:168) at com.onesignal.OSUtils.supportsHMS(OSUtils.java:324) at com.onesignal.OSUtils.getDeviceType(OSUtils.java:360) at com.onesignal.OSUtils.isAndroidDeviceType(OSUtils.java:378) at com.onesignal.LocationController.isGooglePlayServicesAvailable(LocationController.java:286) at com.onesignal.LocationController.onFocusChange(LocationController.java:274) at com.onesignal.OneSignal.onAppLostFocus(OneSignal.java:1251) at com.onesignal.ActivityLifecycleHandler$AppFocusRunnable.run(ActivityLifecycleHandler.java:263) at android.os.Handler.handleCallback(Handler.java:888) at android.os.Handler.dispatchMessage(Handler.java:100) at android.os.Looper.loop(Looper.java:213) at android.os.HandlerThread.run(HandlerThread.java:67)

It just a stupid! Why you call this freaking huawai code if I don't use any freaking huawei api? Why you call com.huawei.xxx without checking is it available or not? Why you don't wrap it by try...catch to prevent with stupid crashing? Tell me ASAP, how fast you can fix this stupid bug and give me a real working version without that lamer's bugs.

b99202021 commented 4 years ago

Please help, I am running into the same issue

Caused by java.lang.ClassNotFoundException
Didn't find class "com.huawei.hms.api.HuaweiApiAvailability" on path: DexPathList[[zip file "/data/app/live.free.tv_tw-1/base.apk", zip file "/data/app/live.free.tv_tw-1/split_config.armeabi_v7a.apk", zip file "/data/app/live.free.tv_tw-1/split_config.hdpi.apk", zip file "/data/app/live.free.tv_tw-1/split_config.zh.apk"],nativeLibraryDirectories=[/data/app/live.free.tv_tw-1/lib/arm, /vendor/lib, /system/lib]]
jkasten2 commented 4 years ago

@Peter-Warlock

Thanks for the latest stacktrace.

We already have a try-catch for NoClassDefFoundError exactly where your crash is being reported. https://github.com/OneSignal/OneSignal-Android-SDK/blob/3.15.1/OneSignalSDK/onesignal/src/main/java/com/onesignal/OSUtils.java#L166-L171

It seems -keep class com.onesignal.** {*;} resulted not obfuscating / minifying the OneSignal classes. However something in your build process is still removing catches that it should not. Specific the catches for NoClassDefFoundError in this case, possibly others.

Proguard or R8 Bug

There have been some reports of Proguard bugs with removing try-catches. However they seem to have been fixed log ago

I also tried to search the R8 bug tracker but did not find any things specific enough to your case. https://issuetracker.google.com/issues?q=componentid:326788%20NoClassDefFoundError%20 However there could still be a bug with R8 under very specific conditions.

Needed details

We will need to be able to reproduce the issue on our end to help find the root cause.

  1. Provide the full printconfiguration noted my https://github.com/OneSignal/OneSignal-Android-SDK/issues/1085#issuecomment-655674615 above.
  2. Do you use R8 or Proguard?
    • Check if you have enableR8 in your gradle.properties or anywhere in your project.
    • Since you have a newer version of the AGP it will default R8 on unless you disable it.
  3. Any other build or obfuscation tools used as part of building your APK?

Confirming the issue in Java bytecode

Smali of the hasHMSAvailabilityLibrary method from dex in APK

  1. Our test APK built with your provided proguard-project-new.cfg.

    .method private static hasHMSAvailabilityLibrary()Z
    .registers 2
    
    .line 168
    :try_start_0
    const-class v0, Lcom/huawei/hms/api/HuaweiApiAvailability;
    :try_end_2
    .catch Ljava/lang/NoClassDefFoundError; {:try_start_0 .. :try_end_2} :catch_4
    
    const/4 v0, 0x1
    
    return v0
    
    .line 169
    :catch_4
    move-exception v0
    
    .line 170
    .local v0, "e":Ljava/lang/NoClassDefFoundError;
    const/4 v1, 0x0
    
    return v1
    .end method
  2. From your APK on the Google Play Store

    .method private static hasHMSAvailabilityLibrary()Z
    .registers 1
    
    .line 168
    const-class v0, Lcom/huawei/hms/api/HuaweiApiAvailability;
    
    const/4 v0, 0x1
    
    return v0
    .end method

The smali from your APK shows that the catch for NoClassDefFoundError is not in your dex's bytecode in your released APK. Why this is the case is unknown until we have a build process reproducing the outputted results as an APK.

Inspecting the smali

The above was discovered with the jadx tool: https://github.com/skylot/jadx

Open your APK with jadx and look for hasHMSPushKitLibrary. Then select smali on the bottom tab (jadex does NOT correctly show you the catch with it's java code option . If you see a catch for NoClassDefFoundError under this method your build process is setup correctly.

image

After you have jadx setup you can perform some trial and error if you wish to attempt to fix the error from your end. If you found a solution let us know as I can help others.

jkasten2 commented 4 years ago

@b99202021 Your message is different, this is an expected warning when the app is started. It won't have any effect on the runtime of your app.

Peter-Warlock commented 4 years ago

@jkasten2

I looked in your source code and now I see the problem. The way you checked for class exist or not is wrong. Minifier will remove try....catch... because you can't build this code if you don't have that class -> if you have it - you don't need try...catch. 1

Here is correct and worked code:

    public boolean isClass(String className) {
        try {
            Class.forName(className);
            return true;
        } catch (final ClassNotFoundException e) {
            return false;
        }
    }

Class.forName able to generate ClassNotFoundException exception, Minifier know about it, so no one will remove try...catch in this case.

Usage in your case is like this:

private static boolean hasHMSAvailabilityLibrary() {
         return isClass("com.huawei.hms.api.HuaweiApiAvailability");
}

I tested it. I builded APK with a both ways. I don't have any huawai api, so I changed it to Applovin classes just for test. Here decompiled result as code. 2

..and as smali 3

After releasing the game with that bug, my daily new users dropped by x10. So, few days ago, I tired to wait fast fix from you and just rolled back to v3.13.1 of OneSignal.

I hope you will change the way as you cheked for class exist to way as I gave you in this message and it will solve the problem.

jkasten2 commented 4 years ago

@Peter-Warlock Thanks for the suggestion, however we have had issues with string based runtime detection if a class exists with proguard as well. Instead of the try-catch being removed the SDK won't think the class is there when it is as Proguard renames the class.

Please provide the details above so we reproduce the try-catch removal, we should be able to find a solution from there.

Issue only if "Google Play services app" missing or disabled

The crash you are seeing only happens if the device has disabled the "Google Play services" app on the device. If they downloaded your app from the Google Play store this won't be a problem as they would have needed it to download your app. https://github.com/OneSignal/OneSignal-Android-SDK/blob/3.15.1/OneSignalSDK/onesignal/src/main/java/com/onesignal/OSUtils.java#L356-L357 However if your app is on other stores then this would be a larger problem. In that case using OneSignal at version 3.14.X would be recommend until we can solve this issue.

Peter-Warlock commented 4 years ago

@jkasten2 How proguard can rename system class com.huawei.hms.api.HuaweiApiAvailability? Proguard can obfuscate some inner classes, that was not be marked as -keep class xxxx, but how it can obfuscate a system classes? Or use -keep class com.huawei.hms.api.* {;} at the build time of your SDK if it's not a system class.

I don't upload the game in store other than Google Play. As I said before, I don't use any huawai api and don't upload it to AppGalery Store.

OneSignal v3.13.1 so far seems good.

Info that you asked:

  1. here is printconfiguration for the latest build with OneSignal 3.15.1 proguard_printconfiguration.txt

  2. I tried R8 as it was released as pre-release, but got some strange bugs in some strange place on some old devices with Mediatec chip. I was contacted Google, they tried to fix it, but at least in the next version it was not fixed. So, I disabled R8 and continue to use ProGuard by using: android.enableR8 = false in my gradle.properties. I used the latest release of Android Studio 4.0.

  3. I don't use any other obfuscation tools.

Hope it will help.

jkasten2 commented 4 years ago

@Peter-Warlock Thanks for the full proguard config, I was able to reproduce the issue!

Fix

It seems since there isn't a method call or other evaluations in the try or catch it seem Proguard thought it was safe to remove. Simply changing com.huawei.hms.api.HuaweiApiAvailability.class.getName(); from a null check resulted in keeping the try-catch. I have fixed this in PR #1098 with more details.

Configurations Affected

The issue only affects Proguard it seems, not R8. Also only if specific Proguard settings are used. One being proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rule.pro'. However if the less aggressive 'proguard-android.txt' is used with Proguard there also was not an issue.

Peter-Warlock commented 4 years ago

@jkasten2 Glad to hear it!!! So, it will be fixed in next release?

jkasten2 commented 4 years ago

@Peter-Warlock Yes, correct, thanks for providing all the requested details! Wouldn't have been able to reproduce and hunt down the issue without them.

raghav2945 commented 2 years ago

This problem has resurfaced with your version: 4.6.3. for us [Audiomack]. The stacks looks similar but still I am uploading the latest stack-trace from Firebase.

Stack-trace

Fatal Exception: java.lang.NoClassDefFoundError: Failed resolution of: Lcom/huawei/hms/api/HuaweiApiAvailability; at com.onesignal.OSUtils.isHMSCoreInstalledAndEnabled(OSUtils.java:289) at com.onesignal.OSUtils.supportsHMS(OSUtils.java:317) at com.onesignal.OSUtils.getDeviceType(OSUtils.java:349) at com.onesignal.OSUtils.initializationChecker(OSUtils.java:112) at com.onesignal.OneSignal.init(OneSignal.java:796) at com.onesignal.OneSignal.setAppId(OneSignal.java:692) at com.onesignal.OneSignal.reassignDelayedInitParams(OneSignal.java:1136) at com.onesignal.OneSignal.onRemoteParamSet(OneSignal.java:844) at com.onesignal.OneSignal$6.complete(OneSignal.java:1077) at com.onesignal.OneSignalRemoteParams.processJson(OneSignalRemoteParams.java:206) at com.onesignal.OneSignalRemoteParams.access$100(OneSignalRemoteParams.java:12) at com.onesignal.OneSignalRemoteParams$1.onSuccess(OneSignalRemoteParams.java:151) at com.onesignal.OneSignalRestClient$5.run(OneSignalRestClient.java:283) at java.lang.Thread.run(Thread.java:818)

Caused by java.lang.ClassNotFoundException: Didn't find class "com.huawei.hms.api.HuaweiApiAvailability" on path: DexPathList[[zip file "/system/framework/android.test.runner.jar", zip file "/data/app/com.audiomack-1/base.apk"],nativeLibraryDirectories=[/data/app/com.audiomack-1/lib/arm64, /data/app/com.audiomack-1/base.apk!/lib/arm64-v8a, /vendor/lib64, /system/lib64]] at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56) at java.lang.ClassLoader.loadClass(ClassLoader.java:511) at java.lang.ClassLoader.loadClass(ClassLoader.java:469) at com.onesignal.OSUtils.isHMSCoreInstalledAndEnabled(OSUtils.java:289) at com.onesignal.OSUtils.supportsHMS(OSUtils.java:317) at com.onesignal.OSUtils.getDeviceType(OSUtils.java:349) at com.onesignal.OSUtils.initializationChecker(OSUtils.java:112) at com.onesignal.OneSignal.init(OneSignal.java:796) at com.onesignal.OneSignal.setAppId(OneSignal.java:692) at com.onesignal.OneSignal.reassignDelayedInitParams(OneSignal.java:1136) at com.onesignal.OneSignal.onRemoteParamSet(OneSignal.java:844) at com.onesignal.OneSignal$6.complete(OneSignal.java:1077) at com.onesignal.OneSignalRemoteParams.processJson(OneSignalRemoteParams.java:206) at com.onesignal.OneSignalRemoteParams.access$100(OneSignalRemoteParams.java:12) at com.onesignal.OneSignalRemoteParams$1.onSuccess(OneSignalRemoteParams.java:151) at com.onesignal.OneSignalRestClient$5.run(OneSignalRestClient.java:283) at java.lang.Thread.run(Thread.java:818)