Closed TsmileAssassin closed 4 years ago
Previous reports of similar issues mostly forgot to enable Java 8 support (for example: #5600). Can you check that your gradle config includes the following lines?
compileOptions {
targetCompatibility JavaVersion.VERSION_1_8
}
You could also try to clean all Android Studio caches ("File -> Invalidate Caches / Restart") and then also clean and rebuild your project to exclude unwanted side effects from previous versions of ExoPlayer.
I experience exactly the same issue. I have targetCompatibility JavaVersion.VERSION_1_8 included. This issue is only visible if generating signed builds, it doesn't matter if it's debug or release.
The only solution I have found is to disable D8 desugaring by adding the following line to gradle.properties:
android.enableD8.desugaring=false
This solution however is not ok. I am developing a library and I can't force the users to use this workaround.
I have targetCompatibility JavaVersion.VERSION_1_8 included
I can't reproduce this in my setup. Have you tried the suggested cleaning and rebuilding steps?
If you did and the problem persists, could you also tell us the Android Studio version and gradle version you are using? And also how you depend on ExoPlayer and other noteworthy build setting that may help us to reproduce the issue.
@tonihei Please note that this is only reproducible when a signed builds (it doesn't matter if you use debug or release).
I am using:
Android Studio 3.5.3 Gradle 5.4.1
Nothing helps other than android.enableD8.desugaring=false This could maybe also be a bug in D8.
There must be something else.
I just did the following:
compileOptions { targetCompatibility JavaVersion.VERSION_1_8 }
to the apps' build.gradleminifyEnabled true
and shrinkResources true
implementation 'com.google.android.exoplayer:exoplayer:2.11.1'
signingConfigs {
signingConfig {
storeFile file('~/.android/debug.keystore')
storePassword 'android'
keyAlias = 'androiddebugkey'
keyPassword 'android'
}
}
<uses-permission android:name="android.permission.INTERNET"/>
Added a very basic ExoPlayer playback to the acitivity and made sure that the method in your stack trace is used in my code and the code imported by ExoPlayer:
@Override
protected void onResume() {
super.onResume();
player = new SimpleExoPlayer.Builder(this).build();
player.addAnalyticsListener(new EventLogger(null));
player.addListener(new Player.EventListener() {
@Override
public void onTimelineChanged(Timeline timeline, int reason) {
Log.d("TAG", "Timeline changed.");
}
});
player.prepare(
new DashMediaSource.Factory(
new DefaultDataSourceFactory(
this, Util.getUserAgent(this, "myApplication")))
.createMediaSource(
Uri.parse("https://storage.googleapis.com/wvmedia/clear/h264/tears/tears.mpd")));
player.setPlayWhenReady(true);
}
@Override
protected void onPause() {
super.onPause();
player.release();
}
Running this application on a Nexus 6P works without any crashes. And I can see both the signing and the R8 step happening during the build.
Could try to some up with a similar basic setup that reproduces the problem? This would help to find the offending part and whether there is something we can do about it.
@tonihei
It really looks like that this is some kind of Android Studio or Gradle caching bug. Invalidate caches and restart did the trick, It's strange as I did this before and it didn't help. Currently I can't reproduce this anymore. I really hope that this is the solution.
Thank you for your help.
Good to know. We had this before that ExoPlayer updates with subtle API changes caused Android Studio to build something wrong, possible based on cached data. Invalidating the caches helped in almost all cases so far :)
@TsmileAssassin Can you also try to do invalidate caches and restart again to see if it works?
@tonihei Actually the issue persists. I finally found the cause. It's a bug in Gradle Plugin and it has something to do with Dexing Artifact Transformations. Steps to reproduce:
You will see the crash:
java.lang.AbstractMethodError: abstract method "void com.google.android.exoplayer2.Player$EventListener.onTimelineChanged(com.google.android.exoplayer2.Timeline, int)"
at com.google.android.exoplayer2.ExoPlayerImpl$PlaybackInfoUpdate.lambda$run$0$ExoPlayerImpl$PlaybackInfoUpdate(ExoPlayerImpl.java:804)
at com.google.android.exoplayer2.-$$Lambda$ExoPlayerImpl$PlaybackInfoUpdate$N_S5kRfhaRTAkH28P5luFgKnFjQ.invokeListener(Unknown Source:2)
at com.google.android.exoplayer2.BasePlayer$ListenerHolder.invoke(BasePlayer.java:182)
at com.google.android.exoplayer2.ExoPlayerImpl.invokeAll(ExoPlayerImpl.java:845)
at com.google.android.exoplayer2.ExoPlayerImpl.access$000(ExoPlayerImpl.java:43)
at com.google.android.exoplayer2.ExoPlayerImpl$PlaybackInfoUpdate.run(ExoPlayerImpl.java:802)
at com.google.android.exoplayer2.ExoPlayerImpl.notifyListeners(ExoPlayerImpl.java:736)
at com.google.android.exoplayer2.ExoPlayerImpl.updatePlaybackInfo(ExoPlayerImpl.java:710)
at com.google.android.exoplayer2.ExoPlayerImpl.handlePlaybackInfo(ExoPlayerImpl.java:652)
at com.google.android.exoplayer2.ExoPlayerImpl.handleEvent(ExoPlayerImpl.java:595)
at com.google.android.exoplayer2.ExoPlayerImpl$1.handleMessage(ExoPlayerImpl.java:127)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loop(Looper.java:214)
The crash doesn't happen if I create a maven repo that includes the Exo Player dependencies automatically by using transitive true. If not using transitive true and providing the Exo Player dependencies inside the app's build.gradle file it crashes. There is a workaround that fixes this issue by using: android.enableDexingArtifactTransform=false This however is not a solution for me as I can't force users to do this in their App.
Please refer to https://issuetracker.google.com/issues/139821726 and https://www.reddit.com/r/androiddev/comments/d0e1mi/gradle_plugin_350_causes_abstractmethoderror_for/
Edit: The min API level needs to be below 21.
I am also having a similar AbstractMethodError issue using ExoPlayer 2.10.6. This occurs when we call SimpleExoPlayer#setVideoSurfaceHolder() in our ExoPlayer implementation:
java.lang.AbstractMethodError: abstract method "void com.google.android.exoplayer2.analytics.AnalyticsListener.onSurfaceSizeChanged(com.google.android.exoplayer2.analytics.AnalyticsListener$EventTime, int, int)"
at com.google.android.exoplayer2.analytics.AnalyticsCollector.onSurfaceSizeChanged(AnalyticsCollector.java:331)
at com.google.android.exoplayer2.SimpleExoPlayer.maybeNotifySurfaceSizeChanged(SimpleExoPlayer.java:1208)
at com.google.android.exoplayer2.SimpleExoPlayer.setVideoSurfaceHolder(SimpleExoPlayer.java:342)
My project is also using Mux 1.0.0-r2.10.6 (https://github.com/muxinc/mux-stats-sdk-exoplayer). Mux listens to Exoplayer's AnalyticsListener interface. When we disable Mux, the issue does not seem to occur.
Also, this issue only consistently occurs on devices running Android API 22 and below.
My solution was to downgrade our project's Gradle plugin 3.5.2 -> 3.4.2, as described in the previous posts about this issue. After downgrading the Gradle plugin, the issue no longer reproduces on any API level, even with Mux enabled.
@zvonkokemperle @Koster35 Thanks for updating the reproduction steps.
It seems this is may actually be working as intended according to the issue you've linked, in particular this post: https://issuetracker.google.com/139821726#comment5 "The dexing and desugaring pipeline has changed in 3.5, and by default, we assume all Maven dependencies are fully declared. In your case, "[library1, e.g. your library]" depends on "[library2, e.g. ExoPlayer]" which you are explicitly excluding."
Can you provide more details on how the app, your test lib and ExoPlayer depend upon each other in gradle? I think directly depending on an aar without context means you may not automatically get all dependencies needed for correct dexing. Mux is also doing some aar rewriting that may be related.
To further debug this, it may be helpful to upload your test setup somewhere so we can verify ourselves.
@tonihei
Here is my implementation.
Library:
build.gradle
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-android'
android {
compileSdkVersion 29
buildToolsVersion "29.0.2"
defaultConfig {
minSdkVersion 16
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles 'consumer-rules.pro'
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
targetCompatibility JavaVersion.VERSION_1_8
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'androidx.appcompat:appcompat:1.1.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
api 'com.google.android.exoplayer:exoplayer-core:2.11.1'
api 'com.google.android.exoplayer:exoplayer-ui:2.11.1'
api 'androidx.legacy:legacy-support-v4:1.0.0'
implementation "androidx.core:core-ktx:1.1.0"
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
}
MyPlayer.kt
class MyPlayer {
private val TAG = "MyPlayer"
private var exoPlayer: SimpleExoPlayer? = null
fun initPlayer(context: Context?): SimpleExoPlayer {
exoPlayer = ExoPlayerFactory.newSimpleInstance(context!!, DefaultTrackSelector())
val listener: Player.EventListener = object : Player.EventListener {
override fun onPlayerStateChanged(playWhenReady: Boolean, playbackState: Int) {
Log.w(TAG, "playewhenready: $playWhenReady, state: $playbackState")
exoPlayer!!.playWhenReady = true
}
override fun onRepeatModeChanged(repeatMode: Int) {}
override fun onIsPlayingChanged(isPlaying: Boolean) {}
override fun onPlayerError(error: ExoPlaybackException) {}
override fun onSeekProcessed() {}
override fun onTimelineChanged(timeline: Timeline, manifest: Any?, reason: Int) {}
override fun onTracksChanged(trackGroups: TrackGroupArray, trackSelections: TrackSelectionArray) {}
override fun onShuffleModeEnabledChanged(shuffleModeEnabled: Boolean) {}
override fun onPositionDiscontinuity(reason: Int) {}
override fun onPlaybackParametersChanged(playbackParameters: PlaybackParameters) {}
}
exoPlayer!!.addListener(listener)
val dataSourceFactory: DataSource.Factory = DefaultDataSourceFactory(context, "My User Agent")
val videoSource: MediaSource = ProgressiveMediaSource.Factory(dataSourceFactory).createMediaSource(Uri.parse("https://file-examples.com/wp-content/uploads/2017/04/file_example_MP4_480_1_5MG.mp4"))
exoPlayer!!.prepare(videoSource)
return exoPlayer!!
}
}
App:
build.gradle
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-android'
android {
compileSdkVersion 29
buildToolsVersion "29.0.2"
defaultConfig {
applicationId "com.test.exocrashtest"
minSdkVersion 16
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
targetCompatibility JavaVersion.VERSION_1_8
}
}
repositories {
google()
mavenCentral()
maven {
url 'https://maven.google.com'
}
jcenter()
flatDir {
dirs 'libs'
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
implementation "androidx.core:core-ktx:1.1.0"
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
// my library including ExoPlayer
implementation (name: 'exolibrary-debug', ext: 'aar')
implementation 'com.google.android.exoplayer:exoplayer-core:2.11.1'
implementation 'com.google.android.exoplayer:exoplayer-ui:2.11.1'
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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">
<com.google.android.exoplayer2.ui.PlayerView
android:id="@+id/playerView"
android:layout_width="300dp"
android:layout_height="300dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
MainActivity.kt
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
override fun onResume() {
super.onResume()
val simpleExoPlayer = MyPlayer().initPlayer(this)
val view = findViewById<PlayerView>(R.id.playerView)
view.useController = true
view.player = simpleExoPlayer
}
}
For dependencies I have tried both api and implementation and it crashes in both cases.
I can reliably reproduce the problem with your setup. I think it still works as intended because you directly depend on the aar file and the problem goes away once you change the dependency to implementation project(path: ':exolibrary-debug')
The underlying issue is that the aar file doesn't contain any dependency declaration and that's why the dexing step can't resolve the methods successfully. According to the post linked above, full dependency declarations are required from 3.5.3 onwards.
To tell gradle about the dependencies, you need a pom file as published by Maven for example. If you were publishing your library to Maven and then include it directly from there (i.e. using the aar + the pom file), it probably works again. You could also try to use a local Maven repository including pom files, following the instructions here. I haven't tried it because it's no longer ExoPlayer related and we can't provide support for generic gradle issues. Might be worth a try though.
Based on the above, I'll close this issue as working as intended. It only occurs if you depend on an aar directly without full dependency declaration, so anyone depending on ExoPlayer through the normal way will not see any issues.
For me the fix was to override exact every abstract default method in all exoplayer interfaces with blank code
I am using exoplayer version 2.11.1 with androidX ,java1.8 and gradle version 3.5.3. The crash appears after updating the gradle version to 3.5+. I am getting runtime crash below:
====================