From 27cc55df195dd151dc2e50ed1ce03557c19e686a Mon Sep 17 00:00:00 2001 From: lovegaoshi <106490582+lovegaoshi@users.noreply.github.com> Date: Wed, 16 Oct 2024 10:19:44 -0700 Subject: [PATCH] fix: new arch https://github.com/doublesymmetry/react-native-track-player/pull/2290 --- .../trackplayer/module/MusicModule.kt | 198 +++++++++--------- ios/RNTrackPlayer/RNTrackPlayerBridge.m | 13 -- 2 files changed, 103 insertions(+), 108 deletions(-) diff --git a/android/src/main/java/com/doublesymmetry/trackplayer/module/MusicModule.kt b/android/src/main/java/com/doublesymmetry/trackplayer/module/MusicModule.kt index a0b354301..41313e0db 100644 --- a/android/src/main/java/com/doublesymmetry/trackplayer/module/MusicModule.kt +++ b/android/src/main/java/com/doublesymmetry/trackplayer/module/MusicModule.kt @@ -54,7 +54,7 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM } override fun onServiceConnected(name: ComponentName, service: IBinder) { - scope.launch { + launchInScope { // If a binder already exists, don't get a new one if (!::musicService.isInitialized) { val binder: MusicService.MusicBinder = service as MusicService.MusicBinder @@ -71,7 +71,7 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM * Called when a connection to the Service has been lost. */ override fun onServiceDisconnected(name: ComponentName) { - scope.launch { + launchInScope { isServiceBound = false } } @@ -289,8 +289,8 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM } @ReactMethod - fun updateOptions(data: ReadableMap?, callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun updateOptions(data: ReadableMap?, callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope val options = Arguments.toBundle(data) @@ -302,14 +302,14 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM } @ReactMethod - fun add(data: ReadableArray?, insertBeforeIndex: Int, callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun add(data: ReadableArray?, insertBeforeIndex: Int, callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope try { val tracks = readableArrayToTrackList(data); if (insertBeforeIndex < -1 || insertBeforeIndex > musicService.tracks.size) { callback.reject("index_out_of_bounds", "The track index is out of bounds") - return@launch + return@launchInScope } val index = if (insertBeforeIndex == -1) musicService.tracks.size else insertBeforeIndex musicService.add( @@ -323,11 +323,11 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM } @ReactMethod - fun load(data: ReadableMap?, callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun load(data: ReadableMap?, callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope if (data == null) { callback.resolve(null) - return@launch + return@launchInScope } val bundle = Arguments.toBundle(data); if (bundle is Bundle) { @@ -339,15 +339,15 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM } @ReactMethod - fun move(fromIndex: Int, toIndex: Int, callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun move(fromIndex: Int, toIndex: Int, callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope musicService.move(fromIndex, toIndex) callback.resolve(null) } @ReactMethod - fun remove(data: ReadableArray?, callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun remove(data: ReadableArray?, callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope val inputIndexes = Arguments.toList(data) if (inputIndexes != null) { val size = musicService.tracks.size @@ -359,7 +359,7 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM "index_out_of_bounds", "One or more indexes was out of bounds" ) - return@launch + return@launchInScope } indexes.add(index) } @@ -370,8 +370,8 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM @ReactMethod fun updateMetadataForTrack(index: Int, map: ReadableMap?, callback: Promise) = - scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope if (index < 0 || index >= musicService.tracks.size) { callback.reject("index_out_of_bounds", "The index is out of bounds") @@ -386,8 +386,8 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM } @ReactMethod - fun updateNowPlayingMetadata(map: ReadableMap?, callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun updateNowPlayingMetadata(map: ReadableMap?, callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope if (musicService.tracks.isEmpty()) callback.reject("no_current_item", "There is no current item in the player") @@ -401,8 +401,8 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM } @ReactMethod - fun clearNowPlayingMetadata(callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun clearNowPlayingMetadata(callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope if (musicService.tracks.isEmpty()) callback.reject("no_current_item", "There is no current item in the player") @@ -412,16 +412,16 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM } @ReactMethod - fun removeUpcomingTracks(callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun removeUpcomingTracks(callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope musicService.removeUpcomingTracks() callback.resolve(null) } @ReactMethod - fun skip(index: Int, initialTime: Float, callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun skip(index: Int, initialTime: Float, callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope musicService.skip(index) @@ -433,8 +433,8 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM } @ReactMethod - fun skipToNext(initialTime: Float, callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun skipToNext(initialTime: Float, callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope musicService.skipToNext() @@ -446,8 +446,8 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM } @ReactMethod - fun skipToPrevious(initialTime: Float, callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun skipToPrevious(initialTime: Float, callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope musicService.skipToPrevious() @@ -459,8 +459,8 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM } @ReactMethod - fun reset(callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun reset(callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope musicService.stop() delay(300) // Allow playback to stop @@ -470,116 +470,116 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM } @ReactMethod - fun play(callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun play(callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope musicService.play() callback.resolve(null) } @ReactMethod - fun pause(callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun pause(callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope musicService.pause() callback.resolve(null) } @ReactMethod - fun stop(callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun stop(callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope musicService.stop() callback.resolve(null) } @ReactMethod - fun seekTo(seconds: Float, callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun seekTo(seconds: Float, callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope musicService.seekTo(seconds) callback.resolve(null) } @ReactMethod - fun seekBy(offset: Float, callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun seekBy(offset: Float, callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope musicService.seekBy(offset) callback.resolve(null) } @ReactMethod - fun retry(callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun retry(callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope musicService.retry() callback.resolve(null) } @ReactMethod - fun setVolume(volume: Float, callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun setVolume(volume: Float, callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope musicService.setVolume(volume) callback.resolve(null) } @ReactMethod - fun getVolume(callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun getVolume(callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope callback.resolve(musicService.getVolume()) } @ReactMethod - fun setRate(rate: Float, callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun setRate(rate: Float, callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope musicService.setRate(rate) callback.resolve(null) } @ReactMethod - fun getRate(callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun getRate(callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope callback.resolve(musicService.getRate()) } @ReactMethod - fun setRepeatMode(mode: Int, callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun setRepeatMode(mode: Int, callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope musicService.setRepeatMode(RepeatMode.fromOrdinal(mode)) callback.resolve(null) } @ReactMethod - fun getRepeatMode(callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun getRepeatMode(callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope callback.resolve(musicService.getRepeatMode().ordinal) } @ReactMethod - fun setPlayWhenReady(playWhenReady: Boolean, callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun setPlayWhenReady(playWhenReady: Boolean, callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope musicService.playWhenReady = playWhenReady callback.resolve(null) } @ReactMethod - fun getPlayWhenReady(callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun getPlayWhenReady(callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope callback.resolve(musicService.playWhenReady) } @ReactMethod - fun getTrack(index: Int, callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun getTrack(index: Int, callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope if (index >= 0 && index < musicService.tracks.size) { callback.resolve(Arguments.fromBundle(musicService.tracks[index].originalItem)) @@ -589,15 +589,15 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM } @ReactMethod - fun getQueue(callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun getQueue(callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope callback.resolve(Arguments.fromList(musicService.tracks.map { it.originalItem })) } @ReactMethod - fun setQueue(data: ReadableArray?, callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun setQueue(data: ReadableArray?, callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope try { musicService.clear() @@ -609,16 +609,16 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM } @ReactMethod - fun getActiveTrackIndex(callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun getActiveTrackIndex(callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope callback.resolve( if (musicService.tracks.isEmpty()) null else musicService.getCurrentTrackIndex() ) } @ReactMethod - fun getActiveTrack(callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun getActiveTrack(callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope callback.resolve( if (musicService.tracks.isEmpty()) null else Arguments.fromBundle( @@ -628,29 +628,29 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM } @ReactMethod - fun getDuration(callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun getDuration(callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope callback.resolve(musicService.getDurationInSeconds()) } @ReactMethod - fun getBufferedPosition(callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun getBufferedPosition(callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope callback.resolve(musicService.getBufferedPositionInSeconds()) } @ReactMethod - fun getPosition(callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun getPosition(callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope callback.resolve(musicService.getPositionInSeconds()) } @ReactMethod - fun getProgress(callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun getProgress(callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope val bundle = Bundle() bundle.putDouble("duration", musicService.getDurationInSeconds()); bundle.putDouble("position", musicService.getPositionInSeconds()); @@ -659,54 +659,54 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM } @ReactMethod - fun getPlaybackState(callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun getPlaybackState(callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope callback.resolve(Arguments.fromBundle(musicService.getPlayerStateBundle(musicService.state))) } @ReactMethod - fun setAnimatedVolume(volume: Float = 1f, duration: Int = 0, interval: Int = 20, msg: String = "", callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun setAnimatedVolume(volume: Float = 1f, duration: Int = 0, interval: Int = 20, msg: String = "", callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope musicService.setAnimatedVolume(volume, duration.toLong(), interval.toLong(), msg).await() delay(duration.toLong()) callback.resolve(null) } @ReactMethod - fun fadeOutPause(duration: Int = 0, interval: Int = 20, callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun fadeOutPause(duration: Int = 0, interval: Int = 20, callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope musicService.fadeOutPause(duration.toLong(), interval.toLong()) delay(duration.toLong()) callback.resolve(null) } @ReactMethod - fun fadeOutNext(duration: Int = 0, interval: Int = 20, toVolume: Float = 1f, callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun fadeOutNext(duration: Int = 0, interval: Int = 20, toVolume: Float = 1f, callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope musicService.fadeOutNext(duration.toLong(), interval.toLong(), toVolume) delay(duration.toLong()) callback.resolve(null) } @ReactMethod - fun fadeOutPrevious(duration: Int = 0, interval: Int = 20, toVolume: Float = 1f, callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun fadeOutPrevious(duration: Int = 0, interval: Int = 20, toVolume: Float = 1f, callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope musicService.fadeOutPrevious(duration.toLong(), interval.toLong(), toVolume) delay(duration.toLong()) callback.resolve(null) } @ReactMethod - fun fadeOutJump(index: Int, duration: Int = 0, interval: Int = 20, toVolume: Float = 1f, callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun fadeOutJump(index: Int, duration: Int = 0, interval: Int = 20, toVolume: Float = 1f, callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope musicService.fadeOutJump(index, duration.toLong(), interval.toLong(), toVolume) delay(duration.toLong()) callback.resolve(null) } @ReactMethod - fun setBrowseTree(mediaItems: ReadableMap, callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun setBrowseTree(mediaItems: ReadableMap, callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope val mediaItemsMap = mediaItems.toHashMap() musicService.mediaTree = mediaItemsMap.mapValues { readableArrayToMediaItems(it.value as ArrayList>) } Timber.tag("APM").d("refreshing browseTree") @@ -716,7 +716,7 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM @ReactMethod // this method doesn't seem to affect style after onGetRoot is called, and won't change if notifyChildrenChanged is emitted. - fun setBrowseTreeStyle(browsableStyle: Int, playableStyle: Int, callback: Promise) = scope.launch { + fun setBrowseTreeStyle(browsableStyle: Int, playableStyle: Int, callback: Promise) = launchInScope { fun getStyle(check: Int): Int { return when (check) { 1 -> MediaConstants.DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_GRID_ITEM @@ -725,7 +725,7 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM else -> MediaConstants.DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_LIST_ITEM } } - if (verifyServiceBoundOrReject(callback)) return@launch + if (verifyServiceBoundOrReject(callback)) return@launchInScope musicService.mediaTreeStyle = listOf( getStyle(browsableStyle), getStyle(playableStyle) @@ -734,8 +734,16 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM } @ReactMethod - fun setPlaybackState(mediaID: String, callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun setPlaybackState(mediaID: String, callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope callback.resolve(null) } + + // Bridgeless interop layer tries to pass the `Job` from `scope.launch` to the JS side + // which causes an exception. We can work around this using a wrapper. + private fun launchInScope(block: suspend () -> Unit) { + scope.launch { + block() + } + } } diff --git a/ios/RNTrackPlayer/RNTrackPlayerBridge.m b/ios/RNTrackPlayer/RNTrackPlayerBridge.m index 774199419..776c09ec0 100644 --- a/ios/RNTrackPlayer/RNTrackPlayerBridge.m +++ b/ios/RNTrackPlayer/RNTrackPlayerBridge.m @@ -151,17 +151,4 @@ @interface RCT_EXTERN_REMAP_MODULE(TrackPlayerModule, RNTrackPlayer, NSObject) resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject); -RCT_EXTERN_METHOD(getSleepTimerProgress:(RCTPromiseResolveBlock)resolve - rejecter:(RCTPromiseRejectBlock)reject); - -RCT_EXTERN_METHOD(setSleepTimer:(double)time - resolver:(RCTPromiseResolveBlock)resolve - rejecter:(RCTPromiseRejectBlock)reject); - -RCT_EXTERN_METHOD(sleepWhenActiveTrackReachesEnd:(RCTPromiseResolveBlock)resolve - rejecter:(RCTPromiseRejectBlock)reject); - -RCT_EXTERN_METHOD(clearSleepTimer:(RCTPromiseResolveBlock)resolve - rejecter:(RCTPromiseRejectBlock)reject); - @end