craft-native 0.0.168 → 0.0.169
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/dist/android/src/index.d.ts +62 -0
- package/dist/android/src/index.js +138 -18
- package/dist/android/templates/CraftNativeBackground.kt.template +296 -0
- package/dist/android/templates/CraftNativeCapabilities.kt.template +59 -37
- package/dist/android/templates/CraftNativeHealth.kt.template +1046 -0
- package/dist/android/templates/CraftNativeHealthStub.kt.template +32 -0
- package/dist/android/templates/CraftNativeMessagingService.kt.template +75 -0
- package/dist/android/templates/CraftNativeMutation.kt.template +14 -2
- package/dist/android/templates/CraftNativeServices.kt.template +561 -0
- package/dist/android/templates/CraftNativeShell.kt.template +1013 -0
- package/dist/android/templates/LocationRecordingService.kt.template +7 -0
- package/dist/android/templates/MainActivityNative.kt.template +738 -132
- package/dist/android/templates/build.gradle.kts.app.template +16 -0
- package/dist/cli.js +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
package {{PACKAGE_NAME}}
|
|
2
|
+
|
|
3
|
+
import android.app.Activity
|
|
4
|
+
import android.content.Context
|
|
5
|
+
import android.content.Intent
|
|
6
|
+
import org.json.JSONArray
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Health Connect left out of this app (`enableHealthConnect` is off), so
|
|
10
|
+
* the native renderer compiles without its library. Every call answers
|
|
11
|
+
* `CAPABILITY_DISABLED`; the `health` capability is not advertised either.
|
|
12
|
+
*/
|
|
13
|
+
internal class CraftNativeHealth(
|
|
14
|
+
@Suppress("UNUSED_PARAMETER") context: Context,
|
|
15
|
+
@Suppress("UNUSED_PARAMETER") activityProvider: () -> Activity?,
|
|
16
|
+
@Suppress("UNUSED_PARAMETER") backgroundReads: Boolean,
|
|
17
|
+
@Suppress("UNUSED_PARAMETER") historyReads: Boolean,
|
|
18
|
+
) {
|
|
19
|
+
fun perform(method: String, args: JSONArray, completion: (CraftNativeCapabilityResult) -> Unit) {
|
|
20
|
+
completion(CraftNativeCapabilityResult(code = "CAPABILITY_DISABLED", message = "Health Connect is not enabled for this app ($method, ${args.length()} arguments)"))
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?): Boolean = false
|
|
24
|
+
|
|
25
|
+
fun close() {}
|
|
26
|
+
|
|
27
|
+
companion object {
|
|
28
|
+
const val PERMISSION_REQUEST_CODE = 8411
|
|
29
|
+
fun readPermissions(type: String): Set<String> = emptySet()
|
|
30
|
+
fun writePermissions(type: String): Set<String> = emptySet()
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
package {{PACKAGE_NAME}}
|
|
2
|
+
|
|
3
|
+
import android.app.NotificationChannel
|
|
4
|
+
import android.app.NotificationManager
|
|
5
|
+
import android.app.PendingIntent
|
|
6
|
+
import android.content.Context
|
|
7
|
+
import android.content.Intent
|
|
8
|
+
import android.os.Build
|
|
9
|
+
import androidx.core.app.NotificationCompat
|
|
10
|
+
import androidx.core.app.NotificationManagerCompat
|
|
11
|
+
import com.google.firebase.messaging.FirebaseMessagingService
|
|
12
|
+
import com.google.firebase.messaging.RemoteMessage
|
|
13
|
+
import org.json.JSONObject
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Firebase Cloud Messaging for the native renderer.
|
|
17
|
+
*
|
|
18
|
+
* - A new registration token reaches every screen and the app script as
|
|
19
|
+
* `PUSH_TOKEN` (`craft.push.onToken`, the `craftPushToken` event), as the
|
|
20
|
+
* iOS host sends a new APNs token.
|
|
21
|
+
* - A notification that arrives while the app is open is shown anyway (FCM
|
|
22
|
+
* leaves that to the app) and heard as `craftNotificationReceived`; a tap
|
|
23
|
+
* opens the app with its data, which the app script hears as
|
|
24
|
+
* `craftNotificationResponse` (MainActivity.notificationTap). In the
|
|
25
|
+
* background, Android shows FCM's notification itself and a tap carries
|
|
26
|
+
* the same data.
|
|
27
|
+
* - A data-only message with `content-available` (a silent push) runs the
|
|
28
|
+
* app script's background work once (`craftSilentPush`).
|
|
29
|
+
*/
|
|
30
|
+
class CraftNativeMessagingService : FirebaseMessagingService() {
|
|
31
|
+
override fun onNewToken(token: String) {
|
|
32
|
+
getSharedPreferences("craft-native-push", Context.MODE_PRIVATE).edit().putString("token", token).apply()
|
|
33
|
+
CraftNativeHub.broadcast("PUSH_TOKEN", JSONObject().put("token", token))
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
override fun onMessageReceived(message: RemoteMessage) {
|
|
37
|
+
val data = JSONObject()
|
|
38
|
+
message.data.forEach { (key, value) -> data.put(key, value) }
|
|
39
|
+
val notification = message.notification
|
|
40
|
+
if (notification == null) {
|
|
41
|
+
if (message.data["content-available"] == "1" || message.data["contentAvailable"] == "true") {
|
|
42
|
+
CraftNativeBackground.runOnce(applicationContext, "craftSilentPush")
|
|
43
|
+
}
|
|
44
|
+
return
|
|
45
|
+
}
|
|
46
|
+
CraftNativeHub.broadcast("CRAFT_EVENT", JSONObject().put("event", "craftNotificationReceived").put("detail", data))
|
|
47
|
+
show(notification.title.orEmpty(), notification.body.orEmpty(), message.data)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
private fun show(title: String, body: String, data: Map<String, String>) {
|
|
51
|
+
val manager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
|
52
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && manager.getNotificationChannel(CHANNEL) == null) {
|
|
53
|
+
manager.createNotificationChannel(NotificationChannel(CHANNEL, applicationInfo.loadLabel(packageManager), NotificationManager.IMPORTANCE_DEFAULT))
|
|
54
|
+
}
|
|
55
|
+
val open = Intent(this, MainActivity::class.java)
|
|
56
|
+
.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP)
|
|
57
|
+
.putExtra("craft.notification", true)
|
|
58
|
+
data.forEach { (key, value) -> open.putExtra(key, value) }
|
|
59
|
+
val id = (data["notification_id"]?.toIntOrNull() ?: System.currentTimeMillis().toInt())
|
|
60
|
+
val tap = PendingIntent.getActivity(this, id, open, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
|
|
61
|
+
val built = NotificationCompat.Builder(this, CHANNEL)
|
|
62
|
+
.setSmallIcon(applicationInfo.icon)
|
|
63
|
+
.setContentTitle(title)
|
|
64
|
+
.setContentText(body)
|
|
65
|
+
.setStyle(NotificationCompat.BigTextStyle().bigText(body))
|
|
66
|
+
.setAutoCancel(true)
|
|
67
|
+
.setContentIntent(tap)
|
|
68
|
+
.build()
|
|
69
|
+
runCatching { NotificationManagerCompat.from(this).notify(id, built) }
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
companion object {
|
|
73
|
+
private const val CHANNEL = "craft-push"
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -260,8 +260,20 @@ class CraftNativeMutationDocument {
|
|
|
260
260
|
return result
|
|
261
261
|
}
|
|
262
262
|
|
|
263
|
-
|
|
264
|
-
|
|
263
|
+
/**
|
|
264
|
+
* Every type the renderer draws children of (MainActivity's makeView):
|
|
265
|
+
* an insert into a pressable row, a modal or a drawing's group was
|
|
266
|
+
* refused as INVALID_PARENT, and the whole screen was drawn again.
|
|
267
|
+
*/
|
|
268
|
+
private fun acceptsChildren(type: String): Boolean = type in CONTAINER_TYPES
|
|
269
|
+
|
|
270
|
+
private companion object {
|
|
271
|
+
val CONTAINER_TYPES = setOf(
|
|
272
|
+
"View", "SafeAreaView", "ScrollView", "KeyboardAvoidingView", "Modal", "Pressable",
|
|
273
|
+
"TouchableOpacity", "TouchableHighlight", "ImageBackground", "FlatList", "SectionList",
|
|
274
|
+
"Fragment", "Svg", "G",
|
|
275
|
+
)
|
|
276
|
+
}
|
|
265
277
|
|
|
266
278
|
private fun descendants(id: String, nodes: Map<String, Node>): Set<String> {
|
|
267
279
|
val result = linkedSetOf<String>()
|