capacitor-lottie-splash 0.1.0
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/CapacitorLottieSplash.podspec +19 -0
- package/Package.swift +30 -0
- package/README.md +120 -0
- package/android/build.gradle +36 -0
- package/android/settings.gradle +7 -0
- package/android/src/main/AndroidManifest.xml +3 -0
- package/android/src/main/java/com/headcount/plugins/lottiesplash/LottieSplashCoordinator.kt +498 -0
- package/android/src/main/java/com/headcount/plugins/lottiesplash/LottieSplashLaunch.kt +72 -0
- package/android/src/main/java/com/headcount/plugins/lottiesplash/LottieSplashPlugin.kt +121 -0
- package/android/src/main/res/drawable-nodpi/headcount_splash_poster.png +0 -0
- package/dist/esm/definitions.d.ts +65 -0
- package/dist/esm/definitions.js +2 -0
- package/dist/esm/index.d.ts +5 -0
- package/dist/esm/index.js +7 -0
- package/dist/esm/state-machine.d.ts +19 -0
- package/dist/esm/state-machine.js +79 -0
- package/dist/esm/web.d.ts +31 -0
- package/dist/esm/web.js +175 -0
- package/dist/plugin.cjs.js +17305 -0
- package/dist/plugin.js +17308 -0
- package/ios/Sources/LottieSplashPlugin/LottieSplashCoordinator.swift +501 -0
- package/ios/Sources/LottieSplashPlugin/LottieSplashPlugin.swift +71 -0
- package/package.json +78 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
require 'json'
|
|
2
|
+
|
|
3
|
+
package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
|
|
4
|
+
|
|
5
|
+
Pod::Spec.new do |s|
|
|
6
|
+
s.name = 'CapacitorLottieSplash'
|
|
7
|
+
s.version = package['version']
|
|
8
|
+
s.summary = package['description']
|
|
9
|
+
s.license = package['license']
|
|
10
|
+
s.homepage = package['repository']['url']
|
|
11
|
+
s.author = package['author']
|
|
12
|
+
s.source = { :git => package['repository']['url'], :tag => s.version.to_s }
|
|
13
|
+
s.source_files = 'ios/Sources/**/*.{swift,h,m,c,cc,mm,cpp}'
|
|
14
|
+
s.resources = 'node_modules/lottie-web/build/player/lottie.min.js'
|
|
15
|
+
s.ios.deployment_target = '15.0'
|
|
16
|
+
s.dependency 'Capacitor'
|
|
17
|
+
s.dependency 'lottie-ios', '4.6.1'
|
|
18
|
+
s.swift_version = '5.9'
|
|
19
|
+
end
|
package/Package.swift
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// swift-tools-version: 5.9
|
|
2
|
+
import PackageDescription
|
|
3
|
+
|
|
4
|
+
let package = Package(
|
|
5
|
+
name: "CapacitorLottieSplash",
|
|
6
|
+
platforms: [.iOS(.v15)],
|
|
7
|
+
products: [
|
|
8
|
+
.library(name: "CapacitorLottieSplash", targets: ["LottieSplashPlugin"])
|
|
9
|
+
],
|
|
10
|
+
dependencies: [
|
|
11
|
+
.package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", exact: "8.2.0"),
|
|
12
|
+
.package(url: "https://github.com/airbnb/lottie-ios.git", from: "4.6.1")
|
|
13
|
+
],
|
|
14
|
+
targets: [
|
|
15
|
+
.target(
|
|
16
|
+
name: "LottieSplashPlugin",
|
|
17
|
+
dependencies: [
|
|
18
|
+
.product(name: "Capacitor", package: "capacitor-swift-pm"),
|
|
19
|
+
.product(name: "Cordova", package: "capacitor-swift-pm"),
|
|
20
|
+
.product(name: "Lottie", package: "lottie-ios")
|
|
21
|
+
],
|
|
22
|
+
path: "ios/Sources/LottieSplashPlugin"
|
|
23
|
+
),
|
|
24
|
+
.testTarget(
|
|
25
|
+
name: "LottieSplashPluginTests",
|
|
26
|
+
dependencies: ["LottieSplashPlugin"],
|
|
27
|
+
path: "ios/Tests/LottieSplashPluginTests"
|
|
28
|
+
)
|
|
29
|
+
]
|
|
30
|
+
)
|
package/README.md
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# Capacitor Lottie Splash
|
|
2
|
+
|
|
3
|
+
`capacitor-lottie-splash` is a Capacitor 8 plugin for an app-owned splash presentation: a static OS launch surface hands off to Lottie on iOS and Android, while browser builds use an isolated DOM overlay.
|
|
4
|
+
|
|
5
|
+
The package is public. It contains no HeadCount production art; the consuming app bundles its own Lottie JSON, posters, and native launch resources.
|
|
6
|
+
|
|
7
|
+
## Contract
|
|
8
|
+
|
|
9
|
+
`show()` attaches a presentation or adopts the native cold-start presentation. `waitForCompletion()` resolves only after Lottie has completed or a visible static fallback has been selected. `hide()` is the app-ready latch: it removes the cover only after both conditions are true.
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
// Resolve and persist the app's appearance before this call. Native cold-start
|
|
13
|
+
// hosts read the same Capacitor Preferences value before JavaScript is running.
|
|
14
|
+
const presentation = await LottieSplash.show({ darkMode: true });
|
|
15
|
+
await LottieSplash.waitForCompletion({ presentationId: presentation.presentationId });
|
|
16
|
+
await LottieSplash.hide({ presentationId: presentation.presentationId });
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Repeated `show()` calls adopt an active presentation. Repeated `hide()` calls must use its presentation id. Stale presentation ids are rejected.
|
|
20
|
+
|
|
21
|
+
## Host startup integration
|
|
22
|
+
|
|
23
|
+
The native startup hook is intentionally small. A Capacitor bridge plugin cannot begin before the bridge exists, so the app supplies the earliest handoff and this package supplies the native cover.
|
|
24
|
+
|
|
25
|
+
### iOS
|
|
26
|
+
|
|
27
|
+
Create a `CAPBridgeViewController` subclass in the app target. Set it as the initial controller class/module in `Main.storyboard`.
|
|
28
|
+
|
|
29
|
+
```swift
|
|
30
|
+
import Capacitor
|
|
31
|
+
import CapacitorLottieSplash
|
|
32
|
+
|
|
33
|
+
final class HeadCountBridgeViewController: CAPBridgeViewController {
|
|
34
|
+
override func capacitorDidLoad() {
|
|
35
|
+
super.capacitorDidLoad()
|
|
36
|
+
LottieSplashCoordinator.shared.installInitialCover(on: self)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
override func viewDidAppear(_ animated: Bool) {
|
|
40
|
+
super.viewDidAppear(animated)
|
|
41
|
+
LottieSplashCoordinator.shared.startPlaybackIfVisible()
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Appearance contract
|
|
47
|
+
|
|
48
|
+
The host app's appearance preference is the source of truth for a native cold
|
|
49
|
+
start. Store it with Capacitor Preferences before the next launch, then provide
|
|
50
|
+
the same preference mapping when installing the native cover. In HeadCount this
|
|
51
|
+
is the existing `HEADCOUNT_DARK_MODE` key in Capacitor's default
|
|
52
|
+
`CapacitorStorage`, with `DARK_MODE` and `LIGHT_MODE` values. iOS and Android
|
|
53
|
+
both read that stored value before their WebView starts; the OS appearance is
|
|
54
|
+
only the fallback when it has not yet been set.
|
|
55
|
+
|
|
56
|
+
The JavaScript `show({ darkMode })` call adopts that native presentation. It
|
|
57
|
+
must use the app's already-resolved value and must not recolor an active native
|
|
58
|
+
cold-start cover, which prevents a light/dark flash during boot.
|
|
59
|
+
|
|
60
|
+
The static launch storyboard remains mandatory. Keep it appearance-aware and visually quiet: it should supply the same base color as the native cover, without a second static logo. The Lottie cover takes over as soon as its initial frame is ready.
|
|
61
|
+
|
|
62
|
+
### Android
|
|
63
|
+
|
|
64
|
+
Call `installSystemSplashBeforeCreate()` before `super.onCreate()`, and attach the one native cover from `load()` before `super.load()`. Do not use a dedicated splash activity or a second process: both produce a visible reset during the handoff.
|
|
65
|
+
|
|
66
|
+
```kotlin
|
|
67
|
+
class MainActivity : BridgeActivity() {
|
|
68
|
+
override fun onCreate(savedInstanceState: Bundle?) {
|
|
69
|
+
LottieSplashLaunch.installSystemSplashBeforeCreate(this)
|
|
70
|
+
super.onCreate(savedInstanceState)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
override fun load() {
|
|
74
|
+
LottieSplashLaunch.attachNativeCover(this, darkTheme = true)
|
|
75
|
+
super.load()
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
override fun onPause() {
|
|
79
|
+
LottieSplashLaunch.onHostPaused()
|
|
80
|
+
super.onPause()
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
override fun onResume() {
|
|
84
|
+
super.onResume()
|
|
85
|
+
LottieSplashLaunch.onHostResumed()
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
The system splash is a platform-controlled centered icon on a single color. It cannot render the full Lottie or gradient. Use a transparent system icon with an appearance-aware background when a second static mark would be distracting. The helper retains it only until the native cover has attached, then fades it out; it does not wait for application readiness.
|
|
91
|
+
|
|
92
|
+
## Assets
|
|
93
|
+
|
|
94
|
+
The host provides:
|
|
95
|
+
|
|
96
|
+
- `android/app/src/main/assets/lottie-splash/animatedLogo.json`;
|
|
97
|
+
- an iOS app-bundle `animatedLogo.json` resource;
|
|
98
|
+
- system-launch colors and the Android adaptive splash icon.
|
|
99
|
+
|
|
100
|
+
The documented HeadCount defaults are light `#f0f0f0 → #f5f5f5` and dark `#1e1e1e → #252525`, left to right.
|
|
101
|
+
|
|
102
|
+
## Recovery and accessibility
|
|
103
|
+
|
|
104
|
+
When playback completes before readiness, its final frame holds. After one second, a subtle indeterminate progress rail appears beneath the mark. After 15 foreground seconds the rail stops and a native/browser recovery surface presents “Still starting…” and “Try again.” The native retry reloads the WebView, so it does not depend on JavaScript having already loaded. Reduced-motion and asset failures retain the theme-matched native cover instead of exposing a blank screen.
|
|
105
|
+
|
|
106
|
+
For a staged native/over-the-air rollout, the consuming app must keep its web bundle and native host compatible. The native cover stays visible until the app-ready latch is set; a broken boot transitions to the visible recovery surface instead of exposing a blank page.
|
|
107
|
+
|
|
108
|
+
## Compatibility
|
|
109
|
+
|
|
110
|
+
Native resources cannot be changed by a web-only Capgo update. Before adopting this plugin, the host must define its old/new native-binary and web-bundle compatibility policy. The 30-second compatibility escape hatch prevents a stuck screen while allowing a slow but healthy cold start to adopt the native cover; an old bundle cannot provide the new loading experience.
|
|
111
|
+
|
|
112
|
+
## Verification
|
|
113
|
+
|
|
114
|
+
```sh
|
|
115
|
+
npm run verify:web
|
|
116
|
+
npm run verify:android
|
|
117
|
+
npm run verify:ios
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Native launch continuity requires real-device evidence; unit/build verification alone cannot prove the OS-to-native handoff.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
buildscript {
|
|
2
|
+
repositories { google(); mavenCentral() }
|
|
3
|
+
dependencies {
|
|
4
|
+
classpath 'com.android.tools.build:gradle:8.13.0'
|
|
5
|
+
classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:2.1.0'
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
apply plugin: 'com.android.library'
|
|
10
|
+
apply plugin: 'org.jetbrains.kotlin.android'
|
|
11
|
+
|
|
12
|
+
android {
|
|
13
|
+
namespace 'com.headcount.plugins.lottiesplash'
|
|
14
|
+
compileSdk project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 36
|
|
15
|
+
|
|
16
|
+
defaultConfig {
|
|
17
|
+
minSdk project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 26
|
|
18
|
+
targetSdk project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 36
|
|
19
|
+
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
|
|
20
|
+
}
|
|
21
|
+
compileOptions {
|
|
22
|
+
sourceCompatibility JavaVersion.VERSION_21
|
|
23
|
+
targetCompatibility JavaVersion.VERSION_21
|
|
24
|
+
}
|
|
25
|
+
kotlinOptions { jvmTarget = '21' }
|
|
26
|
+
testOptions { unitTests.returnDefaultValues = true }
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
repositories { google(); mavenCentral() }
|
|
30
|
+
|
|
31
|
+
dependencies {
|
|
32
|
+
implementation project(':capacitor-android')
|
|
33
|
+
implementation 'androidx.core:core-splashscreen:1.2.0'
|
|
34
|
+
implementation 'com.airbnb.android:lottie:6.7.1'
|
|
35
|
+
testImplementation 'junit:junit:4.13.2'
|
|
36
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
pluginManagement {
|
|
2
|
+
repositories { google(); mavenCentral(); gradlePluginPortal() }
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
rootProject.name = 'capacitor-lottie-splash-android'
|
|
6
|
+
include ':capacitor-android'
|
|
7
|
+
project(':capacitor-android').projectDir = new File('../node_modules/@capacitor/android/capacitor')
|