@cloudflare/realtimekit-react-native 1.1.0 → 1.2.0-staging.1
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.
- package/README.md +2 -2
- package/android/src/main/AndroidManifest.xml +6 -1
- package/android/src/main/java/com/cloudflare/realtimekit/KeepAliveService.java +176 -0
- package/android/src/main/java/com/cloudflare/realtimekit/RTKHelperModule.java +27 -60
- package/lib/commonjs/LocalMediaHandler.js +114 -82
- package/lib/commonjs/LocalMediaHandler.js.map +1 -1
- package/lib/commonjs/LocalMediaUtils.js +3 -5
- package/lib/commonjs/LocalMediaUtils.js.map +1 -1
- package/lib/commonjs/ReactContext.js +33 -33
- package/lib/commonjs/ReactContext.js.map +1 -1
- package/lib/commonjs/ReactHooks.js +71 -15
- package/lib/commonjs/ReactHooks.js.map +1 -1
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/utils/version.js +1 -1
- package/lib/commonjs/utils/version.js.map +1 -1
- package/lib/module/LocalMediaHandler.js +114 -82
- package/lib/module/LocalMediaHandler.js.map +1 -1
- package/lib/module/LocalMediaUtils.js +3 -5
- package/lib/module/LocalMediaUtils.js.map +1 -1
- package/lib/module/ReactContext.js +33 -33
- package/lib/module/ReactContext.js.map +1 -1
- package/lib/module/ReactHooks.js +71 -15
- package/lib/module/ReactHooks.js.map +1 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/utils/version.js +1 -1
- package/lib/module/utils/version.js.map +1 -1
- package/lib/typescript/LocalMediaHandler.d.ts +18 -4
- package/lib/typescript/ReactHooks.d.ts +22 -1
- package/lib/typescript/index.d.ts +1 -0
- package/lib/typescript/utils/version.d.ts +1 -1
- package/package.json +3 -5
- package/plugin/build/withRTK.js +50 -22
- package/plugin/src/withRTK.ts +58 -23
- package/android/src/main/java/com/cloudflare/realtimekit/ForegroundService.java +0 -46
- package/android/src/main/java/com/cloudflare/realtimekit/NotificationHelper.java +0 -126
package/plugin/src/withRTK.ts
CHANGED
|
@@ -81,23 +81,13 @@ const withIosPermissions: ConfigPlugin<Props> = (
|
|
|
81
81
|
};
|
|
82
82
|
|
|
83
83
|
/**
|
|
84
|
-
* Adds the following to
|
|
85
|
-
*
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
|
|
92
|
-
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
|
|
93
|
-
<uses-permission android:name="android.permission.WAKE_LOCK"/>
|
|
94
|
-
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
|
95
|
-
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_CAMERA" />
|
|
96
|
-
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MICROPHONE" />
|
|
97
|
-
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION" />
|
|
98
|
-
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
|
99
|
-
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
|
100
|
-
<uses-permission android:name="android.permission.MICROPHONE" />
|
|
84
|
+
* Adds the following permissions to `AndroidManifest.xml`:
|
|
85
|
+
* ACCESS_NETWORK_STATE, BLUETOOTH, CAMERA, INTERNET,
|
|
86
|
+
* MODIFY_AUDIO_SETTINGS, RECORD_AUDIO, SYSTEM_ALERT_WINDOW, WAKE_LOCK,
|
|
87
|
+
* POST_NOTIFICATIONS,
|
|
88
|
+
* FOREGROUND_SERVICE, FOREGROUND_SERVICE_CAMERA, FOREGROUND_SERVICE_MICROPHONE,
|
|
89
|
+
* FOREGROUND_SERVICE_MEDIA_PLAYBACK,
|
|
90
|
+
* WRITE_EXTERNAL_STORAGE, READ_EXTERNAL_STORAGE, MICROPHONE
|
|
101
91
|
*/
|
|
102
92
|
const withAndroidPermissions: ConfigPlugin = (config) => {
|
|
103
93
|
return AndroidConfig.Permissions.withPermissions(config, [
|
|
@@ -109,8 +99,11 @@ const withAndroidPermissions: ConfigPlugin = (config) => {
|
|
|
109
99
|
'android.permission.RECORD_AUDIO',
|
|
110
100
|
'android.permission.SYSTEM_ALERT_WINDOW',
|
|
111
101
|
'android.permission.WAKE_LOCK',
|
|
102
|
+
'android.permission.POST_NOTIFICATIONS',
|
|
112
103
|
'android.permission.FOREGROUND_SERVICE',
|
|
113
|
-
'android.permission.
|
|
104
|
+
'android.permission.FOREGROUND_SERVICE_CAMERA',
|
|
105
|
+
'android.permission.FOREGROUND_SERVICE_MICROPHONE',
|
|
106
|
+
'android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK',
|
|
114
107
|
'android.permission.WRITE_EXTERNAL_STORAGE',
|
|
115
108
|
'android.permission.READ_EXTERNAL_STORAGE',
|
|
116
109
|
'android.permission.MICROPHONE',
|
|
@@ -123,11 +116,24 @@ const withAndroidScreenshare: ConfigPlugin = (config) => {
|
|
|
123
116
|
const app = manifest.manifest.application?.[0];
|
|
124
117
|
|
|
125
118
|
if (app) {
|
|
126
|
-
|
|
119
|
+
const newServiceName =
|
|
120
|
+
'com.cloudflare.realtimekit.WebRTCModule.MediaProjectionService';
|
|
121
|
+
|
|
122
|
+
// Remove the old ForegroundService entry if it exists (migration from previous versions).
|
|
123
|
+
const oldServiceName = 'com.cloudflare.realtimekit.ForegroundService';
|
|
124
|
+
if (app.service) {
|
|
125
|
+
app.service = app.service.filter(
|
|
126
|
+
(service) => service.$['android:name'] !== oldServiceName
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Add the new MediaProjectionService entry if not already present.
|
|
131
|
+
// Note: react-native-webrtc's own AndroidManifest.xml also declares this
|
|
132
|
+
// service, so Expo managed apps that merge library manifests may not need
|
|
133
|
+
// this entry. It is added here explicitly for safety with bare workflow
|
|
134
|
+
// apps that do not perform automatic manifest merging.
|
|
127
135
|
const exists = (app.service || []).some(
|
|
128
|
-
(service) =>
|
|
129
|
-
service.$['android:name'] ===
|
|
130
|
-
'com.cloudflare.realtimekit.ForegroundService'
|
|
136
|
+
(service) => service.$['android:name'] === newServiceName
|
|
131
137
|
);
|
|
132
138
|
if (!exists) {
|
|
133
139
|
app.service = [
|
|
@@ -135,8 +141,9 @@ const withAndroidScreenshare: ConfigPlugin = (config) => {
|
|
|
135
141
|
{
|
|
136
142
|
$: {
|
|
137
143
|
'android:enabled': 'true',
|
|
144
|
+
'android:exported': 'false',
|
|
138
145
|
'android:foregroundServiceType': 'mediaProjection',
|
|
139
|
-
'android:name':
|
|
146
|
+
'android:name': newServiceName,
|
|
140
147
|
},
|
|
141
148
|
},
|
|
142
149
|
];
|
|
@@ -167,6 +174,33 @@ const withAndroidBlobProviderAuthority: ConfigPlugin = (config) => {
|
|
|
167
174
|
});
|
|
168
175
|
};
|
|
169
176
|
|
|
177
|
+
const withAndroidMeetingService: ConfigPlugin = (config) => {
|
|
178
|
+
return withAndroidManifest(config, (_config) => {
|
|
179
|
+
const manifest = _config.modResults as AndroidManifest;
|
|
180
|
+
const app = manifest.manifest.application?.[0];
|
|
181
|
+
if (!app) return _config;
|
|
182
|
+
|
|
183
|
+
const serviceName = 'com.cloudflare.realtimekit.KeepAliveService';
|
|
184
|
+
const exists = (app.service || []).some(
|
|
185
|
+
(service) => service.$['android:name'] === serviceName
|
|
186
|
+
);
|
|
187
|
+
if (!exists) {
|
|
188
|
+
app.service = [
|
|
189
|
+
...(app.service || []),
|
|
190
|
+
{
|
|
191
|
+
$: {
|
|
192
|
+
'android:name': serviceName,
|
|
193
|
+
'android:enabled': 'true',
|
|
194
|
+
'android:exported': 'false',
|
|
195
|
+
'android:foregroundServiceType': 'camera|microphone|mediaPlayback',
|
|
196
|
+
},
|
|
197
|
+
},
|
|
198
|
+
];
|
|
199
|
+
}
|
|
200
|
+
return _config;
|
|
201
|
+
});
|
|
202
|
+
};
|
|
203
|
+
|
|
170
204
|
const withVoice: ConfigPlugin<Props | void> = (config, props = {}) => {
|
|
171
205
|
const _props = props ? props : {};
|
|
172
206
|
config = withIosPermissions(config, _props);
|
|
@@ -174,6 +208,7 @@ const withVoice: ConfigPlugin<Props | void> = (config, props = {}) => {
|
|
|
174
208
|
config = withAndroidPermissions(config);
|
|
175
209
|
}
|
|
176
210
|
config = withAndroidScreenshare(config);
|
|
211
|
+
config = withAndroidMeetingService(config);
|
|
177
212
|
config = withAndroidBlobProviderAuthority(config);
|
|
178
213
|
return config;
|
|
179
214
|
};
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
package com.cloudflare.realtimekit;
|
|
2
|
-
|
|
3
|
-
import android.app.Notification;
|
|
4
|
-
import android.app.Service;
|
|
5
|
-
import android.content.Intent;
|
|
6
|
-
import android.os.Build;
|
|
7
|
-
import android.os.IBinder;
|
|
8
|
-
import android.content.pm.ServiceInfo;
|
|
9
|
-
import android.app.Activity;
|
|
10
|
-
import android.widget.Toast;
|
|
11
|
-
import com.cloudflare.realtimekit.RTKHolder;
|
|
12
|
-
|
|
13
|
-
public class ForegroundService extends Service {
|
|
14
|
-
@Override
|
|
15
|
-
public IBinder onBind(Intent intent) {
|
|
16
|
-
return null;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
public int onStartCommand(Intent intent, int flags, int startId) {
|
|
20
|
-
String action = intent.getAction();
|
|
21
|
-
if (action != null) {
|
|
22
|
-
if (action.equals(Constants.ACTION_FOREGROUND_SERVICE_START)) {
|
|
23
|
-
if(RTKHolder.currActivity!=null) {
|
|
24
|
-
NotificationHelper notificationHelper = NotificationHelper.getInstance(RTKHolder.currActivity);
|
|
25
|
-
Notification notification = notificationHelper.buildNotification(RTKHolder.currActivity);
|
|
26
|
-
if (notification != null) {
|
|
27
|
-
try {
|
|
28
|
-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
|
29
|
-
startForeground(notificationHelper.NOTIFICATION_ID, notification, ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION);
|
|
30
|
-
} else {
|
|
31
|
-
startForeground(notificationHelper.NOTIFICATION_ID, notification);
|
|
32
|
-
}
|
|
33
|
-
} catch (RuntimeException e) {
|
|
34
|
-
RTKLogger.w("ForegroundService", "Failed to start ForegroundService due to: " + e.getMessage());
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
} else if (action.equals(Constants.ACTION_FOREGROUND_SERVICE_STOP)) {
|
|
40
|
-
stopSelf();
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
return START_NOT_STICKY;
|
|
44
|
-
|
|
45
|
-
}
|
|
46
|
-
}
|
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
package com.cloudflare.realtimekit;
|
|
2
|
-
|
|
3
|
-
import android.app.Notification;
|
|
4
|
-
import android.app.NotificationChannel;
|
|
5
|
-
import android.app.NotificationManager;
|
|
6
|
-
import android.app.PendingIntent;
|
|
7
|
-
import android.content.Context;
|
|
8
|
-
import android.content.Intent;
|
|
9
|
-
import android.content.pm.ApplicationInfo;
|
|
10
|
-
import android.content.pm.PackageManager;
|
|
11
|
-
import android.graphics.Bitmap;
|
|
12
|
-
import android.graphics.drawable.BitmapDrawable;
|
|
13
|
-
import android.graphics.drawable.Drawable;
|
|
14
|
-
import android.os.Build;
|
|
15
|
-
import android.util.Log;
|
|
16
|
-
import androidx.core.app.NotificationCompat;
|
|
17
|
-
|
|
18
|
-
import com.facebook.react.bridge.Promise;
|
|
19
|
-
|
|
20
|
-
import java.util.Random;
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
class NotificationHelper {
|
|
24
|
-
public static final int NOTIFICATION_ID = new Random().nextInt(99999) + 10000;
|
|
25
|
-
private static final String CHANNEL_ID = "RealtimeKitNotificationChannel";
|
|
26
|
-
private static final String CHANNEL_NAME = "Screen Sharing";
|
|
27
|
-
private static final String CHANNEL_DESC = "Screen Sharing";
|
|
28
|
-
|
|
29
|
-
private static NotificationHelper instance = null;
|
|
30
|
-
private NotificationManager mNotificationManager;
|
|
31
|
-
|
|
32
|
-
public static synchronized NotificationHelper getInstance(Context context) {
|
|
33
|
-
if (instance == null) {
|
|
34
|
-
instance = new NotificationHelper(context);
|
|
35
|
-
}
|
|
36
|
-
return instance;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
private NotificationHelper(Context context) {
|
|
40
|
-
mNotificationManager = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
|
|
41
|
-
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
void createNotificationChannel(Promise promise) {
|
|
45
|
-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
46
|
-
int channelImportance = NotificationManager.IMPORTANCE_DEFAULT;
|
|
47
|
-
boolean enableVibration = false;
|
|
48
|
-
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, CHANNEL_NAME, channelImportance);
|
|
49
|
-
channel.setDescription(CHANNEL_DESC);
|
|
50
|
-
channel.enableVibration(enableVibration);
|
|
51
|
-
mNotificationManager.createNotificationChannel(channel);
|
|
52
|
-
promise.resolve(null);
|
|
53
|
-
} else {
|
|
54
|
-
promise.reject(Constants.ERROR_ANDROID_VERSION, "RTKForegroundService: Notification channel can be created on Android O+");
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
Notification buildNotification(Context context) {
|
|
59
|
-
if (context == null) {
|
|
60
|
-
return null;
|
|
61
|
-
}
|
|
62
|
-
Intent notificationIntent = new Intent(context, context.getClass());
|
|
63
|
-
PendingIntent pendingIntent;
|
|
64
|
-
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) {
|
|
65
|
-
pendingIntent = PendingIntent.getActivity(context, 0, notificationIntent, PendingIntent.FLAG_MUTABLE);
|
|
66
|
-
}
|
|
67
|
-
else {
|
|
68
|
-
pendingIntent = PendingIntent.getActivity(context, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, CHANNEL_ID);
|
|
72
|
-
final PackageManager packageManager = context.getPackageManager();
|
|
73
|
-
int appIconResId = android.R.mipmap.sym_def_app_icon;
|
|
74
|
-
Bitmap largeIcon = null;
|
|
75
|
-
try {
|
|
76
|
-
final ApplicationInfo applicationInfo = packageManager.getApplicationInfo(context.getPackageName(), PackageManager.GET_META_DATA);
|
|
77
|
-
appIconResId=applicationInfo.icon;
|
|
78
|
-
Drawable drawable=applicationInfo.loadIcon(packageManager);
|
|
79
|
-
largeIcon = ((BitmapDrawable)drawable).getBitmap();
|
|
80
|
-
} catch (Exception e) {
|
|
81
|
-
//pass
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
builder
|
|
85
|
-
.setCategory(NotificationCompat.CATEGORY_CALL)
|
|
86
|
-
.setContentTitle("Screen Share")
|
|
87
|
-
.setContentText("You are sharing your screen")
|
|
88
|
-
.setPriority(NotificationCompat.PRIORITY_LOW)
|
|
89
|
-
.setContentIntent(pendingIntent)
|
|
90
|
-
.setOngoing(false)
|
|
91
|
-
.setUsesChronometer(false)
|
|
92
|
-
.setAutoCancel(true)
|
|
93
|
-
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
|
|
94
|
-
.setOnlyAlertOnce(true)
|
|
95
|
-
.setSmallIcon(appIconResId)
|
|
96
|
-
.setForegroundServiceBehavior(NotificationCompat.FOREGROUND_SERVICE_IMMEDIATE);
|
|
97
|
-
if(largeIcon != null){
|
|
98
|
-
builder.setLargeIcon(largeIcon);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
return builder.build();
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
private Class getMainActivityClass(Context context) {
|
|
105
|
-
String packageName = context.getPackageName();
|
|
106
|
-
Intent launchIntent = context.getPackageManager().getLaunchIntentForPackage(packageName);
|
|
107
|
-
if (launchIntent == null || launchIntent.getComponent() == null) {
|
|
108
|
-
// Log.e("NotificationHelper", "Failed to get launch intent or component");
|
|
109
|
-
return null;
|
|
110
|
-
}
|
|
111
|
-
try {
|
|
112
|
-
return Class.forName(launchIntent.getComponent().getClassName());
|
|
113
|
-
} catch (ClassNotFoundException e) {
|
|
114
|
-
// Log.e("NotificationHelper", "Failed to get main activity class");
|
|
115
|
-
return null;
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
private int getResourceIdForResourceName(Context context, String resourceName) {
|
|
120
|
-
int resourceId = context.getResources().getIdentifier(resourceName, "drawable", context.getPackageName());
|
|
121
|
-
if (resourceId == 0) {
|
|
122
|
-
resourceId = context.getResources().getIdentifier(resourceName, "mipmap", context.getPackageName());
|
|
123
|
-
}
|
|
124
|
-
return resourceId;
|
|
125
|
-
}
|
|
126
|
-
}
|