From 322422a05c63ea2c841e6a954b9a7671e697cf9b Mon Sep 17 00:00:00 2001 From: doomsower Date: Mon, 9 Sep 2019 21:14:35 +0300 Subject: [PATCH] feat: initial commit --- .eslintignore | 3 + .eslintrc.js | 4 + .gitattributes | 1 + .gitignore | 42 + .huskyrc | 6 + .prettierrc.yml | 4 + .releaserc.json | 10 + .travis.yml | 16 + LICENSE | 21 + README.md | 32 + android/build.gradle | 21 + android/src/main/AndroidManifest.xml | 4 + .../github/doomsower/RNStartupTimeModule.java | 39 + .../doomsower/RNStartupTimePackage.java | 26 + commitlint.config.js | 1 + example/.buckconfig | 6 + example/.flowconfig | 99 + example/.gitattributes | 1 + example/.gitignore | 59 + example/.watchmanconfig | 1 + example/App.js | 37 + example/__tests__/App-test.js | 14 + example/android/app/BUCK | 55 + example/android/app/build.gradle | 210 + example/android/app/build_defs.bzl | 19 + example/android/app/proguard-rules.pro | 10 + .../android/app/src/debug/AndroidManifest.xml | 8 + .../android/app/src/main/AndroidManifest.xml | 26 + .../main/java/com/example/MainActivity.java | 15 + .../java/com/example/MainApplication.java | 49 + .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 3056 bytes .../res/mipmap-hdpi/ic_launcher_round.png | Bin 0 -> 5024 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 2096 bytes .../res/mipmap-mdpi/ic_launcher_round.png | Bin 0 -> 2858 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 4569 bytes .../res/mipmap-xhdpi/ic_launcher_round.png | Bin 0 -> 7098 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 6464 bytes .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin 0 -> 10676 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 9250 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin 0 -> 15523 bytes .../app/src/main/res/values/strings.xml | 3 + .../app/src/main/res/values/styles.xml | 9 + example/android/build.gradle | 38 + example/android/gradle.properties | 21 + .../android/gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 55616 bytes .../gradle/wrapper/gradle-wrapper.properties | 5 + example/android/gradlew | 188 + example/android/gradlew.bat | 100 + example/android/settings.gradle | 3 + example/app.json | 4 + example/babel.config.js | 3 + example/index.js | 5 + example/ios/Podfile | 46 + example/ios/Podfile.lock | 187 + example/ios/example-tvOS/Info.plist | 53 + example/ios/example-tvOSTests/Info.plist | 24 + example/ios/example.xcodeproj/project.pbxproj | 923 ++ .../xcschemes/example-tvOS.xcscheme | 129 + .../xcshareddata/xcschemes/example.xcscheme | 136 + .../contents.xcworkspacedata | 10 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + example/ios/example/AppDelegate.h | 15 + example/ios/example/AppDelegate.m | 42 + .../ios/example/Base.lproj/LaunchScreen.xib | 42 + .../AppIcon.appiconset/Contents.json | 38 + .../ios/example/Images.xcassets/Contents.json | 6 + example/ios/example/Info.plist | 57 + example/ios/example/main.m | 16 + example/ios/exampleTests/Info.plist | 24 + example/ios/exampleTests/exampleTests.m | 68 + example/metro.config.js | 17 + example/package.json | 18 + example/yarn.lock | 4711 +++++++++ index.d.ts | 1 + index.js | 5 + ios/RNStartupTime.h | 5 + ios/RNStartupTime.m | 38 + ios/RNStartupTime.xcodeproj/project.pbxproj | 67 + package.json | 56 + react-native-startup-time.podspec | 18 + yarn.lock | 8780 +++++++++++++++++ 81 files changed, 16758 insertions(+) create mode 100644 .eslintignore create mode 100644 .eslintrc.js create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 .huskyrc create mode 100644 .prettierrc.yml create mode 100644 .releaserc.json create mode 100644 .travis.yml create mode 100644 LICENSE create mode 100644 README.md create mode 100644 android/build.gradle create mode 100644 android/src/main/AndroidManifest.xml create mode 100644 android/src/main/java/com/github/doomsower/RNStartupTimeModule.java create mode 100644 android/src/main/java/com/github/doomsower/RNStartupTimePackage.java create mode 100644 commitlint.config.js create mode 100644 example/.buckconfig create mode 100644 example/.flowconfig create mode 100644 example/.gitattributes create mode 100644 example/.gitignore create mode 100644 example/.watchmanconfig create mode 100644 example/App.js create mode 100644 example/__tests__/App-test.js create mode 100644 example/android/app/BUCK create mode 100644 example/android/app/build.gradle create mode 100644 example/android/app/build_defs.bzl create mode 100644 example/android/app/proguard-rules.pro create mode 100644 example/android/app/src/debug/AndroidManifest.xml create mode 100644 example/android/app/src/main/AndroidManifest.xml create mode 100644 example/android/app/src/main/java/com/example/MainActivity.java create mode 100644 example/android/app/src/main/java/com/example/MainApplication.java create mode 100644 example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 example/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png create mode 100644 example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 example/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png create mode 100644 example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 example/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png create mode 100644 example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png create mode 100644 example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png create mode 100644 example/android/app/src/main/res/values/strings.xml create mode 100644 example/android/app/src/main/res/values/styles.xml create mode 100644 example/android/build.gradle create mode 100644 example/android/gradle.properties create mode 100644 example/android/gradle/wrapper/gradle-wrapper.jar create mode 100644 example/android/gradle/wrapper/gradle-wrapper.properties create mode 100755 example/android/gradlew create mode 100644 example/android/gradlew.bat create mode 100644 example/android/settings.gradle create mode 100644 example/app.json create mode 100644 example/babel.config.js create mode 100644 example/index.js create mode 100644 example/ios/Podfile create mode 100644 example/ios/Podfile.lock create mode 100644 example/ios/example-tvOS/Info.plist create mode 100644 example/ios/example-tvOSTests/Info.plist create mode 100644 example/ios/example.xcodeproj/project.pbxproj create mode 100644 example/ios/example.xcodeproj/xcshareddata/xcschemes/example-tvOS.xcscheme create mode 100644 example/ios/example.xcodeproj/xcshareddata/xcschemes/example.xcscheme create mode 100644 example/ios/example.xcworkspace/contents.xcworkspacedata create mode 100644 example/ios/example.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 example/ios/example/AppDelegate.h create mode 100644 example/ios/example/AppDelegate.m create mode 100644 example/ios/example/Base.lproj/LaunchScreen.xib create mode 100644 example/ios/example/Images.xcassets/AppIcon.appiconset/Contents.json create mode 100644 example/ios/example/Images.xcassets/Contents.json create mode 100644 example/ios/example/Info.plist create mode 100644 example/ios/example/main.m create mode 100644 example/ios/exampleTests/Info.plist create mode 100644 example/ios/exampleTests/exampleTests.m create mode 100644 example/metro.config.js create mode 100644 example/package.json create mode 100644 example/yarn.lock create mode 100644 index.d.ts create mode 100644 index.js create mode 100644 ios/RNStartupTime.h create mode 100644 ios/RNStartupTime.m create mode 100644 ios/RNStartupTime.xcodeproj/project.pbxproj create mode 100644 package.json create mode 100644 react-native-startup-time.podspec create mode 100644 yarn.lock diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..97c3725 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,3 @@ +example/android/ +example/node_modules/ +example/ios/ diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..40c6dcd --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,4 @@ +module.exports = { + root: true, + extends: '@react-native-community', +}; diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..d42ff18 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +*.pbxproj -text diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c5464d9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,42 @@ +# OSX +# +.DS_Store + +# node.js +# +node_modules/ +npm-debug.log +yarn-error.log + +# Xcode +# +build/ +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 +xcuserdata +*.xccheckout +*.moved-aside +DerivedData +*.hmap +*.ipa +*.xcuserstate +project.xcworkspace + +# Android/IntelliJ +# +build/ +.idea +.gradle +local.properties +*.iml + +# BUCK +buck-out/ +\.buckd/ +*.keystore diff --git a/.huskyrc b/.huskyrc new file mode 100644 index 0000000..cfc13f3 --- /dev/null +++ b/.huskyrc @@ -0,0 +1,6 @@ +{ + "hooks": { + "pre-commit": "yarn lint && yarn pretty-quick --staged", + "commit-msg": "commitlint -E HUSKY_GIT_PARAMS" + } +} diff --git a/.prettierrc.yml b/.prettierrc.yml new file mode 100644 index 0000000..9ccf0c8 --- /dev/null +++ b/.prettierrc.yml @@ -0,0 +1,4 @@ +printWidth: 80 +singleQuote: true +trailingComma: 'all' +arrowParens: 'always' diff --git a/.releaserc.json b/.releaserc.json new file mode 100644 index 0000000..74b1a5b --- /dev/null +++ b/.releaserc.json @@ -0,0 +1,10 @@ +{ + "branch": "master", + "plugins": [ + "@semantic-release/commit-analyzer", + "@semantic-release/release-notes-generator", + "@semantic-release/npm", + "@semantic-release/git", + "@semantic-release/github" + ] +} diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..0eb2c77 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,16 @@ +language: node_js + +cache: + directories: + - node_modules +node_js: + - 10 + +branches: + only: + - master + +before_script: + - npm prune +script: + - npm run semantic-release diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..065cb84 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2019 Konstantin Kuznetsov + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..e67a205 --- /dev/null +++ b/README.md @@ -0,0 +1,32 @@ +# react-native-startup-time + +This module helps you to measure your app launch time. It is measured from the earliest point in time available to the native module, that is the module's initialization. When `getTimeSinceStartup` is called on JS side, you'll get a promise which resolves with difference between these two moments in ms. This is not very accurate, but should give you good enough base for further optimizations. + +On iOS time measurement is based on [this article](https://medium.com/@michael.eisel/measuring-your-ios-apps-pre-main-time-in-the-wild-98197f3d95b4). On Android [SystemClock.uptimeMills](https://developer.android.com/reference/android/os/SystemClock.html) is used. + +As far as I know, there's no way to programmatically obtain time passed since the moment when user taps on app icon. For this you have to use native dev tools. On Android this module will call `reportFullyDrawn` so you can inspect adb logs. + +If you know a better way to measure startup time (in a module), let me know or better shoot a PR. + +## Getting started + +`$ yarn add react-native-startup-time` + +### Mostly automatic installation + +This module supports autolinking so if you use RN 0.60+ then no additional action is required. + +Otherwise, run + +`$ react-native link react-native-startup-time` + +## Usage + +```javascript +import { getTimeSinceStartup } from 'react-native-startup-time'; + +// somewhere where you app is ready: +getTimeSinceStartup().then((time) => { + console.log(`Time since startup: ${time} ms`); +}); +``` diff --git a/android/build.gradle b/android/build.gradle new file mode 100644 index 0000000..8e2ae63 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,21 @@ +apply plugin: 'com.android.library' + +def safeExtGet(prop, fallback) { + rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback +} + +android { + compileSdkVersion safeExtGet('compileSdkVersion', 28) + buildToolsVersion safeExtGet('buildToolsVersion', '28.0.3') + + defaultConfig { + minSdkVersion safeExtGet('minSdkVersion', 16) + targetSdkVersion safeExtGet('targetSdkVersion', 28) + versionCode 1 + versionName "1.0.0" + } +} + +dependencies { + implementation 'com.facebook.react:react-native:+' +} diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml new file mode 100644 index 0000000..97e5a21 --- /dev/null +++ b/android/src/main/AndroidManifest.xml @@ -0,0 +1,4 @@ + + + diff --git a/android/src/main/java/com/github/doomsower/RNStartupTimeModule.java b/android/src/main/java/com/github/doomsower/RNStartupTimeModule.java new file mode 100644 index 0000000..cc92d3a --- /dev/null +++ b/android/src/main/java/com/github/doomsower/RNStartupTimeModule.java @@ -0,0 +1,39 @@ +package com.github.doomsower; + +import android.app.Activity; +import android.os.Build; +import android.os.SystemClock; +import android.util.Log; + +import com.facebook.react.bridge.Promise; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReactContextBaseJavaModule; +import com.facebook.react.bridge.ReactMethod; +import com.facebook.react.module.annotations.ReactModule; + +@ReactModule(name = "RNStartupTime") +public class RNStartupTimeModule extends ReactContextBaseJavaModule { + public static final String NAME = "RNStartupTime"; + + private final long startMark; + + public RNStartupTimeModule(ReactApplicationContext reactContext, long startMark) { + super(reactContext); + this.startMark = startMark; + } + + @Override + public String getName() { + return NAME; + } + + @ReactMethod + public void getTimeSinceStartup(Promise promise) { + int ms = (int) (SystemClock.uptimeMillis() - startMark); + Activity activity = getCurrentActivity(); + if (activity != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + activity.reportFullyDrawn(); + } + promise.resolve(ms); + } +} diff --git a/android/src/main/java/com/github/doomsower/RNStartupTimePackage.java b/android/src/main/java/com/github/doomsower/RNStartupTimePackage.java new file mode 100644 index 0000000..013beae --- /dev/null +++ b/android/src/main/java/com/github/doomsower/RNStartupTimePackage.java @@ -0,0 +1,26 @@ +package com.github.doomsower; + +import android.os.SystemClock; + +import com.facebook.react.ReactPackage; +import com.facebook.react.bridge.NativeModule; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.uimanager.ViewManager; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +public class RNStartupTimePackage implements ReactPackage { + private static final long START_MARK = SystemClock.uptimeMillis(); + + @Override + public List createNativeModules(ReactApplicationContext reactContext) { + return Arrays.asList(new RNStartupTimeModule(reactContext, START_MARK)); + } + + @Override + public List createViewManagers(ReactApplicationContext reactContext) { + return Collections.emptyList(); + } +} diff --git a/commitlint.config.js b/commitlint.config.js new file mode 100644 index 0000000..422b194 --- /dev/null +++ b/commitlint.config.js @@ -0,0 +1 @@ +module.exports = { extends: ['@commitlint/config-conventional'] }; diff --git a/example/.buckconfig b/example/.buckconfig new file mode 100644 index 0000000..934256c --- /dev/null +++ b/example/.buckconfig @@ -0,0 +1,6 @@ + +[android] + target = Google Inc.:Google APIs:23 + +[maven_repositories] + central = https://repo1.maven.org/maven2 diff --git a/example/.flowconfig b/example/.flowconfig new file mode 100644 index 0000000..1319ea1 --- /dev/null +++ b/example/.flowconfig @@ -0,0 +1,99 @@ +[ignore] +; We fork some components by platform +.*/*[.]android.js + +; Ignore "BUCK" generated dirs +/\.buckd/ + +; Ignore unexpected extra "@providesModule" +.*/node_modules/.*/node_modules/fbjs/.* + +; Ignore duplicate module providers +; For RN Apps installed via npm, "Libraries" folder is inside +; "node_modules/react-native" but in the source repo it is in the root +node_modules/react-native/Libraries/react-native/React.js + +; Ignore polyfills +node_modules/react-native/Libraries/polyfills/.* + +; These should not be required directly +; require from fbjs/lib instead: require('fbjs/lib/warning') +node_modules/warning/.* + +; Flow doesn't support platforms +.*/Libraries/Utilities/HMRLoadingView.js + +[untyped] +.*/node_modules/@react-native-community/cli/.*/.* + +[include] + +[libs] +node_modules/react-native/Libraries/react-native/react-native-interface.js +node_modules/react-native/flow/ + +[options] +emoji=true + +esproposal.optional_chaining=enable +esproposal.nullish_coalescing=enable + +module.file_ext=.js +module.file_ext=.json +module.file_ext=.ios.js + +module.system=haste +module.system.haste.use_name_reducers=true +# get basename +module.system.haste.name_reducers='^.*/\([a-zA-Z0-9$_.-]+\.js\(\.flow\)?\)$' -> '\1' +# strip .js or .js.flow suffix +module.system.haste.name_reducers='^\(.*\)\.js\(\.flow\)?$' -> '\1' +# strip .ios suffix +module.system.haste.name_reducers='^\(.*\)\.ios$' -> '\1' +module.system.haste.name_reducers='^\(.*\)\.android$' -> '\1' +module.system.haste.name_reducers='^\(.*\)\.native$' -> '\1' +module.system.haste.paths.blacklist=.*/__tests__/.* +module.system.haste.paths.blacklist=.*/__mocks__/.* +module.system.haste.paths.whitelist=/node_modules/react-native/Libraries/.* +module.system.haste.paths.whitelist=/node_modules/react-native/RNTester/.* +module.system.haste.paths.whitelist=/node_modules/react-native/IntegrationTests/.* +module.system.haste.paths.blacklist=/node_modules/react-native/Libraries/react-native/react-native-implementation.js +module.system.haste.paths.blacklist=/node_modules/react-native/Libraries/Animated/src/polyfills/.* + +munge_underscores=true + +module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub' + +suppress_type=$FlowIssue +suppress_type=$FlowFixMe +suppress_type=$FlowFixMeProps +suppress_type=$FlowFixMeState + +suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(\\)? *\\(site=[a-z,_]*react_native\\(_ios\\)?_\\(oss\\|fb\\)[a-z,_]*\\)?)\\) +suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(\\)? *\\(site=[a-z,_]*react_native\\(_ios\\)?_\\(oss\\|fb\\)[a-z,_]*\\)?)\\)?:? #[0-9]+ +suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError + +[lints] +sketchy-null-number=warn +sketchy-null-mixed=warn +sketchy-number=warn +untyped-type-import=warn +nonstrict-import=warn +deprecated-type=warn +unsafe-getters-setters=warn +inexact-spread=warn +unnecessary-invariant=warn +signature-verification-failure=warn +deprecated-utility=error + +[strict] +deprecated-type +nonstrict-import +sketchy-null +unclear-type +unsafe-getters-setters +untyped-import +untyped-type-import + +[version] +^0.98.0 diff --git a/example/.gitattributes b/example/.gitattributes new file mode 100644 index 0000000..d42ff18 --- /dev/null +++ b/example/.gitattributes @@ -0,0 +1 @@ +*.pbxproj -text diff --git a/example/.gitignore b/example/.gitignore new file mode 100644 index 0000000..828cc88 --- /dev/null +++ b/example/.gitignore @@ -0,0 +1,59 @@ +# OSX +# +.DS_Store + +# Xcode +# +build/ +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 +xcuserdata +*.xccheckout +*.moved-aside +DerivedData +*.hmap +*.ipa +*.xcuserstate +project.xcworkspace + +# Android/IntelliJ +# +build/ +.idea +.gradle +local.properties +*.iml + +# node.js +# +node_modules/ +npm-debug.log +yarn-error.log + +# BUCK +buck-out/ +\.buckd/ +*.keystore + +# fastlane +# +# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the +# screenshots whenever they are needed. +# For more information about the recommended setup visit: +# https://docs.fastlane.tools/best-practices/source-control/ + +*/fastlane/report.xml +*/fastlane/Preview.html +*/fastlane/screenshots + +# Bundle artifact +*.jsbundle + +# CocoaPods +/ios/Pods/ diff --git a/example/.watchmanconfig b/example/.watchmanconfig new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/example/.watchmanconfig @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/example/App.js b/example/App.js new file mode 100644 index 0000000..ddc8757 --- /dev/null +++ b/example/App.js @@ -0,0 +1,37 @@ +import React from 'react'; +import { Button, StyleSheet, Text, View } from 'react-native'; +import { getTimeSinceStartup } from 'react-native-startup-time'; + +const styles = StyleSheet.create({ + container: { + ...StyleSheet.absoluteFillObject, + alignItems: 'center', + justifyContent: 'center', + }, + label: { + marginTop: 16, + }, +}); + +const App = () => { + const [label, setLabel] = React.useState(''); + const refreshLabel = React.useCallback(() => { + getTimeSinceStartup().then((time) => { + console.log(`Time since startup: ${time} ms`); + setLabel(`Time since startup: ${time} ms`); + }); + }, []); + React.useEffect(() => { + refreshLabel(); + }, [refreshLabel]); + return ( + +