@javascriptcommon/react-native-track-player 1.2.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/CHANGELOG.md +75 -0
  2. package/LICENSE +21 -0
  3. package/android/build.gradle +34 -0
  4. package/android/proguard-rules.txt +3 -0
  5. package/android/react-native-music-control.iml +139 -0
  6. package/android/react-native-track-player.iml +151 -0
  7. package/android/src/main/AndroidManifest.xml +30 -0
  8. package/android/src/main/java/com/guichaguri/trackplayer/TrackPlayer.java +28 -0
  9. package/android/src/main/java/com/guichaguri/trackplayer/module/MusicEvents.java +55 -0
  10. package/android/src/main/java/com/guichaguri/trackplayer/module/MusicModule.java +298 -0
  11. package/android/src/main/java/com/guichaguri/trackplayer/service/HeadlessJsMediaService.java +174 -0
  12. package/android/src/main/java/com/guichaguri/trackplayer/service/MusicBinder.java +47 -0
  13. package/android/src/main/java/com/guichaguri/trackplayer/service/MusicManager.java +383 -0
  14. package/android/src/main/java/com/guichaguri/trackplayer/service/MusicService.java +271 -0
  15. package/android/src/main/java/com/guichaguri/trackplayer/service/Utils.java +243 -0
  16. package/android/src/main/java/com/guichaguri/trackplayer/service/metadata/ButtonEvents.java +148 -0
  17. package/android/src/main/java/com/guichaguri/trackplayer/service/metadata/MetadataManager.java +379 -0
  18. package/android/src/main/java/com/guichaguri/trackplayer/service/models/Track.java +141 -0
  19. package/android/src/main/java/com/guichaguri/trackplayer/service/models/TrackType.java +35 -0
  20. package/android/src/main/res/drawable-hdpi/ic_forward.png +0 -0
  21. package/android/src/main/res/drawable-hdpi/ic_logo.png +0 -0
  22. package/android/src/main/res/drawable-hdpi/ic_next.png +0 -0
  23. package/android/src/main/res/drawable-hdpi/ic_pause.png +0 -0
  24. package/android/src/main/res/drawable-hdpi/ic_play.png +0 -0
  25. package/android/src/main/res/drawable-hdpi/ic_previous.png +0 -0
  26. package/android/src/main/res/drawable-hdpi/ic_rewind.png +0 -0
  27. package/android/src/main/res/drawable-hdpi/ic_stop.png +0 -0
  28. package/android/src/main/res/drawable-mdpi/ic_forward.png +0 -0
  29. package/android/src/main/res/drawable-mdpi/ic_logo.png +0 -0
  30. package/android/src/main/res/drawable-mdpi/ic_next.png +0 -0
  31. package/android/src/main/res/drawable-mdpi/ic_pause.png +0 -0
  32. package/android/src/main/res/drawable-mdpi/ic_play.png +0 -0
  33. package/android/src/main/res/drawable-mdpi/ic_previous.png +0 -0
  34. package/android/src/main/res/drawable-mdpi/ic_rewind.png +0 -0
  35. package/android/src/main/res/drawable-mdpi/ic_stop.png +0 -0
  36. package/android/src/main/res/drawable-xhdpi/ic_forward.png +0 -0
  37. package/android/src/main/res/drawable-xhdpi/ic_logo.png +0 -0
  38. package/android/src/main/res/drawable-xhdpi/ic_next.png +0 -0
  39. package/android/src/main/res/drawable-xhdpi/ic_pause.png +0 -0
  40. package/android/src/main/res/drawable-xhdpi/ic_play.png +0 -0
  41. package/android/src/main/res/drawable-xhdpi/ic_previous.png +0 -0
  42. package/android/src/main/res/drawable-xhdpi/ic_rewind.png +0 -0
  43. package/android/src/main/res/drawable-xhdpi/ic_stop.png +0 -0
  44. package/android/src/main/res/drawable-xxhdpi/ic_forward.png +0 -0
  45. package/android/src/main/res/drawable-xxhdpi/ic_logo.png +0 -0
  46. package/android/src/main/res/drawable-xxhdpi/ic_next.png +0 -0
  47. package/android/src/main/res/drawable-xxhdpi/ic_pause.png +0 -0
  48. package/android/src/main/res/drawable-xxhdpi/ic_play.png +0 -0
  49. package/android/src/main/res/drawable-xxhdpi/ic_previous.png +0 -0
  50. package/android/src/main/res/drawable-xxhdpi/ic_rewind.png +0 -0
  51. package/android/src/main/res/drawable-xxhdpi/ic_stop.png +0 -0
  52. package/android/src/main/res/drawable-xxxhdpi/ic_forward.png +0 -0
  53. package/android/src/main/res/drawable-xxxhdpi/ic_logo.png +0 -0
  54. package/android/src/main/res/drawable-xxxhdpi/ic_next.png +0 -0
  55. package/android/src/main/res/drawable-xxxhdpi/ic_pause.png +0 -0
  56. package/android/src/main/res/drawable-xxxhdpi/ic_play.png +0 -0
  57. package/android/src/main/res/drawable-xxxhdpi/ic_previous.png +0 -0
  58. package/android/src/main/res/drawable-xxxhdpi/ic_rewind.png +0 -0
  59. package/android/src/main/res/drawable-xxxhdpi/ic_stop.png +0 -0
  60. package/index.d.ts +174 -0
  61. package/index.js +4 -0
  62. package/ios/RNTrackPlayer/Models/Capabilities.swift +17 -0
  63. package/ios/RNTrackPlayer/Models/MediaURL.swift +32 -0
  64. package/ios/RNTrackPlayer/Models/Track.swift +120 -0
  65. package/ios/RNTrackPlayer/RNTrackPlayer.swift +488 -0
  66. package/ios/RNTrackPlayer/RNTrackPlayerBridge.h +12 -0
  67. package/ios/RNTrackPlayer/RNTrackPlayerBridge.m +29 -0
  68. package/ios/RNTrackPlayer/Support/RNTrackPlayer-Bridging-Header.h +6 -0
  69. package/ios/TrackPlayer.xcodeproj/project.pbxproj +495 -0
  70. package/ios/TrackPlayer.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
  71. package/ios/TrackPlayer.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
  72. package/ios/TrackPlayer.xcodeproj/project.xcworkspace/xcuserdata/marco.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  73. package/ios/TrackPlayer.xcodeproj/xcuserdata/marco.xcuserdatad/xcschemes/xcschememanagement.plist +14 -0
  74. package/lib/ProgressComponent.js +70 -0
  75. package/lib/eventTypes.js +28 -0
  76. package/lib/hooks.js +160 -0
  77. package/lib/index.js +177 -0
  78. package/package.json +47 -0
  79. package/react-native-track-player.podspec +22 -0
@@ -0,0 +1,488 @@
1
+ //
2
+ // RNTrackPlayer.swift
3
+ // RNTrackPlayer
4
+ //
5
+ // Created by David Chavez on 13.08.17.
6
+ // Copyright © 2017 David Chavez. All rights reserved.
7
+ //
8
+
9
+ import Foundation
10
+ import MediaPlayer
11
+ import React
12
+
13
+ @available(iOS 10.3, *)
14
+ @objc(RNTrackPlayer)
15
+ public class RNTrackPlayer: RCTEventEmitter {
16
+
17
+ // MARK: - Attributes
18
+
19
+ private var hasInitialized = false
20
+
21
+ // MARK: - Lifecycle Methods
22
+
23
+ deinit {
24
+ reset(resolve: { _ in }, reject: { _, _, _ in })
25
+ }
26
+
27
+ private var currentTrack: Track? = nil
28
+
29
+ private var previousArtworkUrl : String? = nil
30
+
31
+ private var placeHolderImageArtwork : MPMediaItemArtwork? = nil
32
+
33
+ private var artworkUrl : MediaURL? = nil
34
+
35
+
36
+ // MARK: - RCTEventEmitter
37
+
38
+ override public static func requiresMainQueueSetup() -> Bool {
39
+ return true;
40
+ }
41
+
42
+ @objc(constantsToExport)
43
+ override public func constantsToExport() -> [AnyHashable: Any] {
44
+ return [
45
+ "STATE_NONE": PlayState.none.rawValue,
46
+ "STATE_PLAYING": PlayState.playing.rawValue,
47
+ "STATE_PAUSED": PlayState.paused.rawValue,
48
+ "STATE_STOPPED": PlayState.stopped.rawValue,
49
+
50
+ "CAPABILITY_PLAY": Capability.play.rawValue,
51
+ "CAPABILITY_PLAY_FROM_ID": "NOOP",
52
+ "CAPABILITY_PLAY_FROM_SEARCH": "NOOP",
53
+ "CAPABILITY_PAUSE": Capability.pause.rawValue,
54
+ "CAPABILITY_STOP": Capability.stop.rawValue,
55
+ "CAPABILITY_SEEK_TO": Capability.seek.rawValue,
56
+ "CAPABILITY_SKIP": "NOOP",
57
+ "CAPABILITY_SKIP_TO_NEXT": Capability.next.rawValue,
58
+ "CAPABILITY_SKIP_TO_PREVIOUS": Capability.previous.rawValue,
59
+ "CAPABILITY_SET_RATING": "NOOP",
60
+ "CAPABILITY_JUMP_FORWARD": Capability.jumpForward.rawValue,
61
+ "CAPABILITY_JUMP_BACKWARD": Capability.jumpBackward.rawValue,
62
+ "CAPABILITY_LIKE": Capability.like.rawValue,
63
+ "CAPABILITY_DISLIKE": Capability.dislike.rawValue,
64
+ "CAPABILITY_BOOKMARK": Capability.bookmark.rawValue,
65
+ ]
66
+ }
67
+
68
+ @objc(supportedEvents)
69
+ override public func supportedEvents() -> [String] {
70
+ return [
71
+ "playback-queue-ended",
72
+ "playback-state",
73
+ "playback-error",
74
+ "playback-track-changed",
75
+
76
+ "remote-play-pause",
77
+ "remote-stop",
78
+ "remote-pause",
79
+ "remote-play",
80
+ "remote-duck",
81
+ "remote-next",
82
+ "remote-seek",
83
+ "remote-previous",
84
+ "remote-jump-forward",
85
+ "remote-jump-backward",
86
+ "remote-like",
87
+ "remote-dislike",
88
+ "remote-bookmark",
89
+ ]
90
+ }
91
+
92
+ func setupInterruptionHandling() {
93
+ let notificationCenter = NotificationCenter.default
94
+ notificationCenter.removeObserver(self)
95
+ notificationCenter.addObserver(self,
96
+ selector: #selector(handleInterruption),
97
+ name: AVAudioSession.interruptionNotification,
98
+ object: nil)
99
+ }
100
+
101
+ @objc func handleInterruption(notification: Notification) {
102
+ guard let userInfo = notification.userInfo,
103
+ let typeValue = userInfo[AVAudioSessionInterruptionTypeKey] as? UInt,
104
+ let type = AVAudioSession.InterruptionType(rawValue: typeValue) else {
105
+ return
106
+ }
107
+
108
+ let center = MPNowPlayingInfoCenter.default()
109
+
110
+ if(center.nowPlayingInfo == nil){
111
+ center.nowPlayingInfo = [
112
+ MPMediaItemPropertyTitle: "",
113
+ MPMediaItemPropertyArtist: "",
114
+ MPMediaItemPropertyAlbumTitle: "",
115
+ MPMediaItemPropertyPlaybackDuration: 0,
116
+ MPNowPlayingInfoPropertyElapsedPlaybackTime: 0,
117
+ MPNowPlayingInfoPropertyPlaybackRate: 0
118
+ ]
119
+ }
120
+
121
+ if type == .began {
122
+
123
+ var wasSupended = userInfo[AVAudioSessionInterruptionWasSuspendedKey] as? Bool
124
+
125
+ #if TARGET_OS_IOS
126
+ if #available(iOS 14.5, *) {
127
+ let reason = userInfo[AVAudioSessionInterruptionReasonKey] as? NSNumber
128
+
129
+ if(reason != nil && reason == 1){
130
+ wasSupended = true
131
+ }
132
+ }
133
+ #endif
134
+
135
+ if(wasSupended != nil && wasSupended == true){
136
+ return
137
+ }
138
+
139
+ center.nowPlayingInfo![MPNowPlayingInfoPropertyPlaybackRate] = 0
140
+ // Interruption began, take appropriate actions
141
+ self.sendEvent(withName: "remote-duck", body: [
142
+ "paused": true
143
+ ])
144
+ }
145
+ else if type == .ended {
146
+ if let optionsValue = userInfo[AVAudioSessionInterruptionOptionKey] as? UInt {
147
+ let options = AVAudioSession.InterruptionOptions(rawValue: optionsValue)
148
+ if options.contains(.shouldResume) {
149
+ // Interruption Ended - playback should resume
150
+ center.nowPlayingInfo![MPNowPlayingInfoPropertyPlaybackRate] = 1.0
151
+ self.sendEvent(withName: "remote-duck", body: [
152
+ "paused": false
153
+ ])
154
+ } else {
155
+ // Interruption Ended - playback should NOT resume
156
+ self.sendEvent(withName: "remote-duck", body: [
157
+ "paused": true,
158
+ "permanent": true
159
+ ])
160
+ }
161
+ }
162
+ }
163
+ }
164
+
165
+ private func setupPlayer() {
166
+ if hasInitialized {
167
+ return
168
+ }
169
+
170
+ setupInterruptionHandling();
171
+
172
+ let center = MPRemoteCommandCenter.shared()
173
+
174
+ if #available(iOS 9.1, *) {
175
+ center.changePlaybackPositionCommand.addTarget { (commandEvent) -> MPRemoteCommandHandlerStatus in
176
+ if let event = commandEvent as? MPChangePlaybackPositionCommandEvent {
177
+ self.sendEvent(withName: "remote-seek", body: ["position": event.positionTime])
178
+ return MPRemoteCommandHandlerStatus.success
179
+ }
180
+
181
+ return MPRemoteCommandHandlerStatus.commandFailed
182
+ }
183
+ }
184
+
185
+ center.playCommand.addTarget { (commandEvent) -> MPRemoteCommandHandlerStatus in
186
+ self.sendEvent(withName: "remote-play", body: nil)
187
+ return MPRemoteCommandHandlerStatus.success
188
+ }
189
+
190
+
191
+ center.pauseCommand.addTarget { (commandEvent) -> MPRemoteCommandHandlerStatus in
192
+ self.sendEvent(withName: "remote-pause", body: nil)
193
+ return MPRemoteCommandHandlerStatus.success
194
+ }
195
+
196
+ center.nextTrackCommand.addTarget { (commandEvent) -> MPRemoteCommandHandlerStatus in
197
+ self.sendEvent(withName: "remote-next", body: nil)
198
+ return MPRemoteCommandHandlerStatus.success
199
+ }
200
+
201
+ center.previousTrackCommand.addTarget { (commandEvent) -> MPRemoteCommandHandlerStatus in
202
+ self.sendEvent(withName: "remote-previous", body: nil)
203
+ return MPRemoteCommandHandlerStatus.success
204
+ }
205
+
206
+ center.skipBackwardCommand.addTarget { (commandEvent) -> MPRemoteCommandHandlerStatus in
207
+ if let command = commandEvent.command as? MPSkipIntervalCommand,
208
+ let interval = command.preferredIntervals.first {
209
+ self.sendEvent(withName: "remote-jump-backward", body: ["interval": interval])
210
+ return MPRemoteCommandHandlerStatus.success
211
+ }
212
+
213
+ return MPRemoteCommandHandlerStatus.commandFailed
214
+ }
215
+
216
+ center.skipForwardCommand.addTarget { (commandEvent) -> MPRemoteCommandHandlerStatus in
217
+ if let command = commandEvent.command as? MPSkipIntervalCommand,
218
+ let interval = command.preferredIntervals.first {
219
+ self.sendEvent(withName: "remote-jump-forward", body: ["interval": interval])
220
+ return MPRemoteCommandHandlerStatus.success
221
+ }
222
+
223
+ return MPRemoteCommandHandlerStatus.commandFailed
224
+ }
225
+
226
+ center.stopCommand.addTarget { (commandEvent) -> MPRemoteCommandHandlerStatus in
227
+ self.sendEvent(withName: "remote-stop", body: nil)
228
+ return MPRemoteCommandHandlerStatus.success
229
+ }
230
+
231
+ center.togglePlayPauseCommand.addTarget { (commandEvent) -> MPRemoteCommandHandlerStatus in
232
+ self.sendEvent(withName: "remote-play-pause", body: nil)
233
+ return MPRemoteCommandHandlerStatus.success
234
+ }
235
+
236
+
237
+ center.likeCommand.addTarget { (commandEvent) -> MPRemoteCommandHandlerStatus in
238
+ self.sendEvent(withName: "remote-like", body: nil)
239
+ return MPRemoteCommandHandlerStatus.success
240
+ }
241
+
242
+ center.dislikeCommand.addTarget { (commandEvent) -> MPRemoteCommandHandlerStatus in
243
+ self.sendEvent(withName: "remote-dislike", body: nil)
244
+ return MPRemoteCommandHandlerStatus.success
245
+ }
246
+
247
+ center.bookmarkCommand.addTarget { (commandEvent) -> MPRemoteCommandHandlerStatus in
248
+ self.sendEvent(withName: "remote-bookmark", body: nil)
249
+ return MPRemoteCommandHandlerStatus.success
250
+ }
251
+
252
+ hasInitialized = true
253
+ }
254
+
255
+ @objc(reset:rejecter:)
256
+ public func reset(resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) {
257
+ print("Resetting player.")
258
+ MPNowPlayingInfoCenter.default().nowPlayingInfo = nil
259
+ resolve(NSNull())
260
+ DispatchQueue.main.async {
261
+ UIApplication.shared.endReceivingRemoteControlEvents();
262
+ }
263
+ }
264
+
265
+ @objc(updateOptions:resolver:rejecter:)
266
+ public func update(options: [String: Any], resolve: @escaping RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) {
267
+ DispatchQueue.main.async {
268
+ let capabilitiesStr = options["capabilities"] as? [String]
269
+ let capabilities = capabilitiesStr?.compactMap { Capability(rawValue: $0) } ?? []
270
+
271
+ let jumpInterval = options["jumpInterval"] as? NSNumber
272
+ let likeOptions = options["likeOptions"] as? [String: Any]
273
+ let dislikeOptions = options["dislikeOptions"] as? [String: Any]
274
+ let bookmarkOptions = options["bookmarkOptions"] as? [String: Any]
275
+
276
+ let center = MPRemoteCommandCenter.shared()
277
+
278
+
279
+ if #available(iOS 9.1, *) {
280
+ center.changePlaybackPositionCommand.isEnabled = capabilities.contains(.seek)
281
+ }
282
+
283
+ center.togglePlayPauseCommand.isEnabled = capabilities.contains(.play)
284
+
285
+ center.playCommand.isEnabled = capabilities.contains(.play)
286
+ center.pauseCommand.isEnabled = capabilities.contains(.pause)
287
+ center.nextTrackCommand.isEnabled = capabilities.contains(.next)
288
+ center.previousTrackCommand.isEnabled = capabilities.contains(.previous)
289
+
290
+ center.skipBackwardCommand.isEnabled = capabilities.contains(.jumpBackward)
291
+ center.skipBackwardCommand.preferredIntervals = [jumpInterval ?? 15]
292
+
293
+ center.skipForwardCommand.isEnabled = capabilities.contains(.jumpForward)
294
+ center.skipForwardCommand.preferredIntervals = [jumpInterval ?? 15]
295
+
296
+ center.stopCommand.isEnabled = capabilities.contains(.stop)
297
+
298
+ center.likeCommand.isEnabled = likeOptions?["isActive"] as? Bool ?? false//capabilities.contains(.like)
299
+ center.likeCommand.localizedTitle = likeOptions?["title"] as? String ?? "Like"
300
+ center.likeCommand.localizedShortTitle = likeOptions?["title"] as? String ?? "Like"
301
+
302
+ center.dislikeCommand.isEnabled = dislikeOptions?["isActive"] as? Bool ?? false//capabilities.contains(.like)
303
+ center.dislikeCommand.localizedTitle = dislikeOptions?["title"] as? String ?? "Dislike"
304
+ center.dislikeCommand.localizedShortTitle = dislikeOptions?["title"] as? String ?? "Dislike"
305
+
306
+ center.bookmarkCommand.isEnabled = bookmarkOptions?["isActive"] as? Bool ?? false//capabilities.contains(.like)
307
+ center.bookmarkCommand.localizedTitle = bookmarkOptions?["title"] as? String ?? "Bookmark"
308
+ center.bookmarkCommand.localizedShortTitle = bookmarkOptions?["title"] as? String ?? "Bookmark"
309
+
310
+
311
+ //load placeholder
312
+ if(self.placeHolderImageArtwork == nil && options["placeholderImage"] != nil){
313
+ let placeHolderImage : UIImage = RCTConvert.uiImage(options["placeholderImage"])
314
+
315
+ if #available(iOS 10.0, *) {
316
+ self.placeHolderImageArtwork = MPMediaItemArtwork.init(boundsSize: placeHolderImage.size, requestHandler: { (size) -> UIImage in
317
+ return placeHolderImage
318
+ })
319
+ } else {
320
+ self.placeHolderImageArtwork = MPMediaItemArtwork(image: placeHolderImage)
321
+ }
322
+ }
323
+
324
+ resolve(NSNull())
325
+ }
326
+
327
+ }
328
+
329
+ @objc(setNowPlaying:resolver:rejecter:)
330
+ public func setNowPlaying(trackDict: [String: Any], resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) {
331
+
332
+ if(!hasInitialized){
333
+ setupPlayer()
334
+ }
335
+
336
+ DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
337
+ UIApplication.shared.beginReceivingRemoteControlEvents();
338
+ }
339
+
340
+ currentTrack = Track(dictionary: trackDict)
341
+ updatePlayback(properties: trackDict, resolve: resolve, reject: reject)
342
+
343
+ }
344
+
345
+ @objc(updatePlayback:resolver:rejecter:)
346
+ public func updatePlayback(properties: [String: Any], resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) {
347
+
348
+ let center = MPNowPlayingInfoCenter.default()
349
+
350
+ let stateRaw = properties["state"] as? String
351
+
352
+ let state = stateRaw != nil ? PlayState(rawValue: stateRaw!) : PlayState.none
353
+
354
+ currentTrack?.updateMetadata(dictionary: properties)
355
+
356
+ updateMetadata(properties: properties, state: state)
357
+
358
+ let commandCenter = MPRemoteCommandCenter.shared()
359
+
360
+ if(state == PlayState.stopped){
361
+ commandCenter.stopCommand.isEnabled = false
362
+ }
363
+
364
+ #if TARGET_OS_IOS
365
+ if #available(iOS 13.0, *) {
366
+ if (state == PlayState.playing) {
367
+ center.playbackState = MPNowPlayingPlaybackState.playing
368
+ } else if (state == PlayState.paused) {
369
+ center.playbackState = MPNowPlayingPlaybackState.paused;
370
+ } else if (state == PlayState.stopped) {
371
+ center.playbackState = MPNowPlayingPlaybackState.stopped;
372
+ }
373
+ }
374
+ #endif
375
+
376
+ resolve(NSNull())
377
+ }
378
+
379
+ private func updateMetadata(properties: [String: Any], state: PlayState!) {
380
+
381
+ let center = MPNowPlayingInfoCenter.default()
382
+
383
+ if(center.nowPlayingInfo == nil){
384
+ center.nowPlayingInfo = [
385
+ MPMediaItemPropertyTitle: "",
386
+ MPMediaItemPropertyArtist: "",
387
+ MPMediaItemPropertyAlbumTitle: "",
388
+ MPMediaItemPropertyPlaybackDuration: 0,
389
+ MPNowPlayingInfoPropertyElapsedPlaybackTime: 0,
390
+ ]
391
+ }
392
+
393
+
394
+ let elapsedTime = properties["elapsedTime"] as? Double
395
+
396
+ var newNowPlaying = center.nowPlayingInfo
397
+
398
+ newNowPlaying![MPMediaItemPropertyTitle] = currentTrack?.title ?? center.nowPlayingInfo![MPMediaItemPropertyTitle]
399
+ newNowPlaying![MPMediaItemPropertyArtist] = currentTrack?.artist ?? center.nowPlayingInfo![MPMediaItemPropertyArtist]
400
+ newNowPlaying![MPMediaItemPropertyAlbumTitle] = currentTrack?.album ?? center.nowPlayingInfo![MPMediaItemPropertyAlbumTitle]
401
+ newNowPlaying![MPMediaItemPropertyPlaybackDuration] = currentTrack?.duration ?? center.nowPlayingInfo![MPMediaItemPropertyPlaybackDuration]
402
+ newNowPlaying![MPNowPlayingInfoPropertyElapsedPlaybackTime] = elapsedTime ?? center.nowPlayingInfo![MPNowPlayingInfoPropertyElapsedPlaybackTime]
403
+ newNowPlaying![MPNowPlayingInfoPropertyPlaybackRate] = state == PlayState.paused ? 0 : 1.0
404
+
405
+ let newArtworkUrl = properties["artwork"] as? String
406
+
407
+ self.artworkUrl = MediaURL(object: newArtworkUrl)
408
+
409
+ //add placeholder while image is loading
410
+ if(newArtworkUrl != nil && newArtworkUrl != self.previousArtworkUrl /*&& !(self.artworkUrl?.isLocal ?? false)*/){
411
+ newNowPlaying![MPMediaItemPropertyArtwork] = placeHolderImageArtwork
412
+ }
413
+
414
+ MPNowPlayingInfoCenter.default().nowPlayingInfo = newNowPlaying
415
+
416
+ //updateArtworkIfNeeded(artworkUrl: newArtworkUrl, newNowPlaying: newNowPlaying!)
417
+
418
+
419
+ if(newArtworkUrl == nil){
420
+ return
421
+ }
422
+
423
+ if(self.previousArtworkUrl == newArtworkUrl && newNowPlaying![MPMediaItemPropertyArtwork] != nil){
424
+ return
425
+ }
426
+
427
+ if(newArtworkUrl == ""){
428
+ return
429
+ }
430
+
431
+ self.previousArtworkUrl = newArtworkUrl
432
+
433
+ self.getArtwork { [weak self] image in
434
+ if let image = image {
435
+
436
+ // check whether image is loaded
437
+ if (image.cgImage == nil && image.ciImage == nil) {
438
+ return;
439
+ }
440
+
441
+ if(self?.previousArtworkUrl != newArtworkUrl){
442
+ return
443
+ }
444
+
445
+
446
+ let artwork = self?.mediaItemArtwork(from: image)//MPMediaItemArtwork(from: image)
447
+
448
+ if(MPNowPlayingInfoCenter.default().nowPlayingInfo != nil)
449
+ {
450
+ MPNowPlayingInfoCenter.default().nowPlayingInfo![MPMediaItemPropertyArtwork] = artwork
451
+ }
452
+ }
453
+ }
454
+ }
455
+
456
+ func getArtwork(_ handler: @escaping (UIImage?) -> Void) {
457
+ if let artworkURL = self.artworkUrl?.value {
458
+ if(self.artworkUrl?.isLocal ?? false){
459
+
460
+ if(FileManager.default.fileExists(atPath: artworkURL.path)){
461
+ let image = UIImage.init(named: artworkURL.path);
462
+ handler(image);
463
+ }
464
+
465
+ } else {
466
+ URLSession.shared.dataTask(with: artworkURL, completionHandler: { (data, _, error) in
467
+ if let data = data, let artwork = UIImage(data: data), error == nil {
468
+ handler(artwork)
469
+ }
470
+
471
+ handler(nil)
472
+ }).resume()
473
+ }
474
+ }
475
+
476
+ handler(nil)
477
+ }
478
+
479
+ fileprivate func mediaItemArtwork(from image: UIImage) -> MPMediaItemArtwork {
480
+ if #available(iOS 10.0, *) {
481
+ return MPMediaItemArtwork.init(boundsSize: image.size, requestHandler: { (size: CGSize) -> UIImage in
482
+ return image
483
+ })
484
+ } else {
485
+ return MPMediaItemArtwork(image: image)
486
+ }
487
+ }
488
+ }
@@ -0,0 +1,12 @@
1
+ //
2
+ // RNTrackPlayerBridge.h
3
+ // RNTrackPlayerBridge
4
+ //
5
+ // Created by David Chavez on 7/1/17.
6
+ // Copyright © 2017 David Chavez. All rights reserved.
7
+ //
8
+
9
+ #import <Foundation/Foundation.h>
10
+
11
+ @interface RNTrackPlayerBridge: NSObject
12
+ @end
@@ -0,0 +1,29 @@
1
+ //
2
+ // RNTrackPlayerBridge.m
3
+ // RNTrackPlayerBridge
4
+ //
5
+ // Created by David Chavez on 7/1/17.
6
+ // Copyright © 2017 David Chavez. All rights reserved.
7
+ //
8
+
9
+ #import "RNTrackPlayerBridge.h"
10
+ #import <React/RCTBridgeModule.h>
11
+ #import <React/RCTConvert.h>
12
+
13
+ @interface RCT_EXTERN_REMAP_MODULE(TrackPlayerModule, RNTrackPlayer, NSObject)
14
+
15
+ RCT_EXTERN_METHOD(updateOptions:(NSDictionary *)options
16
+ resolver:(RCTPromiseResolveBlock)resolve
17
+ rejecter:(RCTPromiseRejectBlock)reject);
18
+
19
+ RCT_EXTERN_METHOD(setNowPlaying:(NSDictionary *)trackDict
20
+ resolver:(RCTPromiseResolveBlock)resolve
21
+ rejecter:(RCTPromiseRejectBlock)reject);
22
+
23
+ RCT_EXTERN_METHOD(updatePlayback:(NSDictionary *)properties
24
+ resolver:(RCTPromiseResolveBlock)resolve
25
+ rejecter:(RCTPromiseRejectBlock)reject);
26
+
27
+ RCT_EXTERN_METHOD(reset:(RCTPromiseResolveBlock)resolve
28
+ rejecter:(RCTPromiseRejectBlock)reject);
29
+ @end
@@ -0,0 +1,6 @@
1
+ //
2
+ // Use this file to import your target's public headers that you would like to expose to Swift.
3
+ //
4
+
5
+ #import <React/RCTBridgeModule.h>
6
+ #import <React/RCTEventEmitter.h>