Skip to content

Commit 1f99933

Browse files
authored
feat: use react-native NativeEventEmitter (#189)
* Use NativeEventEmitter * Adopt react-native event emitter signature * Update docs
1 parent f820b55 commit 1f99933

File tree

24 files changed

+337
-635
lines changed

24 files changed

+337
-635
lines changed

.all-contributorsrc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -121,10 +121,10 @@
121121
]
122122
},
123123
{
124-
"login": "hoang",
124+
"login": "hoangvvo",
125125
"name": "Hoang",
126-
"avatar_url": "https://avatars.githubusercontent.com/u/170571?v=4",
127-
"profile": "https://github.com/hoang",
126+
"avatar_url": "https://avatars.githubusercontent.com/u/40987398?v=4",
127+
"profile": "https://github.com/hoangvvo",
128128
"contributions": [
129129
"code"
130130
]

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
11+
### Refactor
12+
13+
- feat: use react-native NativeEventEmitter (#189)
14+
1015
### Fix
1116

1217
- Update gradle to direct include aar files to fix [#194](https://github.com/cjam/react-native-spotify-remote/issues/194)
1318

19+
1420
## [0.3.11-6] - 2022-06-04
1521

1622
### Fix
23+
1724
- Android null check to fix [#191](https://github.com/cjam/react-native-spotify-remote/issues/191) (Thanks @pretorh)
1825

1926
## [0.3.11-5] - 2022-02-10
@@ -30,15 +37,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
3037
- update `react-native-events` to `^1.0.21` (#174)
3138

3239
## [0.3.11-3] - 2021-12-19
40+
3341
### Fix
42+
3443
- Update react-native-events (Fix [#173](https://github.com/cjam/react-native-spotify-remote/issues/173))
3544
- Fix PlayerRestrictions key name ([#172](https://github.com/cjam/react-native-spotify-remote/issues/172))
3645

3746
## [0.3.11-2] - 2021-11-11
47+
3848
### Documentation
49+
3950
- Add note for Android 11 setup
4051

4152
### Chore
53+
4254
- Fix build scripts, add back the postpack script
4355
- update `.npmignore`
4456

README.md

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ npm install --save react-native-spotify-remote
7575
7676
## Linking
7777

78-
As of React Native `> 0.61`, auto linking should work for both iOS and Android. There shouldn't be any modifications necessary and it _Should_ work out of the box. The one caveat, is that `react-native-events` needs to be linked as it doesn't yet support auto linking. If you do run into issues or are using an older version of React Native, the following sections should help get you up and running.
78+
As of React Native `> 0.61`, auto linking should work for both iOS and Android. There shouldn't be any modifications necessary and it _Should_ work out of the box. If you do run into issues or are using an older version of React Native, the following sections should help get you up and running.
7979

8080
### iOS
8181

@@ -86,7 +86,6 @@ As of React Native `> 0.61`, auto linking should work for both iOS and Android.
8686
By far the easiest way to integrate into your project. In your `ios/PodFile` add the following lines to your projects target:
8787

8888
```rb
89-
pod 'RNEventEmitter', :path => "../node_modules/react-native-events"
9089
pod 'RNSpotifyRemote', :path => '../node_modules/react-native-spotify-remote'
9190
```
9291

@@ -139,15 +138,12 @@ Modifications are needed for the `AppDelegate.m`:
139138
140139
If you need to link your project manually, here are some things you'll need to do.
141140
142-
> ### `react-native-events` does not support autolinking at this point and will need to be manually linked into your application
143-
144141
1. Open up `android/app/src/main/java/[...]/MainApplication.java`
145142
146143
- Add the following imports to the top of the file
147144
148145
```
149146
import com.reactlibrary.RNSpotifyRemotePackage;
150-
import com.lufinkey.react.eventemitter.RNEventEmitterPackage;
151147
```
152148
153149
- Add to the list returned by `getPackages()` for example:
@@ -158,7 +154,6 @@ import com.lufinkey.react.eventemitter.RNEventEmitterPackage;
158154
@SuppressWarnings("UnnecessaryLocalVariable")
159155
List<ReactPackage> packages = new PackageList(this).getPackages();
160156
// Packages that cannot be autolinked yet can be added manually here, for example:
161-
packages.add(new RNEventEmitterPackage());
162157
packages.add(new RNSpotifyRemotePackage());
163158
return packages;
164159
}
@@ -169,15 +164,11 @@ import com.lufinkey.react.eventemitter.RNEventEmitterPackage;
169164
```
170165
include ':react-native-spotify-remote'
171166
project(':react-native-spotify-remote').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-spotify-remote/android')
172-
173-
include ':react-native-events'
174-
project(':react-native-events').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-events/android')
175167
```
176168

177169
3. Insert the following lines inside the dependencies block in `android/app/build.gradle`:
178170
```
179171
implementation project(':react-native-spotify-remote')
180-
implementation project(':react-native-events')
181172
```
182173
4. As per the [Spotify Android SDK Docs](https://developer.spotify.com/documentation/android/guides/android-authentication/) Insert the following lines into `android/app/src/AndroidManifest.xml`
183174

@@ -270,7 +261,7 @@ Please do not open issues about getting the module to work unless you have tried
270261
Big thanks to [@lufinkey](https://github.com/lufinkey) and all of the great work that he has done in the [react-native-spotify](https://github.com/lufinkey/react-native-spotify) repo which was the original source of inspiration and some useful patterns for this package.
271262

272263
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
273-
[![All Contributors](https://img.shields.io/badge/all_contributors-14-orange.svg?style=flat-square)](#contributors-)
264+
[![All Contributors](https://img.shields.io/badge/all_contributors-13-orange.svg?style=flat-square)](#contributors-)
274265
<!-- ALL-CONTRIBUTORS-BADGE:END -->
275266

276267
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
@@ -292,7 +283,7 @@ Big thanks to [@lufinkey](https://github.com/lufinkey) and all of the great work
292283
<td align="center"><a href="https://github.com/reinhardholl"><img src="https://avatars.githubusercontent.com/u/4051986?v=4" width="100px;" alt=""/><br /><sub><b>Reinhard Höll</b></sub></a><br /><a href="https://github.com/cjam/react-native-spotify-remote/issues?q=author%3Areinhardholl" title="Bug reports">🐛</a> <a href="https://github.com/cjam/react-native-spotify-remote/commits?author=reinhardholl" title="Code">💻</a></td>
293284
<td align="center"><a href="https://github.com/gustavoggs"><img src="https://avatars.githubusercontent.com/u/793491?v=4" width="100px;" alt=""/><br /><sub><b>Gustavo Graña</b></sub></a><br /><a href="https://github.com/cjam/react-native-spotify-remote/issues?q=author%3Agustavoggs" title="Bug reports">🐛</a> <a href="https://github.com/cjam/react-native-spotify-remote/commits?author=gustavoggs" title="Code">💻</a></td>
294285
<td align="center"><a href="https://www.companjenapps.com"><img src="https://avatars.githubusercontent.com/u/12894112?v=4" width="100px;" alt=""/><br /><sub><b>Dylan</b></sub></a><br /><a href="https://github.com/cjam/react-native-spotify-remote/commits?author=dylancom" title="Code">💻</a></td>
295-
<td align="center"><a href="https://github.com/hoang"><img src="https://avatars.githubusercontent.com/u/170571?v=4" width="100px;" alt=""/><br /><sub><b>Hoang</b></sub></a><br /><a href="https://github.com/cjam/react-native-spotify-remote/commits?author=hoang" title="Code">💻</a></td>
286+
<td align="center"><a href="https://github.com/hoangvvo"><img src="https://avatars.githubusercontent.com/u/40987398?v=4" width="100px;" alt=""/><br /><sub><b>Hoang</b></sub></a><br /><a href="https://github.com/cjam/react-native-spotify-remote/commits?author=hoangvvo" title="Code">💻</a></td>
296287
<td align="center"><a href="https://github.com/pretorh"><img src="https://avatars.githubusercontent.com/u/4050990?v=4" width="100px;" alt=""/><br /><sub><b>Hendri Pretorius</b></sub></a><br /><a href="https://github.com/cjam/react-native-spotify-remote/issues?q=author%3Apretorh" title="Bug reports">🐛</a> <a href="https://github.com/cjam/react-native-spotify-remote/commits?author=pretorh" title="Code">💻</a></td>
297288
</tr>
298289
</table>
@@ -301,7 +292,6 @@ Big thanks to [@lufinkey](https://github.com/lufinkey) and all of the great work
301292
<!-- prettier-ignore-end -->
302293
<!-- ALL-CONTRIBUTORS-LIST:END -->
303294

304-
305295
## Projects using this library
306296

307-
Checkout existing [Projects](./PROJECTS.md) that are using this library.
297+
Checkout existing [Projects](./PROJECTS.md) that are using this library.

android/build.gradle

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,6 @@ dependencies {
6969
implementation (name: "spotify-auth-release-1.2.3", ext: "aar")
7070
implementation (name: "spotify-app-remote-release-0.7.2", ext: "aar")
7171
implementation "com.google.code.gson:gson:2.8.5" // needed by spotify-app-remote
72-
implementation project(path: ':react-native-events') // From node_module
7372
//noinspection GradleDynamicVersion
7473
implementation "com.facebook.react:react-native:+" // From node_modules
7574
}

android/src/main/java/com/reactlibrary/RNSpotifyRemoteAppModule.java

Lines changed: 85 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
package com.reactlibrary;
32

43
import android.util.Log;
@@ -13,25 +12,27 @@
1312
import com.facebook.react.bridge.ReadableMap;
1413
import com.facebook.react.bridge.WritableMap;
1514
import com.facebook.react.module.annotations.ReactModule;
16-
import com.lufinkey.react.eventemitter.RNEventEmitter;
15+
import com.facebook.react.modules.core.DeviceEventManagerModule;
1716
import com.spotify.android.appremote.api.ConnectionParams;
1817
import com.spotify.android.appremote.api.Connector;
1918
import com.spotify.android.appremote.api.SpotifyAppRemote;
2019
import com.spotify.android.appremote.api.error.CouldNotFindSpotifyApp;
2120
import com.spotify.android.appremote.api.error.NotLoggedInException;
2221
import com.spotify.android.appremote.api.error.UserNotAuthorizedException;
2322

24-
import com.lufinkey.react.eventemitter.RNEventConformer;
25-
2623
import com.spotify.protocol.client.CallResult;
2724
import com.spotify.protocol.client.ErrorCallback;
2825
import com.spotify.protocol.types.ListItem;
2926

30-
import java.util.Stack;
27+
import com.spotify.protocol.client.Subscription;
28+
import com.spotify.protocol.types.PlayerContext;
29+
import com.spotify.protocol.types.PlayerState;
3130

31+
import java.util.Stack;
32+
import java.util.HashMap;
3233

3334
@ReactModule(name = "RNSpotifyRemoteAppRemote")
34-
public class RNSpotifyRemoteAppModule extends ReactContextBaseJavaModule implements RNEventConformer {
35+
public class RNSpotifyRemoteAppModule extends ReactContextBaseJavaModule {
3536
private static final String LOG_TAG = "RNSpotifyAppRemote";
3637

3738
private final ReactApplicationContext reactContext;
@@ -41,19 +42,29 @@ public class RNSpotifyRemoteAppModule extends ReactContextBaseJavaModule impleme
4142
private Connector.ConnectionListener mSpotifyRemoteConnectionListener;
4243
private Stack<Promise> mConnectPromises = new Stack<Promise>();
4344

45+
private Subscription<PlayerContext> mPlayerContextSubscription;
46+
private Subscription<PlayerState> mPlayerStateSubscription;
47+
48+
public static final String EventNamePlayerStateChanged = "playerStateChanged";
49+
public static final String EventNamePlayerContextChanged = "playerContextChanged";
50+
public static final String EventNameRemoteDisconnected = "remoteDisconnected";
51+
public static final String EventNameRemoteConnected = "remoteConnected";
52+
53+
private HashMap<String, Boolean> subscriptionHasListeners = new HashMap<String, Boolean>();
54+
4455
public RNSpotifyRemoteAppModule(ReactApplicationContext reactContext) {
4556
super(reactContext);
4657
this.reactContext = reactContext;
4758
mSpotifyRemoteConnectionListener = new Connector.ConnectionListener() {
4859

4960
public void onConnected(SpotifyAppRemote spotifyAppRemote) {
5061
mSpotifyAppRemote = spotifyAppRemote;
51-
handleOnConnect();
62+
handleEventSubscriptions();
5263
while (!mConnectPromises.empty()) {
5364
Promise promise = mConnectPromises.pop();
5465
promise.resolve(true);
5566
}
56-
sendEvent("remoteConnected", null);
67+
sendEvent(EventNameRemoteConnected, null);
5768
}
5869

5970
public void onFailure(Throwable throwable) {
@@ -66,52 +77,85 @@ public void onFailure(Throwable throwable) {
6677
} else if (throwable instanceof CouldNotFindSpotifyApp) {
6778
promise.reject(new Error("Spotify connection failed: could not find the Spotify app, it may need to be installed."));
6879
} else {
69-
promise.reject(throwable);
80+
promise.reject(throwable);
7081
}
7182
}
72-
sendEvent("remoteDisconnected", null);
83+
sendEvent(EventNameRemoteDisconnected, null);
7384
}
7485
};
7586
}
7687

77-
@Override
78-
@ReactMethod
79-
public void __registerAsJSEventEmitter(int moduleId) {
80-
RNEventEmitter.registerEventEmitterModule(this.reactContext, moduleId, this);
88+
private void sendEvent(String eventName,
89+
Object params) {
90+
reactContext
91+
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
92+
.emit(eventName, params);
8193
}
8294

83-
@Override
84-
public void onNativeEvent(String eventName, Object... args) {
85-
// Called when an event for this module is emitted from native code
95+
@ReactMethod
96+
public void addListener(String eventName) {
97+
// Set up any upstream listeners or background tasks as necessary
8698
}
8799

88-
@Override
89-
public void onJSEvent(String eventName, Object... args) {
90-
// Called when an event for this module is emitted from javascript
100+
@ReactMethod
101+
public void removeListeners(Integer count) {
102+
// Remove upstream listeners, stop unnecessary background tasks
91103
}
92104

93-
@Override
94-
public void onEvent(String eventName, Object... args) {
95-
// Called when any event for this module is emitted
105+
@ReactMethod
106+
public void eventStartObserving(String eventName) {
107+
// Will be called when the event first listener is added.
108+
subscriptionHasListeners.put(eventName, true);
109+
handleEventSubscriptions();
96110
}
97111

98-
private void sendEvent(String eventMame, Object data) {
99-
RNEventEmitter.emitEvent(this.reactContext, this, eventMame, data);
112+
@ReactMethod
113+
public void eventStopObserving(String eventName) {
114+
// Will be called when the event last listener is removed.
115+
subscriptionHasListeners.put(eventName, false);
116+
handleEventSubscriptions();
100117
}
101-
102-
private void handleOnConnect() {
103-
mSpotifyAppRemote.getPlayerApi()
104-
.subscribeToPlayerContext()
105-
.setEventCallback(playerContext -> {
106-
ReadableMap map = Convert.toMap(playerContext);
107-
sendEvent("playerContextChanged", map);
108-
});
109-
mSpotifyAppRemote.getPlayerApi()
110-
.subscribeToPlayerState()
111-
.setEventCallback(playerState -> {
112-
WritableMap map = Convert.toMap(playerState);
113-
sendEvent("playerStateChanged", map);
114-
});
118+
119+
private void handleEventSubscriptions() {
120+
if (mSpotifyAppRemote == null)
121+
return;
122+
123+
Boolean hasContextListeners = subscriptionHasListeners.get(EventNamePlayerContextChanged);
124+
Boolean hasPlayerStateListeners = subscriptionHasListeners.get(EventNamePlayerContextChanged);
125+
126+
if (hasContextListeners != null && hasContextListeners) {
127+
if (mPlayerContextSubscription != null && !mPlayerContextSubscription.isCanceled()) {
128+
return; // already subscribed
129+
}
130+
mPlayerContextSubscription = mSpotifyAppRemote.getPlayerApi()
131+
.subscribeToPlayerContext()
132+
.setEventCallback(playerContext -> {
133+
ReadableMap map = Convert.toMap(playerContext);
134+
sendEvent(EventNamePlayerContextChanged, map);
135+
});
136+
} else {
137+
if (mPlayerContextSubscription != null && !mPlayerContextSubscription.isCanceled()) {
138+
mPlayerContextSubscription.cancel();
139+
mPlayerContextSubscription = null;
140+
}
141+
}
142+
143+
if (hasPlayerStateListeners != null && hasPlayerStateListeners) {
144+
if (mPlayerStateSubscription != null && !mPlayerStateSubscription.isCanceled()) {
145+
return; // already subscribed
146+
}
147+
mPlayerStateSubscription = mSpotifyAppRemote.getPlayerApi()
148+
.subscribeToPlayerState()
149+
.setEventCallback(playerContext -> {
150+
ReadableMap map = Convert.toMap(playerContext);
151+
sendEvent(EventNamePlayerStateChanged, map);
152+
});
153+
} else {
154+
if (mPlayerStateSubscription != null && !mPlayerStateSubscription.isCanceled()) {
155+
mPlayerStateSubscription.cancel();
156+
mPlayerStateSubscription = null;
157+
}
158+
}
115159
}
116160

117161
private <T> void executeAppRemoteCall(Function<SpotifyAppRemote, CallResult<T>> apiCall, CallResult.ResultCallback<T> resultCallback, ErrorCallback errorCallback) {
@@ -132,7 +176,7 @@ private void getPlayerStateInternal(CallResult.ResultCallback<ReadableMap> resul
132176
.setResultCallback(playerState -> {
133177
WritableMap map = Convert.toMap(playerState);
134178
WritableMap eventMap = Convert.toMap(playerState);
135-
sendEvent("playerStateChanged", eventMap);
179+
sendEvent(EventNamePlayerStateChanged, eventMap);
136180
resultCallback.onResult(map);
137181
})
138182
.setErrorCallback(errorCallback);
@@ -186,7 +230,7 @@ public void connect(String token, Promise promise) {
186230
public void disconnect(Promise promise) {
187231
if (mSpotifyAppRemote != null) {
188232
SpotifyAppRemote.disconnect(mSpotifyAppRemote);
189-
sendEvent("remoteDisconnected", null);
233+
sendEvent(EventNameRemoteDisconnected, null);
190234
}
191235
promise.resolve(null);
192236
}

docs/assets/js/search.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)