Skip to content

Commit a429683

Browse files
authored
[Feature] - Implement background job (#37)
1 parent ee7b64d commit a429683

File tree

6 files changed

+146
-14
lines changed

6 files changed

+146
-14
lines changed

README.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,26 @@ or
3131
npm install react-native-wear-connectivity
3232
```
3333

34+
Add the following entry to your `android/app/src/main/AndroidManifest.xml` (full example of AndroidManifest available [here](example/android/app/src/main/AndroidManifest.xml)):
35+
36+
```xml
37+
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
38+
<uses-permission android:name="android.permission.INTERNET" />
39+
<!-- ADD THIS PERMISSIONS -->
40+
<uses-permission android:name="android.permission.WAKE_LOCK"/>
41+
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
42+
<!-- END OF THE CHANGES -->
43+
44+
<application>
45+
<!-- ADD THIS SERVICE -->
46+
<service android:name="com.wearconnectivity.WearConnectivityTask"
47+
android:permission="android.permission.BIND_JOB_SERVICE"
48+
android:exported="true" />
49+
<!-- END OF THE CHANGES -->
50+
</application>
51+
</manifest>
52+
```
53+
3454
## React Native API Documentation
3555

3656
### Send Messages

android/src/main/AndroidManifest.xml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
11
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
22
package="com.wearconnectivity">
3+
<uses-permission android:name="android.permission.INTERNET" />
4+
<uses-permission android:name="android.permission.WAKE_LOCK"/>
5+
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
6+
<service android:name="com.wearconnectivity.WearConnectivityTask"
7+
android:permission="android.permission.BIND_JOB_SERVICE"
8+
android:exported="true" />
9+
<intent-filter>
10+
<action android:name="com.facebook.react.HeadlessJsTaskService" />
11+
</intent-filter>
312
</manifest>

android/src/main/java/com/wearconnectivity/WearConnectivityModule.java

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
package com.wearconnectivity;
22

3+
import android.app.ActivityManager;
4+
import android.content.Context;
5+
import android.os.Build;
36
import android.util.Log;
47
import androidx.annotation.NonNull;
58
import androidx.annotation.Nullable;
69
import com.facebook.common.logging.FLog;
10+
import com.facebook.react.bridge.Arguments;
711
import com.facebook.react.bridge.Callback;
812
import com.facebook.react.bridge.JSONArguments;
913
import com.facebook.react.bridge.LifecycleEventListener;
@@ -28,8 +32,15 @@
2832
import org.json.JSONObject;
2933
import com.google.android.gms.common.GoogleApiAvailability;
3034

35+
import androidx.annotation.RequiresApi;
36+
import com.facebook.react.HeadlessJsTaskService;
37+
import android.content.Intent;
38+
import android.os.Bundle;
39+
3140
public class WearConnectivityModule extends WearConnectivitySpec
3241
implements MessageClient.OnMessageReceivedListener, LifecycleEventListener {
42+
43+
private static ReactApplicationContext reactContext;
3344
public static final String NAME = "WearConnectivity";
3445
private static final String TAG = "react-native-wear-connectivity ";
3546
private final MessageClient client;
@@ -48,6 +59,7 @@ public class WearConnectivityModule extends WearConnectivitySpec
4859

4960
WearConnectivityModule(ReactApplicationContext context) {
5061
super(context);
62+
reactContext = context;
5163
context.addLifecycleEventListener(this);
5264
client = Wearable.getMessageClient(context);
5365
Log.d(TAG, CLIENT_ADDED);
@@ -118,29 +130,33 @@ private void sendMessageToClient(
118130
}
119131
}
120132

133+
@RequiresApi(api = Build.VERSION_CODES.O)
134+
@Override
121135
public void onMessageReceived(MessageEvent messageEvent) {
136+
ReactApplicationContext context = getReactContext();
122137
try {
123138
JSONObject jsonObject = new JSONObject(messageEvent.getPath());
124139
WritableMap messageAsWritableMap = (WritableMap) JSONArguments.fromJSONObject(jsonObject);
125140
String event = jsonObject.getString("event");
126141
FLog.w(TAG, TAG + " event: " + event + " message: " + messageAsWritableMap);
127-
sendEvent(getReactApplicationContext(), event, messageAsWritableMap);
142+
Intent service = new Intent(getReactContext(), com.wearconnectivity.WearConnectivityTask.class);
143+
Bundle bundle = Arguments.toBundle(messageAsWritableMap);
144+
service.putExtras(bundle);
145+
getReactContext().startForegroundService(service);
146+
HeadlessJsTaskService.acquireWakeLockNow(getReactContext());
128147
} catch (JSONException e) {
129148
FLog.w(
130-
TAG,
131-
TAG
132-
+ "onMessageReceived with message: "
133-
+ messageEvent.getPath()
134-
+ " failed with error: "
135-
+ e);
149+
TAG,
150+
TAG
151+
+ "onMessageReceived with message: "
152+
+ messageEvent.getPath()
153+
+ " failed with error: "
154+
+ e);
136155
}
137156
}
138157

139-
private void sendEvent(
140-
ReactContext reactContext, String eventName, @Nullable WritableMap params) {
141-
reactContext
142-
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
143-
.emit(eventName, params);
158+
public static ReactApplicationContext getReactContext() {
159+
return reactContext;
144160
}
145161

146162
@Override
@@ -153,8 +169,9 @@ public void onHostResume() {
153169

154170
@Override
155171
public void onHostPause() {
156-
Log.d(TAG, REMOVE_CLIENT);
157-
client.removeListener(this);
172+
// Log.d(TAG, REMOVE_CLIENT);
173+
// removed this to allow to send updates when app is in the background
174+
// client.removeListener(this);
158175
}
159176

160177
@Override
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package com.wearconnectivity;
2+
3+
import android.app.Notification;
4+
import android.app.NotificationChannel;
5+
import android.app.NotificationManager;
6+
import android.content.Intent;
7+
import android.os.Build;
8+
import android.os.Bundle;
9+
import androidx.core.app.NotificationCompat;
10+
import com.facebook.react.HeadlessJsTaskService;
11+
import com.facebook.react.bridge.Arguments;
12+
import com.facebook.react.jstasks.HeadlessJsTaskConfig;
13+
import javax.annotation.Nullable;
14+
15+
public class WearConnectivityTask extends HeadlessJsTaskService {
16+
17+
private static final int NOTIFICATION_ID = 1337;
18+
private static final String CHANNEL_ID = "wear_connectivity_channel";
19+
20+
@Override
21+
public void onCreate() {
22+
super.onCreate();
23+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
24+
NotificationChannel channel = new NotificationChannel(
25+
CHANNEL_ID,
26+
"Wear Connectivity",
27+
NotificationManager.IMPORTANCE_LOW
28+
);
29+
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
30+
if (manager != null) {
31+
manager.createNotificationChannel(channel);
32+
}
33+
}
34+
}
35+
36+
@Override
37+
public int onStartCommand(Intent intent, int flags, int startId) {
38+
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
39+
.setContentTitle("Wear Connectivity")
40+
.setContentText("Processing background task")
41+
.setSmallIcon(android.R.drawable.ic_popup_sync)
42+
.build();
43+
startForeground(NOTIFICATION_ID, notification);
44+
return super.onStartCommand(intent, flags, startId);
45+
}
46+
47+
@Override
48+
protected @Nullable HeadlessJsTaskConfig getTaskConfig(Intent intent) {
49+
Bundle extras = intent.getExtras();
50+
if (extras != null) {
51+
return new HeadlessJsTaskConfig(
52+
"WearConnectivityTask",
53+
Arguments.fromBundle(extras),
54+
5000,
55+
true
56+
);
57+
}
58+
return null;
59+
}
60+
}

example/android/app/src/main/AndroidManifest.xml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22

33
<uses-permission android:name="android.permission.INTERNET" />
44

5+
<!-- ADD THIS PERMISSIONS -->
6+
<uses-permission android:name="android.permission.WAKE_LOCK"/>
7+
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
8+
<!-- END OF THE CHANGES -->
9+
510
<application
611
android:name=".MainApplication"
712
android:label="@string/app_name"
@@ -22,5 +27,12 @@
2227
<category android:name="android.intent.category.LAUNCHER" />
2328
</intent-filter>
2429
</activity>
30+
31+
<!-- ADD THIS SERVICE -->
32+
<service android:name="com.wearconnectivity.WearConnectivityTask"
33+
android:permission="android.permission.BIND_JOB_SERVICE"
34+
android:exported="true" />
35+
<!-- END OF THE CHANGES -->
36+
2537
</application>
2638
</manifest>

src/index.tsx

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
import { AppRegistry } from 'react-native';
12
import { NativeModules, Platform } from 'react-native';
23
import { watchEvents } from './subscriptions';
34
import { sendMessage } from './messages';
45
import type { ReplyCallback, ErrorCallback } from './NativeWearConnectivity';
6+
import { DeviceEventEmitter } from 'react-native';
57

68
const LINKING_ERROR =
79
`The package 'react-native-wear-connectivity' doesn't seem to be linked. Make sure: \n\n` +
@@ -29,3 +31,15 @@ const WearConnectivity = WearConnectivityModule
2931

3032
export { sendMessage, watchEvents, WearConnectivity };
3133
export type { ReplyCallback, ErrorCallback };
34+
35+
// Define the headless task
36+
const WearConnectivityTask = async (taskData) => {
37+
// Emit an event or process the message as needed
38+
DeviceEventEmitter.emit('message', taskData);
39+
};
40+
41+
// Register the headless task with React Native
42+
AppRegistry.registerHeadlessTask(
43+
'WearConnectivityTask',
44+
() => WearConnectivityTask
45+
);

0 commit comments

Comments
 (0)