1
0
mirror of https://gitcode.com/gh_mirrors/re/react-native-pushy.git synced 2025-09-18 00:26:11 +08:00
Code Issues Packages Projects Releases Wiki Activity GitHub Gitee

Compare commits

...

83 Commits

Author SHA1 Message Date
sunnylqm
8f07d2da1d v9.0.5 2023-09-24 21:17:41 +08:00
sunnylqm
821722165a v9.0.4 2023-09-15 16:16:48 +08:00
sunnylqm
6cb53ac655 fix: lastChecking 2023-09-15 16:16:13 +08:00
sunnylqm
7b9a24168a v9.0.3 2023-09-06 23:18:07 +08:00
sunnylqm
c6354bbedc fix: return type 2023-09-06 23:16:42 +08:00
sunnylqm
b53878c291 chore: cleanup 2023-09-06 22:56:41 +08:00
sunnylqm
ab01312f8d v9.0.2 2023-09-06 22:53:54 +08:00
sunnylqm
44784b6d3e feat: return cached result 2023-09-06 11:20:31 +08:00
sunnylqm
30c21fed91 v9.0.1 2023-09-05 22:50:53 +08:00
sunnylqm
15af7802ad fix: type 2023-09-05 22:47:47 +08:00
sunnylqm
8bed6ef979 chore: cleanup 2023-09-05 22:01:13 +08:00
Sunny Luo
7d03dc24b7 Update README.md 2023-09-02 23:02:15 +08:00
sunnylqm
18849ee441 v9.0.0 2023-09-02 22:54:26 +08:00
sunnylqm
3ba1df2020 revert ios bundle detect 2023-09-02 22:52:58 +08:00
sunnylqm
7152ef7304 v9.0.0-beta.3 2023-09-02 22:49:12 +08:00
sunnylqm
094eb3f267 chore: cleanup 2023-09-02 22:40:55 +08:00
sunnylqm
6d01ce5152 chore: cleanup 2023-09-02 22:35:45 +08:00
sunnylqm
8bf1fed3f8 v9.0.0-beta.2 2023-09-02 21:07:04 +08:00
sunnylqm
39c4a6d339 feat: onEvents 2023-08-31 19:24:00 +08:00
sunnylqm
f1e9244a14 v9.0.0-beta.0 2023-07-01 12:11:28 +08:00
Sunny Luo
546f287b6c Merge pull request #409 from bozaigao/master
ci: remove testHotUpdate workflows
2023-04-03 15:58:38 +08:00
steven
175e43d524 ci: remove testHotUpdate workflows 2023-04-03 15:48:02 +08:00
Sunny Luo
b200766aa3 Merge pull request #408 from bozaigao/master
添加Detox e2e测试功能
2023-04-03 15:28:33 +08:00
Sunny Luo
7e65457cc1 Update .gitignore 2023-04-03 15:28:19 +08:00
Sunny Luo
6c5ccd98b7 Delete Example/testHotUpdate/artifacts directory 2023-04-03 15:27:41 +08:00
steven
d7abd590b0 feat: CI测试 2023-04-03 11:21:15 +08:00
steven
ffb2bf4afa feat: CI测试 2023-04-03 11:18:31 +08:00
steven
94c177512e feat: CI测试 2023-04-03 10:30:12 +08:00
steven
a16a73e754 feat: CI测试 2023-04-03 10:28:04 +08:00
steven
40df51db0f feat: CI测试 2023-04-03 08:18:19 +08:00
steven
97fec1e79e feat: CI测试 2023-04-02 23:53:28 +08:00
steven
75b4447437 feat: CI测试 2023-04-02 23:05:16 +08:00
steven
f9c6a97a50 feat: CI测试 2023-04-02 15:35:25 +08:00
steven
90aa07cc55 feat: CI测试 2023-04-02 14:47:05 +08:00
steven
26cda39451 feat: CI测试 2023-04-02 13:25:58 +08:00
steven
3d5012fced feat: CI测试 2023-04-02 12:51:43 +08:00
steven
533696e34d feat: fix 2023-03-31 22:03:42 +08:00
steven
9c98aaa899 feat: fix 2023-03-31 22:01:53 +08:00
steven
706cd8c415 feat: fix 2023-03-31 22:01:16 +08:00
steven
e76747f7d3 feat: fix 2023-03-31 21:47:22 +08:00
steven
65a2477932 feat: fix 2023-03-31 21:42:13 +08:00
steven
581cd3310e feat: fix 2023-03-31 21:41:18 +08:00
steven
f24bfd6f2a feat: fix 2023-03-31 21:37:13 +08:00
steven
c57802e2d2 feat: fix 2023-03-31 21:35:25 +08:00
steven
ca4f363e6d feat: fix 2023-03-31 08:52:11 +08:00
steven
6fcfa0b505 feat: fix 2023-03-30 12:50:33 +08:00
steven
12edc1df7a feat: fix 2023-03-30 11:24:44 +08:00
steven
4acba40f6c feat: fix 2023-03-26 20:45:08 +08:00
steven
0adda18b50 feat: e2e测试 2023-03-18 14:43:17 +08:00
steven
6cd256b7f4 feat: e2e测试 2023-03-17 16:16:58 +08:00
steven
bd04badbe8 feat: project init 2023-03-16 21:45:04 +08:00
steven
f0c52b0acd feat: project init 2023-03-16 15:40:10 +08:00
steven
76e5c6c59b feat: project init 2023-03-16 14:45:36 +08:00
steven
d2f53e17c5 feat: project init 2023-03-16 13:45:26 +08:00
steven
a182c5d3c6 feat: project init 2023-03-16 12:19:50 +08:00
steven
4e4c686f4d feat: project init 2023-03-16 11:31:27 +08:00
steven
301243b502 feat: project init 2023-03-16 11:29:34 +08:00
steven
b23898ec48 feat: project init 2023-03-16 10:45:19 +08:00
steven
909788c6f6 feat: project init 2023-03-16 10:38:32 +08:00
steven
507576795c feat: project init 2023-03-16 10:34:47 +08:00
steven
48526430a1 feat: project init 2023-03-16 10:29:08 +08:00
steven
aaab2d77c8 feat: project init 2023-03-16 10:24:42 +08:00
steven
b4b8856ed2 feat: project init 2023-03-16 10:20:57 +08:00
steven
eb1c9ff5de feat: project init 2023-03-16 10:19:38 +08:00
steven
6f346d7990 feat: project init 2023-03-16 10:18:45 +08:00
steven
27c053a645 feat: project init 2023-03-16 10:17:08 +08:00
steven
55506483f9 feat: project init 2023-03-16 10:15:32 +08:00
steven
5f28b75abd feat: project init 2023-03-16 10:03:31 +08:00
steven
4bf921c82c feat: project init 2023-03-16 09:43:26 +08:00
steven
68cc6d3fad feat: project init 2023-03-16 09:06:07 +08:00
steven
63c4825006 feat: project init 2023-03-16 08:36:50 +08:00
steven
aa5f5b9340 feat: project init 2023-03-16 08:06:41 +08:00
steven
6216fdfd35 feat: project init 2023-03-16 07:58:13 +08:00
steven
1d11fc64a8 feat: project init 2023-03-16 07:49:44 +08:00
steven
87a2004b2b feat: project init 2023-03-15 23:28:02 +08:00
steven
92675ed37c feat: project init 2023-03-15 23:27:25 +08:00
Sunny Luo
992b17d25a Merge pull request #403 from bozaigao/master
fix: fix NativeEventEmitter warning
2023-02-20 18:21:00 +08:00
steven
d538782b01 fix: fix NativeEventEmitter warning 2023-02-20 14:36:08 +08:00
sunnylqm
d6c268f533 chore: some tweak 2023-02-20 13:03:12 +08:00
Sunny Luo
55879198e8 Merge pull request #402 from bozaigao/master
feat: support for new architecture
2023-02-20 11:01:03 +08:00
steven
f8115c3a85 fix: optimize 2023-02-19 21:14:03 +08:00
steven
e859900df6 feat: support for new architecture 2023-02-19 18:25:16 +08:00
sunnylqm
65a332b88a update example to 0.71.1 2023-01-27 19:00:17 +08:00
100 changed files with 12777 additions and 4016 deletions

49
.github/workflows/e2e_android.yml vendored Normal file
View File

@@ -0,0 +1,49 @@
name: e2e-android
on: push
jobs:
e2e-android:
runs-on: macos-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
cache: yarn
node-version-file: .nvmrc
- name: Install Yarn dependencies
run: yarn --frozen-lockfile --prefer-offline
- name: Setup Java
uses: actions/setup-java@v3
with:
cache: gradle
distribution: temurin
java-version: 17
- name: Cache Detox build
id: cache-detox-build
uses: actions/cache@v3
with:
path: android/app/build
key: ${{ runner.os }}-detox-build
restore-keys: |
${{ runner.os }}-detox-build
- name: Detox build
run: yarn build:android-debug
- name: Get device name
id: device
run: node -e "console.log('AVD_NAME=' + require('./Example/testHotUpdate/.detoxrc').devices.emulator.device.avdName)" >> $GITHUB_OUTPUT
- name: Detox test
uses: reactivecircus/android-emulator-runner@v2
with:
api-level: 31
arch: x86_64
avd-name: ${{ steps.device.outputs.AVD_NAME }}
script: yarn test:android-debug

182
.github/workflows/e2e_ios.yml vendored Normal file
View File

@@ -0,0 +1,182 @@
name: Testing E2E iOS
on:
pull_request:
branches:
- '**'
paths-ignore:
- 'docs/**'
- 'website/**'
- '.spellcheck.dict.txt'
- '**/*.md'
push:
branches:
- master
paths-ignore:
- 'docs/**'
- 'website/**'
- '.spellcheck.dict.txt'
# - '**/*.md'
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
ios:
name: iOS
runs-on: macos-12
# TODO matrix across APIs, at least 11 and 15 (lowest to highest)
timeout-minutes: 60
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
steps:
# Set up tool versions
- uses: actions/setup-node@v3
with:
node-version: 16
- name: Configure JDK 1.11
uses: actions/setup-java@v3
with:
distribution: 'temurin'
java-version: '11'
- uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: 'latest-stable'
- uses: actions/checkout@v3
with:
fetch-depth: 50
# Set path variables needed for caches
- name: Set workflow variables
id: workflow-variables
run: |
echo "metro-cache=$HOME/.metro" >> $GITHUB_OUTPUT
echo "xcode-version=$(xcodebuild -version|tail -1|cut -f3 -d' ')" >> $GITHUB_OUTPUT
echo "yarn-cache-dir=$(yarn cache dir)" >> $GITHUB_OUTPUT
- uses: actions/cache@v3
name: Yarn Cache
id: yarn-cache
with:
path: ${{ steps.workflow-variables.outputs.yarn-cache-dir }}
key: ${{ runner.os }}-yarn-v1-${{ hashFiles('yarn.lock') }}
restore-keys: ${{ runner.os }}-yarn-v1
- uses: actions/cache@v3
name: Detox Framework Cache
id: detox-cache
with:
path: ~/Library/Detox/ios
key: ${{ runner.os }}-detox-framework-cache-${{ steps.workflow-variables.outputs.xcode-version }}
# Detox is compiled during yarn install, using Xcode, set up cache first
- uses: hendrikmuhs/ccache-action@v1.2
name: Xcode Compile Cache
with:
key: ${{ runner.os }}-v2 # makes a unique key w/related restore key internally
max-size: 1500M
- name: Yarn Install
uses: nick-invision/retry@v2
with:
timeout_minutes: 10
retry_wait_seconds: 60
max_attempts: 3
command: yarn --no-audit --prefer-offline
- name: Setup Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: 3
- name: Update Ruby build tools
uses: nick-invision/retry@v2
with:
timeout_minutes: 2
retry_wait_seconds: 60
max_attempts: 3
command: gem update cocoapods xcodeproj
- uses: actions/cache@v3
name: Cache Pods
id: pods-cache
with:
path: tests/ios/Pods
key: ${{ runner.os }}-pods-v2-${{ hashFiles('tests/ios/Podfile.lock') }}
restore-keys: ${{ runner.os }}-pods-v2
- name: Pod Install
uses: nick-invision/retry@v2
with:
timeout_minutes: 10
retry_wait_seconds: 30
max_attempts: 3
command: yarn tests:ios:pod:install
- name: Cache Firestore Emulator
uses: actions/cache@v3
with:
path: ~/.cache/pushy/emulators
key: pushy-emulators-v1-${{ github.run_id }}
restore-keys: pushy-emulators-v1
- name: Start Firestore Emulator
run: yarn tests:emulator:start-ci
- name: Install brew utilities
uses: nick-invision/retry@v2
with:
timeout_minutes: 5
retry_wait_seconds: 60
max_attempts: 3
command: HOMEBREW_NO_AUTO_UPDATE=1 brew tap wix/brew && HOMEBREW_NO_AUTO_UPDATE=1 brew install applesimutils xcbeautify && applesimutils --list
- name: Build iOS App
run: |
export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH"
export CCACHE_SLOPPINESS=clang_index_store,file_stat_matches,include_file_ctime,include_file_mtime,ivfsoverlay,pch_defines,modules,system_headers,time_macros
export CCACHE_FILECLONE=true
export CCACHE_DEPEND=true
export CCACHE_INODECACHE=true
export CCACHE_LIMIT_MULTIPLE=0.95
ccache -s
export SKIP_BUNDLING=1
export RCT_NO_LAUNCH_PACKAGER=1
set -o pipefail
yarn build:ios-debug
ccache -s
shell: bash
- name: Metro Bundler Cache
uses: actions/cache@v3
with:
path: ${{ steps.workflow-variables.outputs.metro-cache }}
key: ${{ runner.os }}-metro-v1-${{ github.run_id }}
restore-keys: ${{ runner.os }}-metro-v1
- name: Pre-fetch Javascript bundle
run: |
nohup yarn tests:packager:jet-ci &
printf 'Waiting for packager to come online'
until curl --output /dev/null --silent --head --fail http://localhost:8081/status; do
printf '.'
sleep 2
done
echo "Packager is online! Preparing bundle..."
curl --output /dev/null --silent --head --fail "http://localhost:8081/index.bundle?platform=ios&dev=true&minify=false&inlineSourceMap=true"
echo "...javascript bundle ready"
- name: Create Simulator Log
# With a little delay so the detox test below has time to spawn it, missing the first part of boot is fine
# If you boot the simulator separately from detox, some other race fails and detox testee never sends ready to proxy
continue-on-error: true
run: nohup sh -c "sleep 30 && xcrun simctl spawn booted log stream --level debug --style compact > simulator.log 2>&1 &"
- name: Detox Test
timeout-minutes: 60
run: yarn test:ios-debug

View File

@@ -0,0 +1,10 @@
#!/bin/bash
echo "Running $1 on all running emulators..."
devices=`adb devices`
for device in $devices; do
if [[ "$device" =~ "emulator-" ]]; then
adb -s $device $1
fi
done
echo "All Done."

View File

@@ -0,0 +1,13 @@
{
"rules": {
// Database in general is closed. Read/Write to anything but "tests/" will fail.
".read": false,
".write": false,
// ..."tests" node will succeed
"tests": {
".read": true,
".write": true,
}
}
}

39
.github/workflows/scripts/firebase.json vendored Normal file
View File

@@ -0,0 +1,39 @@
{
"firestore": {
"rules": "firestore.rules",
"indexes": "firestore.indexes.json"
},
"functions": {
"predeploy": [
"yarn",
"yarn --prefix \"$RESOURCE_DIR\" build"
],
"source": "functions"
},
"database": {
"rules": "database.rules"
},
"storage": {
"rules": "storage.rules"
},
"emulators": {
"auth": {
"port": 9099
},
"database": {
"port": 9000
},
"firestore": {
"port": 8080
},
"functions": {
"port": 5001
},
"storage": {
"port": 9199
},
"ui": {
"enabled": true
}
}
}

View File

@@ -0,0 +1,72 @@
{
"indexes": [
{
"collectionGroup": "firestore",
"queryScope": "COLLECTION",
"fields": [
{
"fieldPath": "a",
"order": "ASCENDING"
},
{
"fieldPath": "b",
"order": "ASCENDING"
}
]
}
],
"fieldOverrides": [
{
"collectionGroup": "collectionGroup",
"fieldPath": "value",
"indexes": [
{
"order": "ASCENDING",
"queryScope": "COLLECTION"
},
{
"order": "DESCENDING",
"queryScope": "COLLECTION"
},
{
"arrayConfig": "CONTAINS",
"queryScope": "COLLECTION"
},
{
"order": "ASCENDING",
"queryScope": "COLLECTION_GROUP"
},
{
"order": "DESCENDING",
"queryScope": "COLLECTION_GROUP"
}
]
},
{
"collectionGroup": "collectionGroup",
"fieldPath": "number",
"indexes": [
{
"order": "ASCENDING",
"queryScope": "COLLECTION"
},
{
"order": "DESCENDING",
"queryScope": "COLLECTION"
},
{
"arrayConfig": "CONTAINS",
"queryScope": "COLLECTION"
},
{
"order": "ASCENDING",
"queryScope": "COLLECTION_GROUP"
},
{
"order": "DESCENDING",
"queryScope": "COLLECTION_GROUP"
}
]
}
]
}

View File

@@ -0,0 +1,17 @@
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if false;
}
match /firestore-bundle-tests/{document=**} {
allow read, write: if true;
}
match /firestore/{document=**} {
allow read, write: if true;
}
match /{path=**}/collectionGroup/{documentId} {
allow read, write: if true;
}
}
}

View File

@@ -0,0 +1,10 @@
# Compiled JavaScript files
lib/**/*.js
lib/**/*.js.map
# TypeScript v1 declaration files
typings/
# Node.js dependency directory
node_modules/
yarn.lock

View File

@@ -0,0 +1,24 @@
{
"name": "functions",
"scripts": {
"build": "tsc",
"serve": "npm run build && firebase emulators:start --only functions",
"shell": "npm run build && firebase functions:shell",
"start": "npm run shell",
"deploy": "firebase deploy --only functions",
"logs": "firebase functions:log"
},
"engines": {
"node": "16"
},
"main": "lib/index.js",
"dependencies": {
"firebase-admin": "^11.3.0",
"firebase-functions": "^4.2.1"
},
"devDependencies": {
"firebase-functions-test": "^3.0.0",
"typescript": "^4.9.5"
},
"private": true
}

View File

@@ -0,0 +1,13 @@
/*
*
* Testing tools for invertase/react-native-firebase use only.
*
* Copyright (C) 2018-present Invertase Limited <oss@invertase.io>
*
* See License file for more information.
*/
/* eslint-disable global-require */
module.exports = {
SAMPLE_DATA: require('./functions/sample-data'),
};

View File

@@ -0,0 +1,12 @@
import * as functions from 'firebase-functions';
// // Start writing Firebase Functions
// // https://firebase.google.com/docs/functions/typescript
//
export const helloWorld = functions.https.onRequest((request, response) => {
functions.logger.info('Hello logs!', { structuredData: true });
response.send('{ "data": "Hello from Firebase!" }');
});
export { testFunctionCustomRegion } from './testFunctionCustomRegion';
export { testFunctionDefaultRegion } from './testFunctionDefaultRegion';

View File

@@ -0,0 +1,80 @@
/*
* Testing tools for invertase/react-native-firebase use only.
*
* Copyright (C) 2018-present Invertase Limited <oss@invertase.io>
*
* See License file for more information.
*/
const SAMPLE_DATA: { [key: string]: any } = {
number: 1234,
string: 'acde',
boolean: true,
null: null,
object: {
number: 1234,
string: 'acde',
boolean: true,
null: null,
},
array: [1234, 'acde', true, null],
deepObject: {
array: [1234, 'acde', false, null],
object: {
number: 1234,
string: 'acde',
boolean: true,
null: null,
array: [1234, 'acde', true, null],
},
number: 1234,
string: 'acde',
boolean: true,
null: null,
},
deepArray: [
1234,
'acde',
true,
null,
[1234, 'acde', true, null],
{
number: 1234,
string: 'acde',
boolean: true,
null: null,
array: [1234, 'acde', true, null],
},
],
deepMap: {
number: 123,
string: 'foo',
booleanTrue: true,
booleanFalse: false,
null: null,
list: ['1', 2, true, false],
map: {
number: 123,
string: 'foo',
booleanTrue: true,
booleanFalse: false,
null: null,
},
},
deepList: [
'1',
2,
true,
false,
['1', 2, true, false],
{
number: 123,
string: 'foo',
booleanTrue: true,
booleanFalse: false,
null: null,
},
],
};
export default SAMPLE_DATA;

View File

@@ -0,0 +1,14 @@
/*
*
* Testing tools for invertase/react-native-firebase use only.
*
* Copyright (C) 2018-present Invertase Limited <oss@invertase.io>
*
* See License file for more information.
*/
import * as functions from 'firebase-functions';
export const testFunctionCustomRegion = functions
.region('europe-west1')
.https.onCall(() => 'europe-west1');

View File

@@ -0,0 +1,70 @@
/*
*
* Testing tools for invertase/react-native-firebase use only.
*
* Copyright (C) 2018-present Invertase Limited <oss@invertase.io>
*
* See License file for more information.
*/
import * as assert from 'assert';
import { FirebaseError } from 'firebase-admin';
import * as functions from 'firebase-functions';
import SAMPLE_DATA from './sample-data';
export const testFunctionDefaultRegion = functions.https.onCall(data => {
console.log(Date.now(), data);
if (typeof data === 'undefined') {
return 'undefined';
}
if (typeof data === 'string') {
return 'string';
}
if (typeof data === 'number') {
return 'number';
}
if (typeof data === 'boolean') {
return 'boolean';
}
if (data === null) {
return 'null';
}
if (Array.isArray(data)) {
return 'array';
}
const { type, asError, inputData } = data;
if (!Object.hasOwnProperty.call(SAMPLE_DATA, type)) {
throw new functions.https.HttpsError('invalid-argument', 'Invalid test requested.');
}
const outputData = SAMPLE_DATA[type];
try {
assert.deepEqual(outputData, inputData);
} catch (e) {
console.error(e);
throw new functions.https.HttpsError(
'invalid-argument',
'Input and Output types did not match.',
(e as FirebaseError).message,
);
}
// all good
if (asError) {
throw new functions.https.HttpsError(
'cancelled',
'Response data was requested to be sent as part of an Error payload, so here we are!',
outputData,
);
}
return outputData;
});

View File

@@ -0,0 +1,16 @@
{
"compilerOptions": {
"module": "commonjs",
"noImplicitReturns": true,
"noUnusedLocals": true,
"outDir": "lib",
"sourceMap": true,
"skipLibCheck": true,
"strict": true,
"target": "es2017"
},
"compileOnSave": true,
"include": [
"src"
]
}

View File

@@ -0,0 +1,6 @@
@REM this pushd is likely not needed, but just in case
pushd "%~dp0"
@REM this is just to see what our current directory is. Should be .github/workflow/scripts
echo %cd%
@REM strangely, unless you specify the config file as being right in the current directory, it won't find it, and everything fails
yarn firebase emulators:start --config %cd%\firebase.json --only auth,database,firestore,functions,storage --project react-native-firebase-testing

View File

@@ -0,0 +1,44 @@
#!/bin/bash
if ! [ -x "$(command -v firebase)" ]; then
echo "❌ Firebase-tools CLI is missing. Run 'npm i -g firebase-tools' or the equivalent"
exit 1
fi
EMU_START_COMMAND="firebase emulators:start --only auth,database,firestore,functions,storage --project react-native-firebase-testing"
#EMU_START_COMMAND="sleep 120"
MAX_RETRIES=3
MAX_CHECKATTEMPTS=60
CHECKATTEMPTS_WAIT=1
# Make sure functions are ready to go
pushd "$(dirname "$0")/functions" && yarn && yarn build && popd
RETRIES=1
while [ $RETRIES -le $MAX_RETRIES ]; do
if [ "$1" == "--no-daemon" ]; then
echo "Starting Firebase Emulator Suite in foreground."
$EMU_START_COMMAND
exit 0
else
echo "Starting Firebase Emulator Suite in background."
$EMU_START_COMMAND &
CHECKATTEMPTS=1
while [ $CHECKATTEMPTS -le $MAX_CHECKATTEMPTS ]; do
sleep $CHECKATTEMPTS_WAIT
if curl --output /dev/null --silent --fail http://localhost:8080; then
echo "Firebase Emulator Suite is online!"
exit 0;
fi
echo "Waiting for Firebase Emulator Suite to come online, check $CHECKATTEMPTS of $MAX_CHECKATTEMPTS..."
((CHECKATTEMPTS = CHECKATTEMPTS + 1))
done
fi
echo "Firebase Emulator Suite did not come online in $MAX_CHECKATTEMPTS checks. Try $RETRIES of $MAX_RETRIES."
((RETRIES = RETRIES + 1))
done
echo "Firebase Emulator Suite did not come online after $MAX_RETRIES attempts."
exit 1

21
.github/workflows/scripts/storage.rules vendored Normal file
View File

@@ -0,0 +1,21 @@
rules_version = '2';
service firebase.storage {
match /b/{bucket}/o {
match /{document=**} {
allow read, write: if false;
}
match /writeOnly.jpeg {
allow read: if false;
allow write: if true;
}
match /playground/{document=**} {
allow read, write: if true;
}
match /react-native-firebase-testing/{document=**} {
allow read, write: if true;
}
}
}

6
.gitignore vendored
View File

@@ -41,6 +41,8 @@ local.properties
node_modules/ node_modules/
npm-debug.log npm-debug.log
Example/**/update.json Example/**/.update
Example/**/.pushy
Example/testHotUpdate/artifacts
yarn-error.log yarn-error.log
Example/testHotUpdate/.pushy

1
.nvmrc Normal file
View File

@@ -0,0 +1 @@
18

View File

@@ -0,0 +1,94 @@
/** @type {Detox.DetoxConfig} */
module.exports = {
logger: {
level: process.env.CI ? 'debug' : undefined,
},
testRunner: {
args: {
config: 'e2e/jest.config.js',
maxWorkers: process.env.CI ? 2 : undefined,
_: ['e2e'],
},
},
artifacts: {
plugins: {
log: process.env.CI ? 'failing' : undefined,
screenshot: process.env.CI ? 'failing' : undefined,
},
},
apps: {
'ios.debug': {
type: 'ios.app',
binaryPath: 'ios/build/Build/Products/Debug-iphonesimulator/AwesomeProject.app',
build: "xcodebuild -workspace ios/AwesomeProject.xcworkspace -UseNewBuildSystem=NO -scheme AwesomeProject -configuration Debug -sdk iphonesimulator -derivedDataPath ios/build",
start: "scripts/start-rn.sh ios",
},
'ios.release': {
type: 'ios.app',
binaryPath:
'ios/build/Build/Products/Release-iphonesimulator/AwesomeProject.app',
build:
'export RCT_NO_LAUNCH_PACKAGER=true && xcodebuild -workspace ios/AwesomeProject.xcworkspace -UseNewBuildSystem=NO -scheme AwesomeProject -configuration Release -sdk iphonesimulator -derivedDataPath ios/build -quiet',
},
'android.debug': {
type: 'android.apk',
binaryPath: 'android/app/build/outputs/apk/debug/app-debug.apk',
build:
'cd android && ./gradlew assembleDebug assembleAndroidTest -DtestBuildType=debug',
start: "scripts/start-rn.sh android",
reversePorts: [8081],
},
'android.release': {
type: 'android.apk',
binaryPath: 'android/app/build/outputs/apk/release/app-release.apk',
build:
'cd android && ./gradlew assembleRelease assembleAndroidTest -DtestBuildType=release',
},
},
devices: {
simulator: {
type: 'ios.simulator',
device: {
type: 'iPhone 14',
},
},
attached: {
type: 'android.attached',
device: {
adbName: '.*',
},
},
emulator: {
type: 'android.emulator',
device: {
avdName: 'Pixel_3a_API_33_arm64-v8a',
},
},
},
configurations: {
'ios.sim.debug': {
device: 'simulator',
app: 'ios.debug',
},
'ios.sim.release': {
device: 'simulator',
app: 'ios.release',
},
'android.att.debug': {
device: 'attached',
app: 'android.debug',
},
'android.att.release': {
device: 'attached',
app: 'android.release',
},
'android.emu.debug': {
device: 'emulator',
app: 'android.debug',
},
'android.emu.release': {
device: 'emulator',
app: 'android.release',
},
},
};

View File

@@ -52,7 +52,6 @@ nonstrict-import=warn
deprecated-type=warn deprecated-type=warn
unsafe-getters-setters=warn unsafe-getters-setters=warn
unnecessary-invariant=warn unnecessary-invariant=warn
signature-verification-failure=warn
[strict] [strict]
deprecated-type deprecated-type
@@ -64,4 +63,4 @@ untyped-import
untyped-type-import untyped-type-import
[version] [version]
^0.170.0 ^0.176.3

View File

@@ -20,6 +20,7 @@ DerivedData
*.hmap *.hmap
*.ipa *.ipa
*.xcuserstate *.xcuserstate
ios/.xcode.env.local
# Android/IntelliJ # Android/IntelliJ
# #
@@ -49,9 +50,10 @@ buck-out/
# For more information about the recommended setup visit: # For more information about the recommended setup visit:
# https://docs.fastlane.tools/best-practices/source-control/ # https://docs.fastlane.tools/best-practices/source-control/
*/fastlane/report.xml **/fastlane/report.xml
*/fastlane/Preview.html **/fastlane/Preview.html
*/fastlane/screenshots **/fastlane/screenshots
**/fastlane/test_output
# Bundle artifact # Bundle artifact
*.jsbundle *.jsbundle

View File

@@ -0,0 +1 @@
18

View File

@@ -1 +1 @@
2.7.4 2.7.5

View File

@@ -1,112 +0,0 @@
/**
* Sample React Native App
* https://github.com/facebook/react-native
*
* @format
* @flow strict-local
*/
import React from 'react';
import type {Node} from 'react';
import {
SafeAreaView,
ScrollView,
StatusBar,
StyleSheet,
Text,
useColorScheme,
View,
} from 'react-native';
import {
Colors,
DebugInstructions,
Header,
LearnMoreLinks,
ReloadInstructions,
} from 'react-native/Libraries/NewAppScreen';
const Section = ({children, title}): Node => {
const isDarkMode = useColorScheme() === 'dark';
return (
<View style={styles.sectionContainer}>
<Text
style={[
styles.sectionTitle,
{
color: isDarkMode ? Colors.white : Colors.black,
},
]}>
{title}
</Text>
<Text
style={[
styles.sectionDescription,
{
color: isDarkMode ? Colors.light : Colors.dark,
},
]}>
{children}
</Text>
</View>
);
};
const App: () => Node = () => {
const isDarkMode = useColorScheme() === 'dark';
const backgroundStyle = {
backgroundColor: isDarkMode ? Colors.darker : Colors.lighter,
};
return (
<SafeAreaView style={backgroundStyle}>
<StatusBar barStyle={isDarkMode ? 'light-content' : 'dark-content'} />
<ScrollView
contentInsetAdjustmentBehavior="automatic"
style={backgroundStyle}>
<Header />
<View
style={{
backgroundColor: isDarkMode ? Colors.black : Colors.white,
}}>
<Section title="Step One">
Edit <Text style={styles.highlight}>App.js</Text> to change this
screen and then come back to see your edits.
</Section>
<Section title="See Your Changes">
<ReloadInstructions />
</Section>
<Section title="Debug">
<DebugInstructions />
</Section>
<Section title="Learn More">
Read the docs to discover what to do next:
</Section>
<LearnMoreLinks />
</View>
</ScrollView>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
sectionContainer: {
marginTop: 32,
paddingHorizontal: 24,
},
sectionTitle: {
fontSize: 24,
fontWeight: '600',
},
sectionDescription: {
marginTop: 8,
fontSize: 18,
fontWeight: '400',
},
highlight: {
fontWeight: '700',
},
});
export default App;

View File

@@ -1,6 +1,6 @@
source 'https://rubygems.org' source 'https://rubygems.org'
# You may use http://rbenv.org/ or https://rvm.io/ to install and use this version # You may use http://rbenv.org/ or https://rvm.io/ to install and use this version
ruby '2.7.4' ruby '3.1.1'
gem 'cocoapods', '~> 1.11', '>= 1.11.2' gem 'cocoapods', '~> 1.11', '>= 1.11.2'

View File

@@ -1,30 +1,29 @@
GEM GEM
remote: https://rubygems.org/ remote: https://rubygems.org/
specs: specs:
CFPropertyList (3.0.5) CFPropertyList (3.0.6)
rexml rexml
activesupport (6.1.5.1) activesupport (7.0.4.3)
concurrent-ruby (~> 1.0, >= 1.0.2) concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 1.6, < 2) i18n (>= 1.6, < 2)
minitest (>= 5.1) minitest (>= 5.1)
tzinfo (~> 2.0) tzinfo (~> 2.0)
zeitwerk (~> 2.3) addressable (2.8.1)
addressable (2.8.0) public_suffix (>= 2.0.2, < 6.0)
public_suffix (>= 2.0.2, < 5.0)
algoliasearch (1.27.5) algoliasearch (1.27.5)
httpclient (~> 2.8, >= 2.8.3) httpclient (~> 2.8, >= 2.8.3)
json (>= 1.5.1) json (>= 1.5.1)
atomos (0.1.3) atomos (0.1.3)
claide (1.1.0) claide (1.1.0)
cocoapods (1.11.3) cocoapods (1.12.0)
addressable (~> 2.8) addressable (~> 2.8)
claide (>= 1.0.2, < 2.0) claide (>= 1.0.2, < 2.0)
cocoapods-core (= 1.11.3) cocoapods-core (= 1.12.0)
cocoapods-deintegrate (>= 1.0.3, < 2.0) cocoapods-deintegrate (>= 1.0.3, < 2.0)
cocoapods-downloader (>= 1.4.0, < 2.0) cocoapods-downloader (>= 1.6.0, < 2.0)
cocoapods-plugins (>= 1.0.0, < 2.0) cocoapods-plugins (>= 1.0.0, < 2.0)
cocoapods-search (>= 1.0.0, < 2.0) cocoapods-search (>= 1.0.0, < 2.0)
cocoapods-trunk (>= 1.4.0, < 2.0) cocoapods-trunk (>= 1.6.0, < 2.0)
cocoapods-try (>= 1.1.0, < 2.0) cocoapods-try (>= 1.1.0, < 2.0)
colored2 (~> 3.1) colored2 (~> 3.1)
escape (~> 0.0.4) escape (~> 0.0.4)
@@ -32,10 +31,10 @@ GEM
gh_inspector (~> 1.0) gh_inspector (~> 1.0)
molinillo (~> 0.8.0) molinillo (~> 0.8.0)
nap (~> 1.0) nap (~> 1.0)
ruby-macho (>= 1.0, < 3.0) ruby-macho (>= 2.3.0, < 3.0)
xcodeproj (>= 1.21.0, < 2.0) xcodeproj (>= 1.21.0, < 2.0)
cocoapods-core (1.11.3) cocoapods-core (1.12.0)
activesupport (>= 5.0, < 7) activesupport (>= 5.0, < 8)
addressable (~> 2.8) addressable (~> 2.8)
algoliasearch (~> 1.0) algoliasearch (~> 1.0)
concurrent-ruby (~> 1.1) concurrent-ruby (~> 1.1)
@@ -54,19 +53,19 @@ GEM
netrc (~> 0.11) netrc (~> 0.11)
cocoapods-try (1.2.0) cocoapods-try (1.2.0)
colored2 (3.1.2) colored2 (3.1.2)
concurrent-ruby (1.1.10) concurrent-ruby (1.2.2)
escape (0.0.4) escape (0.0.4)
ethon (0.15.0) ethon (0.16.0)
ffi (>= 1.15.0) ffi (>= 1.15.0)
ffi (1.15.5) ffi (1.15.5)
fourflusher (2.3.1) fourflusher (2.3.1)
fuzzy_match (2.0.4) fuzzy_match (2.0.4)
gh_inspector (1.1.3) gh_inspector (1.1.3)
httpclient (2.8.3) httpclient (2.8.3)
i18n (1.10.0) i18n (1.12.0)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
json (2.6.1) json (2.6.3)
minitest (5.15.0) minitest (5.18.0)
molinillo (0.8.0) molinillo (0.8.0)
nanaimo (0.3.0) nanaimo (0.3.0)
nap (1.1.0) nap (1.1.0)
@@ -76,16 +75,15 @@ GEM
ruby-macho (2.5.1) ruby-macho (2.5.1)
typhoeus (1.4.0) typhoeus (1.4.0)
ethon (>= 0.9.0) ethon (>= 0.9.0)
tzinfo (2.0.4) tzinfo (2.0.6)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
xcodeproj (1.21.0) xcodeproj (1.22.0)
CFPropertyList (>= 2.3.3, < 4.0) CFPropertyList (>= 2.3.3, < 4.0)
atomos (~> 0.1.3) atomos (~> 0.1.3)
claide (>= 1.0.2, < 2.0) claide (>= 1.0.2, < 2.0)
colored2 (~> 3.1) colored2 (~> 3.1)
nanaimo (~> 0.3.0) nanaimo (~> 0.3.0)
rexml (~> 3.2.4) rexml (~> 3.2.4)
zeitwerk (2.5.4)
PLATFORMS PLATFORMS
ruby ruby
@@ -94,7 +92,7 @@ DEPENDENCIES
cocoapods (~> 1.11, >= 1.11.2) cocoapods (~> 1.11, >= 1.11.2)
RUBY VERSION RUBY VERSION
ruby 2.7.4p191 ruby 3.1.1p18
BUNDLED WITH BUNDLED WITH
2.2.27 2.1.4

View File

@@ -0,0 +1,66 @@
# react-native-android-detox
[![e2e-android](https://github.com/remarkablemark/react-native-android-detox/actions/workflows/e2e-android.yml/badge.svg)](https://github.com/remarkablemark/react-native-android-detox/actions/workflows/e2e-android.yml)
React Native Android Detox. The project has already been patched with the [additional Android configuration](https://wix.github.io/Detox/docs/introduction/project-setup/).
## Prerequisites
Follow the [environment setup](https://wix.github.io/Detox/docs/introduction/getting-started).
## Install
Clone the repository:
```sh
git clone https://github.com/remarkablemark/react-native-android-detox.git
cd react-native-android-detox
```
Install the dependencies:
```sh
yarn
```
## Build
### Android (Debug)
Build the Android debug app:
```sh
yarn detox build --configuration android.emu.debug
```
### Android (Release)
Build the Android release app:
```sh
yarn detox build --configuration android.emu.release
```
## Test
### Android (Debug)
Start the app:
```sh
yarn start
```
Run the test:
```sh
yarn detox test --configuration android.emu.debug
```
### Android (Release)
Run the test:
```sh
yarn detox test --configuration android.emu.release
```

View File

@@ -35,12 +35,12 @@ android_library(
android_build_config( android_build_config(
name = "build_config", name = "build_config",
package = "com.testhotupdate", package = "com.awesomeproject",
) )
android_resource( android_resource(
name = "res", name = "res",
package = "com.testhotupdate", package = "com.awesomeproject",
res = "src/main/res", res = "src/main/res",
) )

View File

@@ -1,7 +1,9 @@
apply plugin: "com.android.application" plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
}
import com.android.build.OutputFile import com.android.build.OutputFile
import org.apache.tools.ant.taskdefs.condition.Os
/** /**
* The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets * The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets
@@ -135,11 +137,13 @@ android {
compileSdkVersion rootProject.ext.compileSdkVersion compileSdkVersion rootProject.ext.compileSdkVersion
defaultConfig { defaultConfig {
applicationId "com.testhotupdate" applicationId "com.awesomeproject"
minSdkVersion rootProject.ext.minSdkVersion minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 1 versionCode 1
versionName "1.0" versionName "1.0"
testBuildType System.getProperty('testBuildType', 'debug')
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString() buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
if (isNewArchitectureEnabled()) { if (isNewArchitectureEnabled()) {
@@ -152,16 +156,13 @@ android {
"GENERATED_SRC_DIR=$buildDir/generated/source", "GENERATED_SRC_DIR=$buildDir/generated/source",
"PROJECT_BUILD_DIR=$buildDir", "PROJECT_BUILD_DIR=$buildDir",
"REACT_ANDROID_DIR=$rootDir/../node_modules/react-native/ReactAndroid", "REACT_ANDROID_DIR=$rootDir/../node_modules/react-native/ReactAndroid",
"REACT_ANDROID_BUILD_DIR=$rootDir/../node_modules/react-native/ReactAndroid/build" "REACT_ANDROID_BUILD_DIR=$rootDir/../node_modules/react-native/ReactAndroid/build",
"NODE_MODULES_DIR=$rootDir/../node_modules"
cFlags "-Wall", "-Werror", "-fexceptions", "-frtti", "-DWITH_INSPECTOR=1" cFlags "-Wall", "-Werror", "-fexceptions", "-frtti", "-DWITH_INSPECTOR=1"
cppFlags "-std=c++17" cppFlags "-std=c++17"
// Make sure this target name is the same you specify inside the // Make sure this target name is the same you specify inside the
// src/main/jni/Android.mk file for the `LOCAL_MODULE` variable. // src/main/jni/Android.mk file for the `LOCAL_MODULE` variable.
targets "testhotupdate_appmodules" targets "awesomeproject_appmodules"
// Fix for windows limit on number of character in file paths and in command lines
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
arguments "NDK_APP_SHORT_COMMANDS=true"
}
} }
} }
if (!enableSeparateBuildPerCPUArchitecture) { if (!enableSeparateBuildPerCPUArchitecture) {
@@ -239,6 +240,7 @@ android {
signingConfig signingConfigs.debug signingConfig signingConfigs.debug
minifyEnabled enableProguardInReleaseBuilds minifyEnabled enableProguardInReleaseBuilds
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
proguardFile "${rootProject.projectDir}/../node_modules/detox/android/detox/proguard-rules-app.pro"
} }
} }
@@ -260,6 +262,8 @@ android {
} }
dependencies { dependencies {
androidTestImplementation('com.wix:detox:+')
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation fileTree(dir: "libs", include: ["*.jar"]) implementation fileTree(dir: "libs", include: ["*.jar"])
//noinspection GradleDynamicVersion //noinspection GradleDynamicVersion
@@ -281,9 +285,10 @@ dependencies {
} }
if (enableHermes) { if (enableHermes) {
def hermesPath = "../../node_modules/hermes-engine/android/"; //noinspection GradleDynamicVersion
debugImplementation files(hermesPath + "hermes-debug.aar") implementation("com.facebook.react:hermes-engine:+") { // From node_modules
releaseImplementation files(hermesPath + "hermes-release.aar") exclude group:'com.facebook.fbjni'
}
} else { } else {
implementation jscFlavor implementation jscFlavor
} }
@@ -296,7 +301,11 @@ if (isNewArchitectureEnabled()) {
configurations.all { configurations.all {
resolutionStrategy.dependencySubstitution { resolutionStrategy.dependencySubstitution {
substitute(module("com.facebook.react:react-native")) substitute(module("com.facebook.react:react-native"))
.using(project(":ReactAndroid")).because("On New Architecture we're building React Native from source") .using(project(":ReactAndroid"))
.because("On New Architecture we're building React Native from source")
substitute(module("com.facebook.react:hermes-engine"))
.using(project(":ReactAndroid:hermes-engine"))
.because("On New Architecture we're building Hermes from source")
} }
} }
} }

View File

@@ -0,0 +1,29 @@
package com.awesomeproject;
import com.wix.detox.Detox;
import com.wix.detox.config.DetoxConfig;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.LargeTest;
import androidx.test.rule.ActivityTestRule;
@RunWith(AndroidJUnit4.class)
@LargeTest
public class DetoxTest {
@Rule
public ActivityTestRule<MainActivity> mActivityRule = new ActivityTestRule<>(MainActivity.class, false, false);
@Test
public void runDetoxTests() {
DetoxConfig detoxConfig = new DetoxConfig();
detoxConfig.idlePolicyConfig.masterTimeoutSec = 90;
detoxConfig.idlePolicyConfig.idleResourceTimeoutSec = 60;
detoxConfig.rnContextLoadTimeoutSec = (BuildConfig.DEBUG ? 180 : 60);
Detox.runTests(mActivityRule, detoxConfig);
}
}

View File

@@ -4,7 +4,7 @@
* <p>This source code is licensed under the MIT license found in the LICENSE file in the root * <p>This source code is licensed under the MIT license found in the LICENSE file in the root
* directory of this source tree. * directory of this source tree.
*/ */
package com.testhotupdate; package com.awesomeproject;
import android.content.Context; import android.content.Context;
import com.facebook.flipper.android.AndroidFlipperClient; import com.facebook.flipper.android.AndroidFlipperClient;

View File

@@ -1,5 +1,5 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.testhotupdate"> package="com.awesomeproject">
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
@@ -9,7 +9,8 @@
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round" android:roundIcon="@mipmap/ic_launcher_round"
android:allowBackup="false" android:allowBackup="false"
android:theme="@style/AppTheme"> android:theme="@style/AppTheme"
android:networkSecurityConfig="@xml/network_security_config">
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
android:label="@string/app_name" android:label="@string/app_name"

View File

@@ -1,4 +1,4 @@
package com.testhotupdate; package com.awesomeproject;
import com.facebook.react.ReactActivity; import com.facebook.react.ReactActivity;
import com.facebook.react.ReactActivityDelegate; import com.facebook.react.ReactActivityDelegate;
@@ -12,12 +12,13 @@ public class MainActivity extends ReactActivity {
*/ */
@Override @Override
protected String getMainComponentName() { protected String getMainComponentName() {
return "testHotupdate"; return "AwesomeProject";
} }
/** /**
* Returns the instance of the {@link ReactActivityDelegate}. There the RootView is created and * Returns the instance of the {@link ReactActivityDelegate}. There the RootView is created and
* you can specify the rendered you wish to use (Fabric or the older renderer). * you can specify the renderer you wish to use - the new renderer (Fabric) or the old renderer
* (Paper).
*/ */
@Override @Override
protected ReactActivityDelegate createReactActivityDelegate() { protected ReactActivityDelegate createReactActivityDelegate() {
@@ -36,5 +37,12 @@ public class MainActivity extends ReactActivity {
reactRootView.setIsFabric(BuildConfig.IS_NEW_ARCHITECTURE_ENABLED); reactRootView.setIsFabric(BuildConfig.IS_NEW_ARCHITECTURE_ENABLED);
return reactRootView; return reactRootView;
} }
@Override
protected boolean isConcurrentRootEnabled() {
// If you opted-in for the New Architecture, we enable Concurrent Root (i.e. React 18).
// More on this on https://reactjs.org/blog/2022/03/29/react-v18.html
return BuildConfig.IS_NEW_ARCHITECTURE_ENABLED;
}
} }
} }

View File

@@ -1,46 +1,54 @@
package com.testhotupdate; package com.awesomeproject;
import android.app.Application; import android.app.Application;
import android.content.Context; import android.content.Context;
import androidx.annotation.Nullable;
import com.facebook.react.PackageList; import com.facebook.react.PackageList;
import com.facebook.react.ReactApplication; import com.facebook.react.ReactApplication;
import com.facebook.react.ReactInstanceManager; import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactNativeHost; import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage; import com.facebook.react.ReactPackage;
import com.facebook.react.config.ReactFeatureFlags; import com.facebook.react.config.ReactFeatureFlags;
import com.facebook.react.shell.MainReactPackage;
import com.facebook.soloader.SoLoader; import com.facebook.soloader.SoLoader;
import com.testhotupdate.newarchitecture.MainApplicationReactNativeHost; import com.awesomeproject.newarchitecture.MainApplicationReactNativeHost;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.List; import java.util.List;
import cn.reactnative.modules.update.UpdateContext;
import cn.reactnative.modules.update.UpdatePackage;
public class MainApplication extends Application implements ReactApplication { public class MainApplication extends Application implements ReactApplication {
private final ReactNativeHost mReactNativeHost = private final ReactNativeHost mReactNativeHost =
new ReactNativeHost(this) { new ReactNativeHost(this) {
@Override @Override
protected String getJSBundleFile() { public boolean getUseDeveloperSupport() {
return UpdateContext.getBundleUrl(MainApplication.this); return BuildConfig.DEBUG;
} }
@Override @Nullable
public boolean getUseDeveloperSupport() { @Override
return BuildConfig.DEBUG; protected String getJSBundleFile() {
} return UpdateContext.getBundleUrl(MainApplication.this);
}
@Override @Override
protected List<ReactPackage> getPackages() { protected List<ReactPackage> getPackages() {
@SuppressWarnings("UnnecessaryLocalVariable") @SuppressWarnings("UnnecessaryLocalVariable")
List<ReactPackage> packages = new PackageList(this).getPackages(); List<ReactPackage> packages = new PackageList(this).getPackages();
// Packages that cannot be autolinked yet can be added manually here, for example: // Packages that cannot be autolinked yet can be added manually here, for example:
// packages.add(new MyReactNativePackage()); // packages.add(new MyReactNativePackage());
return packages; return packages;
} }
@Override @Override
protected String getJSMainModuleName() { protected String getJSMainModuleName() {
return "index"; return "index";
} }
}; };
private final ReactNativeHost mNewArchitectureNativeHost = private final ReactNativeHost mNewArchitectureNativeHost =
new MainApplicationReactNativeHost(this); new MainApplicationReactNativeHost(this);
@@ -78,7 +86,7 @@ public class MainApplication extends Application implements ReactApplication {
We use reflection here to pick up the class that initializes Flipper, We use reflection here to pick up the class that initializes Flipper,
since Flipper library is not available in release mode since Flipper library is not available in release mode
*/ */
Class<?> aClass = Class.forName("com.testhotupdate.ReactNativeFlipper"); Class<?> aClass = Class.forName("com.awesomeproject.ReactNativeFlipper");
aClass aClass
.getMethod("initializeFlipper", Context.class, ReactInstanceManager.class) .getMethod("initializeFlipper", Context.class, ReactInstanceManager.class)
.invoke(null, context, reactInstanceManager); .invoke(null, context, reactInstanceManager);

View File

@@ -1,4 +1,4 @@
package com.testhotupdate.newarchitecture; package com.awesomeproject.newarchitecture;
import android.app.Application; import android.app.Application;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
@@ -16,12 +16,12 @@ import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.UIManager; import com.facebook.react.bridge.UIManager;
import com.facebook.react.fabric.ComponentFactory; import com.facebook.react.fabric.ComponentFactory;
import com.facebook.react.fabric.CoreComponentsRegistry; import com.facebook.react.fabric.CoreComponentsRegistry;
import com.facebook.react.fabric.EmptyReactNativeConfig;
import com.facebook.react.fabric.FabricJSIModuleProvider; import com.facebook.react.fabric.FabricJSIModuleProvider;
import com.facebook.react.fabric.ReactNativeConfig;
import com.facebook.react.uimanager.ViewManagerRegistry; import com.facebook.react.uimanager.ViewManagerRegistry;
import com.testhotupdate.BuildConfig; import com.awesomeproject.BuildConfig;
import com.testhotupdate.newarchitecture.components.MainComponentsRegistry; import com.awesomeproject.newarchitecture.components.MainComponentsRegistry;
import com.testhotupdate.newarchitecture.modules.MainApplicationTurboModuleManagerDelegate; import com.awesomeproject.newarchitecture.modules.MainApplicationTurboModuleManagerDelegate;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@@ -105,7 +105,7 @@ public class MainApplicationReactNativeHost extends ReactNativeHost {
return new FabricJSIModuleProvider( return new FabricJSIModuleProvider(
reactApplicationContext, reactApplicationContext,
componentFactory, componentFactory,
new EmptyReactNativeConfig(), ReactNativeConfig.DEFAULT_CONFIG,
viewManagerRegistry); viewManagerRegistry);
} }
}); });

View File

@@ -1,4 +1,4 @@
package com.testhotupdate.newarchitecture.components; package com.awesomeproject.newarchitecture.components;
import com.facebook.jni.HybridData; import com.facebook.jni.HybridData;
import com.facebook.proguard.annotations.DoNotStrip; import com.facebook.proguard.annotations.DoNotStrip;

View File

@@ -1,4 +1,4 @@
package com.testhotupdate.newarchitecture.modules; package com.awesomeproject.newarchitecture.modules;
import com.facebook.jni.HybridData; import com.facebook.jni.HybridData;
import com.facebook.react.ReactPackage; import com.facebook.react.ReactPackage;
@@ -41,7 +41,7 @@ public class MainApplicationTurboModuleManagerDelegate
if (!sIsSoLibraryLoaded) { if (!sIsSoLibraryLoaded) {
// If you change the name of your application .so file in the Android.mk file, // If you change the name of your application .so file in the Android.mk file,
// make sure you update the name here as well. // make sure you update the name here as well.
SoLoader.loadLibrary("testhotupdate_appmodules"); SoLoader.loadLibrary("awesomeproject_appmodules");
sIsSoLibraryLoaded = true; sIsSoLibraryLoaded = true;
} }
} }

View File

@@ -10,7 +10,7 @@ include $(CLEAR_VARS)
LOCAL_PATH := $(THIS_DIR) LOCAL_PATH := $(THIS_DIR)
# You can customize the name of your application .so file here. # You can customize the name of your application .so file here.
LOCAL_MODULE := testhotupdate_appmodules LOCAL_MODULE := awesomeproject_appmodules
LOCAL_C_INCLUDES := $(LOCAL_PATH) LOCAL_C_INCLUDES := $(LOCAL_PATH)
LOCAL_SRC_FILES := $(wildcard $(LOCAL_PATH)/*.cpp) LOCAL_SRC_FILES := $(wildcard $(LOCAL_PATH)/*.cpp)
@@ -28,8 +28,7 @@ LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)
LOCAL_SHARED_LIBRARIES := \ LOCAL_SHARED_LIBRARIES := \
libfabricjni \ libfabricjni \
libfbjni \ libfbjni \
libfolly_futures \ libfolly_runtime \
libfolly_json \
libglog \ libglog \
libjsi \ libjsi \
libreact_codegen_rncore \ libreact_codegen_rncore \

View File

@@ -14,7 +14,7 @@ class MainApplicationTurboModuleManagerDelegate
public: public:
// Adapt it to the package you used for your Java class. // Adapt it to the package you used for your Java class.
static constexpr auto kJavaDescriptor = static constexpr auto kJavaDescriptor =
"Lcom/testhotupdate/newarchitecture/modules/MainApplicationTurboModuleManagerDelegate;"; "Lcom/awesomeproject/newarchitecture/modules/MainApplicationTurboModuleManagerDelegate;";
static jni::local_ref<jhybriddata> initHybrid(jni::alias_ref<jhybridobject>); static jni::local_ref<jhybriddata> initHybrid(jni::alias_ref<jhybridobject>);

View File

@@ -13,7 +13,7 @@ class MainComponentsRegistry
public: public:
// Adapt it to the package you used for your Java class. // Adapt it to the package you used for your Java class.
constexpr static auto kJavaDescriptor = constexpr static auto kJavaDescriptor =
"Lcom/testhotupdate/newarchitecture/components/MainComponentsRegistry;"; "Lcom/awesomeproject/newarchitecture/components/MainComponentsRegistry;";
static void registerNatives(); static void registerNatives();

View File

@@ -1,3 +1,3 @@
<resources> <resources>
<string name="app_name">testHotupdate</string> <string name="app_name">AwesomeProject</string>
</resources> </resources>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="true">10.0.2.2</domain>
<domain includeSubdomains="true">localhost</domain>
<domain includeSubdomains="true">cos.pgyer.com</domain>
</domain-config>
</network-security-config>

View File

@@ -8,6 +8,7 @@ buildscript {
minSdkVersion = 21 minSdkVersion = 21
compileSdkVersion = 31 compileSdkVersion = 31
targetSdkVersion = 31 targetSdkVersion = 31
kotlinVersion = '1.6.10'
if (System.properties['os.arch'] == "aarch64") { if (System.properties['os.arch'] == "aarch64") {
// For M1 Users we need to use the NDK 24 which added support for aarch64 // For M1 Users we need to use the NDK 24 which added support for aarch64
@@ -22,11 +23,12 @@ buildscript {
mavenCentral() mavenCentral()
} }
dependencies { dependencies {
classpath("com.android.tools.build:gradle:7.0.4") classpath("com.android.tools.build:gradle:7.1.1")
classpath("com.facebook.react:react-native-gradle-plugin") classpath("com.facebook.react:react-native-gradle-plugin")
classpath("de.undercouch:gradle-download-task:4.1.2") classpath("de.undercouch:gradle-download-task:5.0.1")
// NOTE: Do not place your application dependencies here; they belong // NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files // in the individual module build.gradle files
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion")
} }
} }
@@ -48,6 +50,9 @@ allprojects {
} }
} }
google() google()
maven {
url("$rootDir/../node_modules/detox/Detox-android")
}
maven { url 'https://www.jitpack.io' } maven { url 'https://www.jitpack.io' }
} }
} }

View File

@@ -1,4 +1,4 @@
rootProject.name = 'testHotupdate' rootProject.name = 'AwesomeProject'
apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings) apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings)
include ':app' include ':app'
includeBuild('../node_modules/react-native-gradle-plugin') includeBuild('../node_modules/react-native-gradle-plugin')
@@ -6,4 +6,6 @@ includeBuild('../node_modules/react-native-gradle-plugin')
if (settings.hasProperty("newArchEnabled") && settings.newArchEnabled == "true") { if (settings.hasProperty("newArchEnabled") && settings.newArchEnabled == "true") {
include(":ReactAndroid") include(":ReactAndroid")
project(":ReactAndroid").projectDir = file('../node_modules/react-native/ReactAndroid') project(":ReactAndroid").projectDir = file('../node_modules/react-native/ReactAndroid')
include(":ReactAndroid:hermes-engine")
project(":ReactAndroid:hermes-engine").projectDir = file('../node_modules/react-native/ReactAndroid/hermes-engine')
} }

View File

@@ -1,4 +1,4 @@
{ {
"name": "testHotupdate", "name": "AwesomeProject",
"displayName": "testHotupdate" "displayName": "AwesomeProject"
} }

View File

@@ -0,0 +1,123 @@
import {by, device, element, expect, waitFor} from 'detox';
describe('测试Native模块的方法', () => {
beforeAll(async () => {
await device.launchApp();
});
it('setLocalHashInfo', async () => {
await element(by.id('testcase')).longPress();
await element(by.id('setLocalHashInfo')).longPress();
await element(by.id('submit')).longPress();
await expect(element(by.id('done'))).toBeVisible();
await element(by.id('done')).longPress();
await expect(element(by.id('done'))).toBeNotVisible();
});
it('getLocalHashInfo', async () => {
await element(by.id('getLocalHashInfo')).longPress();
await element(by.id('submit')).longPress();
await expect(element(by.text('done'))).toBeVisible();
await element(by.id('done')).longPress();
await expect(element(by.id('done'))).toBeNotVisible();
});
it('setUuid', async () => {
await element(by.id('setUuid')).longPress();
await element(by.id('submit')).longPress();
await expect(element(by.text('done'))).toBeVisible();
await element(by.id('done')).longPress();
await expect(element(by.id('done'))).toBeNotVisible();
});
it('setBlockUpdate', async () => {
await element(by.id('setBlockUpdate')).longPress();
await element(by.id('submit')).longPress();
await expect(element(by.text('done'))).toBeVisible();
await element(by.id('done')).longPress();
await expect(element(by.id('done'))).toBeNotVisible();
});
if (device.getPlatform() === 'android') {
it('reloadUpdate', async () => {
await element(by.id('reloadUpdate')).longPress();
await element(by.id('submit')).longPress();
await waitFor(element(by.text('确认')))
.toBeVisible()
.withTimeout(10000);
await element(by.id('done')).longPress();
await expect(element(by.id('done'))).toBeNotVisible();
});
}
it('setNeedUpdate', async () => {
await element(by.id('setNeedUpdate')).longPress();
await element(by.id('submit')).longPress();
await expect(element(by.text('done'))).toBeVisible();
await element(by.id('done')).longPress();
await expect(element(by.id('done'))).toBeNotVisible();
});
if (device.getPlatform() === 'android') {
it('markSuccess', async () => {
await element(by.id('markSuccess')).longPress();
await element(by.id('submit')).longPress();
await waitFor(element(by.text('确认')))
.toBeVisible()
.withTimeout(10000);
await element(by.id('done')).longPress();
});
}
it('downloadPatchFromPpk', async () => {
await element(by.id('downloadPatchFromPpk')).longPress();
await element(by.id('submit')).longPress();
if (device.getPlatform() === 'ios') {
await expect(element(by.text('failed to open zip file'))).toBeVisible();
} else {
await waitFor(element(by.text('确认')))
.toBeVisible()
.withTimeout(10000);
}
await element(by.id('done')).longPress();
await expect(element(by.id('done'))).toBeNotVisible();
});
it('downloadPatchFromPackage', async () => {
await element(by.id('downloadPatchFromPackage')).longPress();
await element(by.id('submit')).longPress();
if (device.getPlatform() === 'ios') {
await expect(element(by.text('failed to open zip file'))).toBeVisible();
} else {
await waitFor(element(by.text('确认')))
.toBeVisible()
.withTimeout(10000);
}
await element(by.id('done')).longPress();
await expect(element(by.id('done'))).toBeNotVisible();
});
it('downloadFullUpdate', async () => {
await element(by.id('downloadFullUpdate')).longPress();
await element(by.id('submit')).longPress();
if (device.getPlatform() === 'ios') {
await expect(element(by.text('failed to open zip file'))).toBeVisible();
} else {
await waitFor(element(by.text('确认')))
.toBeVisible()
.withTimeout(10000);
}
await element(by.id('done')).longPress();
await expect(element(by.id('done'))).toBeNotVisible();
});
if (device.getPlatform() === 'android') {
it('downloadAndInstallApk', async () => {
await element(by.id('downloadAndInstallApk')).longPress();
await element(by.id('submit')).longPress();
await waitFor(element(by.text('确认')))
.toBeVisible()
.withTimeout(10000);
await element(by.id('done')).longPress();
await expect(element(by.id('done'))).toBeNotVisible();
});
}
});

View File

@@ -0,0 +1,15 @@
/** @type {import('@jest/types').Config.InitialOptions} */
module.exports = {
rootDir: '..',
testMatch: ['<rootDir>/e2e/**/*.test.ts'],
testTimeout: 240000,
maxWorkers: 2,
transform: {
'\\.tsx?$': 'ts-jest',
},
globalSetup: 'detox/runners/jest/globalSetup',
globalTeardown: 'detox/runners/jest/globalTeardown',
reporters: ['detox/runners/jest/reporter'],
testEnvironment: 'detox/runners/jest/testEnvironment',
verbose: true,
};

View File

@@ -0,0 +1,11 @@
# This `.xcode.env` file is versioned and is used to source the environment
# used when running script phases inside Xcode.
# To customize your local environment, you can create an `.xcode.env.local`
# file that is not versioned.
# NODE_BINARY variable contains the PATH to the node executable.
#
# Customize the NODE_BINARY variable here.
# For example, to use nvm with brew, add the following line
# . "$(brew --prefix nvm)/nvm.sh" --no-use
export NODE_BINARY=$(command -v node)

View File

@@ -7,11 +7,12 @@
objects = { objects = {
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
00E356F31AD99517003FC87E /* testHotupdateTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* testHotupdateTests.m */; }; 00E356F31AD99517003FC87E /* AwesomeProjectTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* AwesomeProjectTests.m */; };
0C80B921A6F3F58F76C31292 /* libPods-testHotupdate.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5DCACB8F33CDC322A6C60F78 /* libPods-testHotupdate.a */; }; 0C80B921A6F3F58F76C31292 /* libPods-AwesomeProject.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5DCACB8F33CDC322A6C60F78 /* libPods-AwesomeProject.a */; };
13B07FBC1A68108700A75B9A /* AppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.mm */; }; 13B07FBC1A68108700A75B9A /* AppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.mm */; };
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; }; 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; }; 13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
7699B88040F8A987B510C191 /* libPods-AwesomeProject-AwesomeProjectTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 19F6CBCC0A4E27FBF8BF4A61 /* libPods-AwesomeProject-AwesomeProjectTests.a */; };
81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */; }; 81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
@@ -21,24 +22,27 @@
containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */; containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */;
proxyType = 1; proxyType = 1;
remoteGlobalIDString = 13B07F861A680F5B00A75B9A; remoteGlobalIDString = 13B07F861A680F5B00A75B9A;
remoteInfo = testHotupdate; remoteInfo = AwesomeProject;
}; };
/* End PBXContainerItemProxy section */ /* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
00E356EE1AD99517003FC87E /* testHotupdateTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = testHotupdateTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 00E356EE1AD99517003FC87E /* AwesomeProjectTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = AwesomeProjectTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; 00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
00E356F21AD99517003FC87E /* testHotupdateTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = testHotupdateTests.m; sourceTree = "<group>"; }; 00E356F21AD99517003FC87E /* AwesomeProjectTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AwesomeProjectTests.m; sourceTree = "<group>"; };
13B07F961A680F5B00A75B9A /* testHotupdate.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = testHotupdate.app; sourceTree = BUILT_PRODUCTS_DIR; }; 13B07F961A680F5B00A75B9A /* AwesomeProject.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AwesomeProject.app; sourceTree = BUILT_PRODUCTS_DIR; };
13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = testHotupdate/AppDelegate.h; sourceTree = "<group>"; }; 13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = AwesomeProject/AppDelegate.h; sourceTree = "<group>"; };
13B07FB01A68108700A75B9A /* AppDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = AppDelegate.mm; path = testHotupdate/AppDelegate.mm; sourceTree = "<group>"; }; 13B07FB01A68108700A75B9A /* AppDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = AppDelegate.mm; path = AwesomeProject/AppDelegate.mm; sourceTree = "<group>"; };
13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = testHotupdate/Images.xcassets; sourceTree = "<group>"; }; 13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = AwesomeProject/Images.xcassets; sourceTree = "<group>"; };
13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = testHotupdate/Info.plist; sourceTree = "<group>"; }; 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = AwesomeProject/Info.plist; sourceTree = "<group>"; };
13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = testHotupdate/main.m; sourceTree = "<group>"; }; 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = AwesomeProject/main.m; sourceTree = "<group>"; };
3B4392A12AC88292D35C810B /* Pods-testHotupdate.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-testHotupdate.debug.xcconfig"; path = "Target Support Files/Pods-testHotupdate/Pods-testHotupdate.debug.xcconfig"; sourceTree = "<group>"; }; 19F6CBCC0A4E27FBF8BF4A61 /* libPods-AwesomeProject-AwesomeProjectTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-AwesomeProject-AwesomeProjectTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
5709B34CF0A7D63546082F79 /* Pods-testHotupdate.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-testHotupdate.release.xcconfig"; path = "Target Support Files/Pods-testHotupdate/Pods-testHotupdate.release.xcconfig"; sourceTree = "<group>"; }; 3B4392A12AC88292D35C810B /* Pods-AwesomeProject.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AwesomeProject.debug.xcconfig"; path = "Target Support Files/Pods-AwesomeProject/Pods-AwesomeProject.debug.xcconfig"; sourceTree = "<group>"; };
5DCACB8F33CDC322A6C60F78 /* libPods-testHotupdate.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-testHotupdate.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 5709B34CF0A7D63546082F79 /* Pods-AwesomeProject.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AwesomeProject.release.xcconfig"; path = "Target Support Files/Pods-AwesomeProject/Pods-AwesomeProject.release.xcconfig"; sourceTree = "<group>"; };
81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = testHotupdate/LaunchScreen.storyboard; sourceTree = "<group>"; }; 5B7EB9410499542E8C5724F5 /* Pods-AwesomeProject-AwesomeProjectTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AwesomeProject-AwesomeProjectTests.debug.xcconfig"; path = "Target Support Files/Pods-AwesomeProject-AwesomeProjectTests/Pods-AwesomeProject-AwesomeProjectTests.debug.xcconfig"; sourceTree = "<group>"; };
5DCACB8F33CDC322A6C60F78 /* libPods-AwesomeProject.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-AwesomeProject.a"; sourceTree = BUILT_PRODUCTS_DIR; };
81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = AwesomeProject/LaunchScreen.storyboard; sourceTree = "<group>"; };
89C6BE57DB24E9ADA2F236DE /* Pods-AwesomeProject-AwesomeProjectTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AwesomeProject-AwesomeProjectTests.release.xcconfig"; path = "Target Support Files/Pods-AwesomeProject-AwesomeProjectTests/Pods-AwesomeProject-AwesomeProjectTests.release.xcconfig"; sourceTree = "<group>"; };
ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; }; ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
/* End PBXFileReference section */ /* End PBXFileReference section */
@@ -47,6 +51,7 @@
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
7699B88040F8A987B510C191 /* libPods-AwesomeProject-AwesomeProjectTests.a in Frameworks */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@@ -54,20 +59,20 @@
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
0C80B921A6F3F58F76C31292 /* libPods-testHotupdate.a in Frameworks */, 0C80B921A6F3F58F76C31292 /* libPods-AwesomeProject.a in Frameworks */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
/* End PBXFrameworksBuildPhase section */ /* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */ /* Begin PBXGroup section */
00E356EF1AD99517003FC87E /* testHotupdateTests */ = { 00E356EF1AD99517003FC87E /* AwesomeProjectTests */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
00E356F21AD99517003FC87E /* testHotupdateTests.m */, 00E356F21AD99517003FC87E /* AwesomeProjectTests.m */,
00E356F01AD99517003FC87E /* Supporting Files */, 00E356F01AD99517003FC87E /* Supporting Files */,
); );
path = testHotupdateTests; path = AwesomeProjectTests;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
00E356F01AD99517003FC87E /* Supporting Files */ = { 00E356F01AD99517003FC87E /* Supporting Files */ = {
@@ -78,7 +83,7 @@
name = "Supporting Files"; name = "Supporting Files";
sourceTree = "<group>"; sourceTree = "<group>";
}; };
13B07FAE1A68108700A75B9A /* testHotupdate */ = { 13B07FAE1A68108700A75B9A /* AwesomeProject */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
13B07FAF1A68108700A75B9A /* AppDelegate.h */, 13B07FAF1A68108700A75B9A /* AppDelegate.h */,
@@ -88,14 +93,15 @@
81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */, 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */,
13B07FB71A68108700A75B9A /* main.m */, 13B07FB71A68108700A75B9A /* main.m */,
); );
name = testHotupdate; name = AwesomeProject;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
2D16E6871FA4F8E400B85C8A /* Frameworks */ = { 2D16E6871FA4F8E400B85C8A /* Frameworks */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
ED297162215061F000B7C4FE /* JavaScriptCore.framework */, ED297162215061F000B7C4FE /* JavaScriptCore.framework */,
5DCACB8F33CDC322A6C60F78 /* libPods-testHotupdate.a */, 5DCACB8F33CDC322A6C60F78 /* libPods-AwesomeProject.a */,
19F6CBCC0A4E27FBF8BF4A61 /* libPods-AwesomeProject-AwesomeProjectTests.a */,
); );
name = Frameworks; name = Frameworks;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -110,9 +116,9 @@
83CBB9F61A601CBA00E9B192 = { 83CBB9F61A601CBA00E9B192 = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
13B07FAE1A68108700A75B9A /* testHotupdate */, 13B07FAE1A68108700A75B9A /* AwesomeProject */,
832341AE1AAA6A7D00B99B32 /* Libraries */, 832341AE1AAA6A7D00B99B32 /* Libraries */,
00E356EF1AD99517003FC87E /* testHotupdateTests */, 00E356EF1AD99517003FC87E /* AwesomeProjectTests */,
83CBBA001A601CBA00E9B192 /* Products */, 83CBBA001A601CBA00E9B192 /* Products */,
2D16E6871FA4F8E400B85C8A /* Frameworks */, 2D16E6871FA4F8E400B85C8A /* Frameworks */,
BBD78D7AC51CEA395F1C20DB /* Pods */, BBD78D7AC51CEA395F1C20DB /* Pods */,
@@ -125,8 +131,8 @@
83CBBA001A601CBA00E9B192 /* Products */ = { 83CBBA001A601CBA00E9B192 /* Products */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
13B07F961A680F5B00A75B9A /* testHotupdate.app */, 13B07F961A680F5B00A75B9A /* AwesomeProject.app */,
00E356EE1AD99517003FC87E /* testHotupdateTests.xctest */, 00E356EE1AD99517003FC87E /* AwesomeProjectTests.xctest */,
); );
name = Products; name = Products;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -134,8 +140,10 @@
BBD78D7AC51CEA395F1C20DB /* Pods */ = { BBD78D7AC51CEA395F1C20DB /* Pods */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
3B4392A12AC88292D35C810B /* Pods-testHotupdate.debug.xcconfig */, 3B4392A12AC88292D35C810B /* Pods-AwesomeProject.debug.xcconfig */,
5709B34CF0A7D63546082F79 /* Pods-testHotupdate.release.xcconfig */, 5709B34CF0A7D63546082F79 /* Pods-AwesomeProject.release.xcconfig */,
5B7EB9410499542E8C5724F5 /* Pods-AwesomeProject-AwesomeProjectTests.debug.xcconfig */,
89C6BE57DB24E9ADA2F236DE /* Pods-AwesomeProject-AwesomeProjectTests.release.xcconfig */,
); );
path = Pods; path = Pods;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -143,27 +151,30 @@
/* End PBXGroup section */ /* End PBXGroup section */
/* Begin PBXNativeTarget section */ /* Begin PBXNativeTarget section */
00E356ED1AD99517003FC87E /* testHotupdateTests */ = { 00E356ED1AD99517003FC87E /* AwesomeProjectTests */ = {
isa = PBXNativeTarget; isa = PBXNativeTarget;
buildConfigurationList = 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "testHotupdateTests" */; buildConfigurationList = 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "AwesomeProjectTests" */;
buildPhases = ( buildPhases = (
A55EABD7B0C7F3A422A6CC61 /* [CP] Check Pods Manifest.lock */,
00E356EA1AD99517003FC87E /* Sources */, 00E356EA1AD99517003FC87E /* Sources */,
00E356EB1AD99517003FC87E /* Frameworks */, 00E356EB1AD99517003FC87E /* Frameworks */,
00E356EC1AD99517003FC87E /* Resources */, 00E356EC1AD99517003FC87E /* Resources */,
C59DA0FBD6956966B86A3779 /* [CP] Embed Pods Frameworks */,
F6A41C54EA430FDDC6A6ED99 /* [CP] Copy Pods Resources */,
); );
buildRules = ( buildRules = (
); );
dependencies = ( dependencies = (
00E356F51AD99517003FC87E /* PBXTargetDependency */, 00E356F51AD99517003FC87E /* PBXTargetDependency */,
); );
name = testHotupdateTests; name = AwesomeProjectTests;
productName = testHotupdateTests; productName = AwesomeProjectTests;
productReference = 00E356EE1AD99517003FC87E /* testHotupdateTests.xctest */; productReference = 00E356EE1AD99517003FC87E /* AwesomeProjectTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test"; productType = "com.apple.product-type.bundle.unit-test";
}; };
13B07F861A680F5B00A75B9A /* testHotupdate */ = { 13B07F861A680F5B00A75B9A /* AwesomeProject */ = {
isa = PBXNativeTarget; isa = PBXNativeTarget;
buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "testHotupdate" */; buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "AwesomeProject" */;
buildPhases = ( buildPhases = (
C38B50BA6285516D6DCD4F65 /* [CP] Check Pods Manifest.lock */, C38B50BA6285516D6DCD4F65 /* [CP] Check Pods Manifest.lock */,
FD10A7F022414F080027D42C /* Start Packager */, FD10A7F022414F080027D42C /* Start Packager */,
@@ -178,9 +189,9 @@
); );
dependencies = ( dependencies = (
); );
name = testHotupdate; name = AwesomeProject;
productName = testHotupdate; productName = AwesomeProject;
productReference = 13B07F961A680F5B00A75B9A /* testHotupdate.app */; productReference = 13B07F961A680F5B00A75B9A /* AwesomeProject.app */;
productType = "com.apple.product-type.application"; productType = "com.apple.product-type.application";
}; };
/* End PBXNativeTarget section */ /* End PBXNativeTarget section */
@@ -200,7 +211,7 @@
}; };
}; };
}; };
buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "testHotupdate" */; buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "AwesomeProject" */;
compatibilityVersion = "Xcode 12.0"; compatibilityVersion = "Xcode 12.0";
developmentRegion = en; developmentRegion = en;
hasScannedForEncodings = 0; hasScannedForEncodings = 0;
@@ -213,8 +224,8 @@
projectDirPath = ""; projectDirPath = "";
projectRoot = ""; projectRoot = "";
targets = ( targets = (
13B07F861A680F5B00A75B9A /* testHotupdate */, 13B07F861A680F5B00A75B9A /* AwesomeProject */,
00E356ED1AD99517003FC87E /* testHotupdateTests */, 00E356ED1AD99517003FC87E /* AwesomeProjectTests */,
); );
}; };
/* End PBXProject section */ /* End PBXProject section */
@@ -245,13 +256,15 @@
files = ( files = (
); );
inputPaths = ( inputPaths = (
"$(SRCROOT)/.xcode.env.local",
"$(SRCROOT)/.xcode.env",
); );
name = "Bundle React Native code and images"; name = "Bundle React Native code and images";
outputPaths = ( outputPaths = (
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh; shellPath = /bin/sh;
shellScript = "set -e\n\nexport NODE_BINARY=node\n../node_modules/react-native/scripts/react-native-xcode.sh\n"; shellScript = "set -e\n\nWITH_ENVIRONMENT=\"../node_modules/react-native/scripts/xcode/with-environment.sh\"\nREACT_NATIVE_XCODE=\"../node_modules/react-native/scripts/react-native-xcode.sh\"\n\n/bin/sh -c \"$WITH_ENVIRONMENT $REACT_NATIVE_XCODE\"\n";
}; };
00EEFC60759A1932668264C0 /* [CP] Embed Pods Frameworks */ = { 00EEFC60759A1932668264C0 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase; isa = PBXShellScriptBuildPhase;
@@ -259,15 +272,37 @@
files = ( files = (
); );
inputFileListPaths = ( inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-testHotupdate/Pods-testHotupdate-frameworks-${CONFIGURATION}-input-files.xcfilelist", "${PODS_ROOT}/Target Support Files/Pods-AwesomeProject/Pods-AwesomeProject-frameworks-${CONFIGURATION}-input-files.xcfilelist",
); );
name = "[CP] Embed Pods Frameworks"; name = "[CP] Embed Pods Frameworks";
outputFileListPaths = ( outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-testHotupdate/Pods-testHotupdate-frameworks-${CONFIGURATION}-output-files.xcfilelist", "${PODS_ROOT}/Target Support Files/Pods-AwesomeProject/Pods-AwesomeProject-frameworks-${CONFIGURATION}-output-files.xcfilelist",
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh; shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-testHotupdate/Pods-testHotupdate-frameworks.sh\"\n"; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-AwesomeProject/Pods-AwesomeProject-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
A55EABD7B0C7F3A422A6CC61 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-AwesomeProject-AwesomeProjectTests-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0; showEnvVarsInLog = 0;
}; };
C38B50BA6285516D6DCD4F65 /* [CP] Check Pods Manifest.lock */ = { C38B50BA6285516D6DCD4F65 /* [CP] Check Pods Manifest.lock */ = {
@@ -285,28 +320,62 @@
outputFileListPaths = ( outputFileListPaths = (
); );
outputPaths = ( outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-testHotupdate-checkManifestLockResult.txt", "$(DERIVED_FILE_DIR)/Pods-AwesomeProject-checkManifestLockResult.txt",
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh; shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0; showEnvVarsInLog = 0;
}; };
C59DA0FBD6956966B86A3779 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-AwesomeProject-AwesomeProjectTests/Pods-AwesomeProject-AwesomeProjectTests-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-AwesomeProject-AwesomeProjectTests/Pods-AwesomeProject-AwesomeProjectTests-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-AwesomeProject-AwesomeProjectTests/Pods-AwesomeProject-AwesomeProjectTests-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
E235C05ADACE081382539298 /* [CP] Copy Pods Resources */ = { E235C05ADACE081382539298 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase; isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
); );
inputFileListPaths = ( inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-testHotupdate/Pods-testHotupdate-resources-${CONFIGURATION}-input-files.xcfilelist", "${PODS_ROOT}/Target Support Files/Pods-AwesomeProject/Pods-AwesomeProject-resources-${CONFIGURATION}-input-files.xcfilelist",
); );
name = "[CP] Copy Pods Resources"; name = "[CP] Copy Pods Resources";
outputFileListPaths = ( outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-testHotupdate/Pods-testHotupdate-resources-${CONFIGURATION}-output-files.xcfilelist", "${PODS_ROOT}/Target Support Files/Pods-AwesomeProject/Pods-AwesomeProject-resources-${CONFIGURATION}-output-files.xcfilelist",
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh; shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-testHotupdate/Pods-testHotupdate-resources.sh\"\n"; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-AwesomeProject/Pods-AwesomeProject-resources.sh\"\n";
showEnvVarsInLog = 0;
};
F6A41C54EA430FDDC6A6ED99 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-AwesomeProject-AwesomeProjectTests/Pods-AwesomeProject-AwesomeProjectTests-resources-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Copy Pods Resources";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-AwesomeProject-AwesomeProjectTests/Pods-AwesomeProject-AwesomeProjectTests-resources-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-AwesomeProject-AwesomeProjectTests/Pods-AwesomeProject-AwesomeProjectTests-resources.sh\"\n";
showEnvVarsInLog = 0; showEnvVarsInLog = 0;
}; };
FD10A7F022414F080027D42C /* Start Packager */ = { FD10A7F022414F080027D42C /* Start Packager */ = {
@@ -335,7 +404,7 @@
isa = PBXSourcesBuildPhase; isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
00E356F31AD99517003FC87E /* testHotupdateTests.m in Sources */, 00E356F31AD99517003FC87E /* AwesomeProjectTests.m in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@@ -353,7 +422,7 @@
/* Begin PBXTargetDependency section */ /* Begin PBXTargetDependency section */
00E356F51AD99517003FC87E /* PBXTargetDependency */ = { 00E356F51AD99517003FC87E /* PBXTargetDependency */ = {
isa = PBXTargetDependency; isa = PBXTargetDependency;
target = 13B07F861A680F5B00A75B9A /* testHotupdate */; target = 13B07F861A680F5B00A75B9A /* AwesomeProject */;
targetProxy = 00E356F41AD99517003FC87E /* PBXContainerItemProxy */; targetProxy = 00E356F41AD99517003FC87E /* PBXContainerItemProxy */;
}; };
/* End PBXTargetDependency section */ /* End PBXTargetDependency section */
@@ -361,14 +430,15 @@
/* Begin XCBuildConfiguration section */ /* Begin XCBuildConfiguration section */
00E356F61AD99517003FC87E /* Debug */ = { 00E356F61AD99517003FC87E /* Debug */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
baseConfigurationReference = 5B7EB9410499542E8C5724F5 /* Pods-AwesomeProject-AwesomeProjectTests.debug.xcconfig */;
buildSettings = { buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)"; BUNDLE_LOADER = "$(TEST_HOST)";
GCC_PREPROCESSOR_DEFINITIONS = ( GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1", "DEBUG=1",
"$(inherited)", "$(inherited)",
); );
INFOPLIST_FILE = testHotupdateTests/Info.plist; INFOPLIST_FILE = AwesomeProjectTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 11.0; IPHONEOS_DEPLOYMENT_TARGET = 12.4;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
@@ -381,17 +451,18 @@
); );
PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/testHotupdate.app/testHotupdate"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/AwesomeProject.app/AwesomeProject";
}; };
name = Debug; name = Debug;
}; };
00E356F71AD99517003FC87E /* Release */ = { 00E356F71AD99517003FC87E /* Release */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
baseConfigurationReference = 89C6BE57DB24E9ADA2F236DE /* Pods-AwesomeProject-AwesomeProjectTests.release.xcconfig */;
buildSettings = { buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)"; BUNDLE_LOADER = "$(TEST_HOST)";
COPY_PHASE_STRIP = NO; COPY_PHASE_STRIP = NO;
INFOPLIST_FILE = testHotupdateTests/Info.plist; INFOPLIST_FILE = AwesomeProjectTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 11.0; IPHONEOS_DEPLOYMENT_TARGET = 12.4;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
@@ -404,19 +475,19 @@
); );
PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/testHotupdate.app/testHotupdate"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/AwesomeProject.app/AwesomeProject";
}; };
name = Release; name = Release;
}; };
13B07F941A680F5B00A75B9A /* Debug */ = { 13B07F941A680F5B00A75B9A /* Debug */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
baseConfigurationReference = 3B4392A12AC88292D35C810B /* Pods-testHotupdate.debug.xcconfig */; baseConfigurationReference = 3B4392A12AC88292D35C810B /* Pods-AwesomeProject.debug.xcconfig */;
buildSettings = { buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 1;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = testHotupdate/Info.plist; INFOPLIST_FILE = AwesomeProject/Info.plist;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
@@ -427,7 +498,7 @@
"-lc++", "-lc++",
); );
PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = testHotupdate; PRODUCT_NAME = AwesomeProject;
SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic"; VERSIONING_SYSTEM = "apple-generic";
@@ -436,12 +507,12 @@
}; };
13B07F951A680F5B00A75B9A /* Release */ = { 13B07F951A680F5B00A75B9A /* Release */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
baseConfigurationReference = 5709B34CF0A7D63546082F79 /* Pods-testHotupdate.release.xcconfig */; baseConfigurationReference = 5709B34CF0A7D63546082F79 /* Pods-AwesomeProject.release.xcconfig */;
buildSettings = { buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 1;
INFOPLIST_FILE = testHotupdate/Info.plist; INFOPLIST_FILE = AwesomeProject/Info.plist;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
@@ -452,7 +523,7 @@
"-lc++", "-lc++",
); );
PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = testHotupdate; PRODUCT_NAME = AwesomeProject;
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic"; VERSIONING_SYSTEM = "apple-generic";
}; };
@@ -507,7 +578,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 11.0; IPHONEOS_DEPLOYMENT_TARGET = 12.4;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
/usr/lib/swift, /usr/lib/swift,
"$(inherited)", "$(inherited)",
@@ -525,6 +596,7 @@
"-DFOLLY_MOBILE=1", "-DFOLLY_MOBILE=1",
"-DFOLLY_USE_LIBCPP=1", "-DFOLLY_USE_LIBCPP=1",
); );
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
SDKROOT = iphoneos; SDKROOT = iphoneos;
}; };
name = Debug; name = Debug;
@@ -571,7 +643,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 11.0; IPHONEOS_DEPLOYMENT_TARGET = 12.4;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
/usr/lib/swift, /usr/lib/swift,
"$(inherited)", "$(inherited)",
@@ -588,6 +660,7 @@
"-DFOLLY_MOBILE=1", "-DFOLLY_MOBILE=1",
"-DFOLLY_USE_LIBCPP=1", "-DFOLLY_USE_LIBCPP=1",
); );
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
SDKROOT = iphoneos; SDKROOT = iphoneos;
VALIDATE_PRODUCT = YES; VALIDATE_PRODUCT = YES;
}; };
@@ -596,7 +669,7 @@
/* End XCBuildConfiguration section */ /* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */ /* Begin XCConfigurationList section */
00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "testHotupdateTests" */ = { 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "AwesomeProjectTests" */ = {
isa = XCConfigurationList; isa = XCConfigurationList;
buildConfigurations = ( buildConfigurations = (
00E356F61AD99517003FC87E /* Debug */, 00E356F61AD99517003FC87E /* Debug */,
@@ -605,7 +678,7 @@
defaultConfigurationIsVisible = 0; defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release; defaultConfigurationName = Release;
}; };
13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "testHotupdate" */ = { 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "AwesomeProject" */ = {
isa = XCConfigurationList; isa = XCConfigurationList;
buildConfigurations = ( buildConfigurations = (
13B07F941A680F5B00A75B9A /* Debug */, 13B07F941A680F5B00A75B9A /* Debug */,
@@ -614,7 +687,7 @@
defaultConfigurationIsVisible = 0; defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release; defaultConfigurationName = Release;
}; };
83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "testHotupdate" */ = { 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "AwesomeProject" */ = {
isa = XCConfigurationList; isa = XCConfigurationList;
buildConfigurations = ( buildConfigurations = (
83CBBA201A601CBA00E9B192 /* Debug */, 83CBBA201A601CBA00E9B192 /* Debug */,

View File

@@ -15,9 +15,9 @@
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "13B07F861A680F5B00A75B9A" BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
BuildableName = "testHotupdate.app" BuildableName = "AwesomeProject.app"
BlueprintName = "testHotupdate" BlueprintName = "AwesomeProject"
ReferencedContainer = "container:testHotupdate.xcodeproj"> ReferencedContainer = "container:AwesomeProject.xcodeproj">
</BuildableReference> </BuildableReference>
</BuildActionEntry> </BuildActionEntry>
</BuildActionEntries> </BuildActionEntries>
@@ -33,9 +33,9 @@
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "00E356ED1AD99517003FC87E" BlueprintIdentifier = "00E356ED1AD99517003FC87E"
BuildableName = "testHotupdateTests.xctest" BuildableName = "AwesomeProjectTests.xctest"
BlueprintName = "testHotupdateTests" BlueprintName = "AwesomeProjectTests"
ReferencedContainer = "container:testHotupdate.xcodeproj"> ReferencedContainer = "container:AwesomeProject.xcodeproj">
</BuildableReference> </BuildableReference>
</TestableReference> </TestableReference>
</Testables> </Testables>
@@ -55,9 +55,9 @@
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "13B07F861A680F5B00A75B9A" BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
BuildableName = "testHotupdate.app" BuildableName = "AwesomeProject.app"
BlueprintName = "testHotupdate" BlueprintName = "AwesomeProject"
ReferencedContainer = "container:testHotupdate.xcodeproj"> ReferencedContainer = "container:AwesomeProject.xcodeproj">
</BuildableReference> </BuildableReference>
</BuildableProductRunnable> </BuildableProductRunnable>
</LaunchAction> </LaunchAction>
@@ -72,9 +72,9 @@
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "13B07F861A680F5B00A75B9A" BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
BuildableName = "testHotupdate.app" BuildableName = "AwesomeProject.app"
BlueprintName = "testHotupdate" BlueprintName = "AwesomeProject"
ReferencedContainer = "container:testHotupdate.xcodeproj"> ReferencedContainer = "container:AwesomeProject.xcodeproj">
</BuildableReference> </BuildableReference>
</BuildableProductRunnable> </BuildableProductRunnable>
</ProfileAction> </ProfileAction>

View File

@@ -2,7 +2,7 @@
<Workspace <Workspace
version = "1.0"> version = "1.0">
<FileRef <FileRef
location = "group:testHotupdate.xcodeproj"> location = "group:AwesomeProject.xcodeproj">
</FileRef> </FileRef>
<FileRef <FileRef
location = "group:Pods/Pods.xcodeproj"> location = "group:Pods/Pods.xcodeproj">

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View File

@@ -1,9 +1,8 @@
#import "AppDelegate.h" #import "AppDelegate.h"
#import "RCTPushy.h"
#import <React/RCTBridge.h> #import <React/RCTBridge.h>
#import <React/RCTBundleURLProvider.h> #import <React/RCTBundleURLProvider.h>
#import <React/RCTRootView.h> #import <React/RCTRootView.h>
#import "RCTPushy.h"
#import <React/RCTAppSetupUtils.h> #import <React/RCTAppSetupUtils.h>
@@ -17,6 +16,8 @@
#import <react/config/ReactNativeConfig.h> #import <react/config/ReactNativeConfig.h>
static NSString *const kRNConcurrentRoot = @"concurrentRoot";
@interface AppDelegate () <RCTCxxBridgeDelegate, RCTTurboModuleManagerDelegate> { @interface AppDelegate () <RCTCxxBridgeDelegate, RCTTurboModuleManagerDelegate> {
RCTTurboModuleManager *_turboModuleManager; RCTTurboModuleManager *_turboModuleManager;
RCTSurfacePresenterBridgeAdapter *_bridgeAdapter; RCTSurfacePresenterBridgeAdapter *_bridgeAdapter;
@@ -42,7 +43,8 @@
bridge.surfacePresenter = _bridgeAdapter.surfacePresenter; bridge.surfacePresenter = _bridgeAdapter.surfacePresenter;
#endif #endif
UIView *rootView = RCTAppSetupDefaultRootView(bridge, @"testHotupdate", nil); NSDictionary *initProps = [self prepareInitialProps];
UIView *rootView = RCTAppSetupDefaultRootView(bridge, @"AwesomeProject", initProps);
if (@available(iOS 13.0, *)) { if (@available(iOS 13.0, *)) {
rootView.backgroundColor = [UIColor systemBackgroundColor]; rootView.backgroundColor = [UIColor systemBackgroundColor];
@@ -58,12 +60,33 @@
return YES; return YES;
} }
/// This method controls whether the `concurrentRoot`feature of React18 is turned on or off.
///
/// @see: https://reactjs.org/blog/2022/03/29/react-v18.html
/// @note: This requires to be rendering on Fabric (i.e. on the New Architecture).
/// @return: `true` if the `concurrentRoot` feture is enabled. Otherwise, it returns `false`.
- (BOOL)concurrentRootEnabled
{
// Switch this bool to turn on and off the concurrent root
return true;
}
- (NSDictionary *)prepareInitialProps
{
NSMutableDictionary *initProps = [NSMutableDictionary new];
#ifdef RCT_NEW_ARCH_ENABLED
initProps[kRNConcurrentRoot] = @([self concurrentRootEnabled]);
#endif
return initProps;
}
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
{ {
#if DEBUG #if DEBUG
return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"]; return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"];
#else #else
// 非DEBUG情况下替换为热更新bundle
return [RCTPushy bundleURL]; return [RCTPushy bundleURL];
#endif #endif
} }

View File

@@ -5,7 +5,7 @@
<key>CFBundleDevelopmentRegion</key> <key>CFBundleDevelopmentRegion</key>
<string>en</string> <string>en</string>
<key>CFBundleDisplayName</key> <key>CFBundleDisplayName</key>
<string>testHotupdate</string> <string>AwesomeProject</string>
<key>CFBundleExecutable</key> <key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string> <string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key> <key>CFBundleIdentifier</key>
@@ -26,6 +26,8 @@
<true/> <true/>
<key>NSAppTransportSecurity</key> <key>NSAppTransportSecurity</key>
<dict> <dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
<key>NSExceptionDomains</key> <key>NSExceptionDomains</key>
<dict> <dict>
<key>localhost</key> <key>localhost</key>

View File

@@ -16,7 +16,7 @@
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/> <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews> <subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="testHotupdate" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="GJd-Yh-RWb"> <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="AwesomeProject" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="GJd-Yh-RWb">
<rect key="frame" x="0.0" y="202" width="375" height="43"/> <rect key="frame" x="0.0" y="202" width="375" height="43"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="36"/> <fontDescription key="fontDescription" type="boldSystem" pointSize="36"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>

View File

@@ -7,11 +7,11 @@
#define TIMEOUT_SECONDS 600 #define TIMEOUT_SECONDS 600
#define TEXT_TO_LOOK_FOR @"Welcome to React" #define TEXT_TO_LOOK_FOR @"Welcome to React"
@interface testHotupdateTests : XCTestCase @interface AwesomeProjectTests : XCTestCase
@end @end
@implementation testHotupdateTests @implementation AwesomeProjectTests
- (BOOL)findSubviewInView:(UIView *)view matching:(BOOL (^)(UIView *view))test - (BOOL)findSubviewInView:(UIView *)view matching:(BOOL (^)(UIView *view))test
{ {

View File

@@ -1,10 +1,12 @@
require_relative '../node_modules/react-native/scripts/react_native_pods' require_relative '../node_modules/react-native/scripts/react_native_pods'
require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules' require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'
platform :ios, '11.0' platform :ios, '12.4'
install! 'cocoapods', :deterministic_uuids => false install! 'cocoapods', :deterministic_uuids => false
target 'testHotupdate' do production = ENV["PRODUCTION"] == "1"
target 'AwesomeProject' do
config = use_native_modules! config = use_native_modules!
# Flags change depending on the env values. # Flags change depending on the env values.
@@ -13,18 +15,18 @@ target 'testHotupdate' do
use_react_native!( use_react_native!(
:path => config[:reactNativePath], :path => config[:reactNativePath],
# to enable hermes on iOS, change `false` to `true` and then install pods # to enable hermes on iOS, change `false` to `true` and then install pods
:production => production,
:hermes_enabled => flags[:hermes_enabled], :hermes_enabled => flags[:hermes_enabled],
:fabric_enabled => flags[:fabric_enabled], :fabric_enabled => flags[:fabric_enabled],
:flipper_configuration => FlipperConfiguration.enabled,
# An absolute path to your application root. # An absolute path to your application root.
:app_path => "#{Pod::Config.instance.installation_root}/.." :app_path => "#{Pod::Config.instance.installation_root}/.."
) )
target 'AwesomeProjectTests' do
# Enables Flipper. inherit! :complete
# # Pods for testing
# Note that if you have use_frameworks! enabled, Flipper will not work and end
# you should disable the next line.
use_flipper!()
post_install do |installer| post_install do |installer|
react_native_post_install(installer) react_native_post_install(installer)

View File

@@ -2,19 +2,19 @@ PODS:
- boost (1.76.0) - boost (1.76.0)
- CocoaAsyncSocket (7.6.5) - CocoaAsyncSocket (7.6.5)
- DoubleConversion (1.1.6) - DoubleConversion (1.1.6)
- FBLazyVector (0.68.2) - FBLazyVector (0.69.8)
- FBReactNativeSpec (0.68.2): - FBReactNativeSpec (0.69.8):
- RCT-Folly (= 2021.06.28.00-v2) - RCT-Folly (= 2021.06.28.00-v2)
- RCTRequired (= 0.68.2) - RCTRequired (= 0.69.8)
- RCTTypeSafety (= 0.68.2) - RCTTypeSafety (= 0.69.8)
- React-Core (= 0.68.2) - React-Core (= 0.69.8)
- React-jsi (= 0.68.2) - React-jsi (= 0.69.8)
- ReactCommon/turbomodule/core (= 0.68.2) - ReactCommon/turbomodule/core (= 0.69.8)
- Flipper (0.125.0): - Flipper (0.125.0):
- Flipper-Folly (~> 2.6) - Flipper-Folly (~> 2.6)
- Flipper-RSocket (~> 1.4) - Flipper-RSocket (~> 1.4)
- Flipper-Boost-iOSX (1.76.0.1.11) - Flipper-Boost-iOSX (1.76.0.1.11)
- Flipper-DoubleConversion (3.2.0) - Flipper-DoubleConversion (3.2.0.1)
- Flipper-Fmt (7.1.7) - Flipper-Fmt (7.1.7)
- Flipper-Folly (2.6.10): - Flipper-Folly (2.6.10):
- Flipper-Boost-iOSX - Flipper-Boost-iOSX
@@ -23,7 +23,7 @@ PODS:
- Flipper-Glog - Flipper-Glog
- libevent (~> 2.1.12) - libevent (~> 2.1.12)
- OpenSSL-Universal (= 1.1.1100) - OpenSSL-Universal (= 1.1.1100)
- Flipper-Glog (0.5.0.4) - Flipper-Glog (0.5.0.5)
- Flipper-PeerTalk (0.0.4) - Flipper-PeerTalk (0.0.4)
- Flipper-RSocket (1.4.3): - Flipper-RSocket (1.4.3):
- Flipper-Folly (~> 2.6) - Flipper-Folly (~> 2.6)
@@ -86,278 +86,284 @@ PODS:
- DoubleConversion - DoubleConversion
- fmt (~> 6.2.1) - fmt (~> 6.2.1)
- glog - glog
- RCTRequired (0.68.2) - RCTRequired (0.69.8)
- RCTTypeSafety (0.68.2): - RCTTypeSafety (0.69.8):
- FBLazyVector (= 0.68.2) - FBLazyVector (= 0.69.8)
- RCTRequired (= 0.69.8)
- React-Core (= 0.69.8)
- React (0.69.8):
- React-Core (= 0.69.8)
- React-Core/DevSupport (= 0.69.8)
- React-Core/RCTWebSocket (= 0.69.8)
- React-RCTActionSheet (= 0.69.8)
- React-RCTAnimation (= 0.69.8)
- React-RCTBlob (= 0.69.8)
- React-RCTImage (= 0.69.8)
- React-RCTLinking (= 0.69.8)
- React-RCTNetwork (= 0.69.8)
- React-RCTSettings (= 0.69.8)
- React-RCTText (= 0.69.8)
- React-RCTVibration (= 0.69.8)
- React-bridging (0.69.8):
- RCT-Folly (= 2021.06.28.00-v2) - RCT-Folly (= 2021.06.28.00-v2)
- RCTRequired (= 0.68.2) - React-jsi (= 0.69.8)
- React-Core (= 0.68.2) - React-callinvoker (0.69.8)
- React (0.68.2): - React-Codegen (0.69.8):
- React-Core (= 0.68.2) - FBReactNativeSpec (= 0.69.8)
- React-Core/DevSupport (= 0.68.2)
- React-Core/RCTWebSocket (= 0.68.2)
- React-RCTActionSheet (= 0.68.2)
- React-RCTAnimation (= 0.68.2)
- React-RCTBlob (= 0.68.2)
- React-RCTImage (= 0.68.2)
- React-RCTLinking (= 0.68.2)
- React-RCTNetwork (= 0.68.2)
- React-RCTSettings (= 0.68.2)
- React-RCTText (= 0.68.2)
- React-RCTVibration (= 0.68.2)
- React-callinvoker (0.68.2)
- React-Codegen (0.68.2):
- FBReactNativeSpec (= 0.68.2)
- RCT-Folly (= 2021.06.28.00-v2) - RCT-Folly (= 2021.06.28.00-v2)
- RCTRequired (= 0.68.2) - RCTRequired (= 0.69.8)
- RCTTypeSafety (= 0.68.2) - RCTTypeSafety (= 0.69.8)
- React-Core (= 0.68.2) - React-Core (= 0.69.8)
- React-jsi (= 0.68.2) - React-jsi (= 0.69.8)
- React-jsiexecutor (= 0.68.2) - React-jsiexecutor (= 0.69.8)
- ReactCommon/turbomodule/core (= 0.68.2) - ReactCommon/turbomodule/core (= 0.69.8)
- React-Core (0.68.2): - React-Core (0.69.8):
- glog - glog
- RCT-Folly (= 2021.06.28.00-v2) - RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default (= 0.68.2) - React-Core/Default (= 0.69.8)
- React-cxxreact (= 0.68.2) - React-cxxreact (= 0.69.8)
- React-jsi (= 0.68.2) - React-jsi (= 0.69.8)
- React-jsiexecutor (= 0.68.2) - React-jsiexecutor (= 0.69.8)
- React-perflogger (= 0.68.2) - React-perflogger (= 0.69.8)
- Yoga - Yoga
- React-Core/CoreModulesHeaders (0.68.2): - React-Core/CoreModulesHeaders (0.69.8):
- glog - glog
- RCT-Folly (= 2021.06.28.00-v2) - RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default - React-Core/Default
- React-cxxreact (= 0.68.2) - React-cxxreact (= 0.69.8)
- React-jsi (= 0.68.2) - React-jsi (= 0.69.8)
- React-jsiexecutor (= 0.68.2) - React-jsiexecutor (= 0.69.8)
- React-perflogger (= 0.68.2) - React-perflogger (= 0.69.8)
- Yoga - Yoga
- React-Core/Default (0.68.2): - React-Core/Default (0.69.8):
- glog - glog
- RCT-Folly (= 2021.06.28.00-v2) - RCT-Folly (= 2021.06.28.00-v2)
- React-cxxreact (= 0.68.2) - React-cxxreact (= 0.69.8)
- React-jsi (= 0.68.2) - React-jsi (= 0.69.8)
- React-jsiexecutor (= 0.68.2) - React-jsiexecutor (= 0.69.8)
- React-perflogger (= 0.68.2) - React-perflogger (= 0.69.8)
- Yoga - Yoga
- React-Core/DevSupport (0.68.2): - React-Core/DevSupport (0.69.8):
- glog - glog
- RCT-Folly (= 2021.06.28.00-v2) - RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default (= 0.68.2) - React-Core/Default (= 0.69.8)
- React-Core/RCTWebSocket (= 0.68.2) - React-Core/RCTWebSocket (= 0.69.8)
- React-cxxreact (= 0.68.2) - React-cxxreact (= 0.69.8)
- React-jsi (= 0.68.2) - React-jsi (= 0.69.8)
- React-jsiexecutor (= 0.68.2) - React-jsiexecutor (= 0.69.8)
- React-jsinspector (= 0.68.2) - React-jsinspector (= 0.69.8)
- React-perflogger (= 0.68.2) - React-perflogger (= 0.69.8)
- Yoga - Yoga
- React-Core/RCTActionSheetHeaders (0.68.2): - React-Core/RCTActionSheetHeaders (0.69.8):
- glog - glog
- RCT-Folly (= 2021.06.28.00-v2) - RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default - React-Core/Default
- React-cxxreact (= 0.68.2) - React-cxxreact (= 0.69.8)
- React-jsi (= 0.68.2) - React-jsi (= 0.69.8)
- React-jsiexecutor (= 0.68.2) - React-jsiexecutor (= 0.69.8)
- React-perflogger (= 0.68.2) - React-perflogger (= 0.69.8)
- Yoga - Yoga
- React-Core/RCTAnimationHeaders (0.68.2): - React-Core/RCTAnimationHeaders (0.69.8):
- glog - glog
- RCT-Folly (= 2021.06.28.00-v2) - RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default - React-Core/Default
- React-cxxreact (= 0.68.2) - React-cxxreact (= 0.69.8)
- React-jsi (= 0.68.2) - React-jsi (= 0.69.8)
- React-jsiexecutor (= 0.68.2) - React-jsiexecutor (= 0.69.8)
- React-perflogger (= 0.68.2) - React-perflogger (= 0.69.8)
- Yoga - Yoga
- React-Core/RCTBlobHeaders (0.68.2): - React-Core/RCTBlobHeaders (0.69.8):
- glog - glog
- RCT-Folly (= 2021.06.28.00-v2) - RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default - React-Core/Default
- React-cxxreact (= 0.68.2) - React-cxxreact (= 0.69.8)
- React-jsi (= 0.68.2) - React-jsi (= 0.69.8)
- React-jsiexecutor (= 0.68.2) - React-jsiexecutor (= 0.69.8)
- React-perflogger (= 0.68.2) - React-perflogger (= 0.69.8)
- Yoga - Yoga
- React-Core/RCTImageHeaders (0.68.2): - React-Core/RCTImageHeaders (0.69.8):
- glog - glog
- RCT-Folly (= 2021.06.28.00-v2) - RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default - React-Core/Default
- React-cxxreact (= 0.68.2) - React-cxxreact (= 0.69.8)
- React-jsi (= 0.68.2) - React-jsi (= 0.69.8)
- React-jsiexecutor (= 0.68.2) - React-jsiexecutor (= 0.69.8)
- React-perflogger (= 0.68.2) - React-perflogger (= 0.69.8)
- Yoga - Yoga
- React-Core/RCTLinkingHeaders (0.68.2): - React-Core/RCTLinkingHeaders (0.69.8):
- glog - glog
- RCT-Folly (= 2021.06.28.00-v2) - RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default - React-Core/Default
- React-cxxreact (= 0.68.2) - React-cxxreact (= 0.69.8)
- React-jsi (= 0.68.2) - React-jsi (= 0.69.8)
- React-jsiexecutor (= 0.68.2) - React-jsiexecutor (= 0.69.8)
- React-perflogger (= 0.68.2) - React-perflogger (= 0.69.8)
- Yoga - Yoga
- React-Core/RCTNetworkHeaders (0.68.2): - React-Core/RCTNetworkHeaders (0.69.8):
- glog - glog
- RCT-Folly (= 2021.06.28.00-v2) - RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default - React-Core/Default
- React-cxxreact (= 0.68.2) - React-cxxreact (= 0.69.8)
- React-jsi (= 0.68.2) - React-jsi (= 0.69.8)
- React-jsiexecutor (= 0.68.2) - React-jsiexecutor (= 0.69.8)
- React-perflogger (= 0.68.2) - React-perflogger (= 0.69.8)
- Yoga - Yoga
- React-Core/RCTSettingsHeaders (0.68.2): - React-Core/RCTSettingsHeaders (0.69.8):
- glog - glog
- RCT-Folly (= 2021.06.28.00-v2) - RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default - React-Core/Default
- React-cxxreact (= 0.68.2) - React-cxxreact (= 0.69.8)
- React-jsi (= 0.68.2) - React-jsi (= 0.69.8)
- React-jsiexecutor (= 0.68.2) - React-jsiexecutor (= 0.69.8)
- React-perflogger (= 0.68.2) - React-perflogger (= 0.69.8)
- Yoga - Yoga
- React-Core/RCTTextHeaders (0.68.2): - React-Core/RCTTextHeaders (0.69.8):
- glog - glog
- RCT-Folly (= 2021.06.28.00-v2) - RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default - React-Core/Default
- React-cxxreact (= 0.68.2) - React-cxxreact (= 0.69.8)
- React-jsi (= 0.68.2) - React-jsi (= 0.69.8)
- React-jsiexecutor (= 0.68.2) - React-jsiexecutor (= 0.69.8)
- React-perflogger (= 0.68.2) - React-perflogger (= 0.69.8)
- Yoga - Yoga
- React-Core/RCTVibrationHeaders (0.68.2): - React-Core/RCTVibrationHeaders (0.69.8):
- glog - glog
- RCT-Folly (= 2021.06.28.00-v2) - RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default - React-Core/Default
- React-cxxreact (= 0.68.2) - React-cxxreact (= 0.69.8)
- React-jsi (= 0.68.2) - React-jsi (= 0.69.8)
- React-jsiexecutor (= 0.68.2) - React-jsiexecutor (= 0.69.8)
- React-perflogger (= 0.68.2) - React-perflogger (= 0.69.8)
- Yoga - Yoga
- React-Core/RCTWebSocket (0.68.2): - React-Core/RCTWebSocket (0.69.8):
- glog - glog
- RCT-Folly (= 2021.06.28.00-v2) - RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default (= 0.68.2) - React-Core/Default (= 0.69.8)
- React-cxxreact (= 0.68.2) - React-cxxreact (= 0.69.8)
- React-jsi (= 0.68.2) - React-jsi (= 0.69.8)
- React-jsiexecutor (= 0.68.2) - React-jsiexecutor (= 0.69.8)
- React-perflogger (= 0.68.2) - React-perflogger (= 0.69.8)
- Yoga - Yoga
- React-CoreModules (0.68.2): - React-CoreModules (0.69.8):
- RCT-Folly (= 2021.06.28.00-v2) - RCT-Folly (= 2021.06.28.00-v2)
- RCTTypeSafety (= 0.68.2) - RCTTypeSafety (= 0.69.8)
- React-Codegen (= 0.68.2) - React-Codegen (= 0.69.8)
- React-Core/CoreModulesHeaders (= 0.68.2) - React-Core/CoreModulesHeaders (= 0.69.8)
- React-jsi (= 0.68.2) - React-jsi (= 0.69.8)
- React-RCTImage (= 0.68.2) - React-RCTImage (= 0.69.8)
- ReactCommon/turbomodule/core (= 0.68.2) - ReactCommon/turbomodule/core (= 0.69.8)
- React-cxxreact (0.68.2): - React-cxxreact (0.69.8):
- boost (= 1.76.0) - boost (= 1.76.0)
- DoubleConversion - DoubleConversion
- glog - glog
- RCT-Folly (= 2021.06.28.00-v2) - RCT-Folly (= 2021.06.28.00-v2)
- React-callinvoker (= 0.68.2) - React-callinvoker (= 0.69.8)
- React-jsi (= 0.68.2) - React-jsi (= 0.69.8)
- React-jsinspector (= 0.68.2) - React-jsinspector (= 0.69.8)
- React-logger (= 0.68.2) - React-logger (= 0.69.8)
- React-perflogger (= 0.68.2) - React-perflogger (= 0.69.8)
- React-runtimeexecutor (= 0.68.2) - React-runtimeexecutor (= 0.69.8)
- React-jsi (0.68.2): - React-jsi (0.69.8):
- boost (= 1.76.0) - boost (= 1.76.0)
- DoubleConversion - DoubleConversion
- glog - glog
- RCT-Folly (= 2021.06.28.00-v2) - RCT-Folly (= 2021.06.28.00-v2)
- React-jsi/Default (= 0.68.2) - React-jsi/Default (= 0.69.8)
- React-jsi/Default (0.68.2): - React-jsi/Default (0.69.8):
- boost (= 1.76.0) - boost (= 1.76.0)
- DoubleConversion - DoubleConversion
- glog - glog
- RCT-Folly (= 2021.06.28.00-v2) - RCT-Folly (= 2021.06.28.00-v2)
- React-jsiexecutor (0.68.2): - React-jsiexecutor (0.69.8):
- DoubleConversion - DoubleConversion
- glog - glog
- RCT-Folly (= 2021.06.28.00-v2) - RCT-Folly (= 2021.06.28.00-v2)
- React-cxxreact (= 0.68.2) - React-cxxreact (= 0.69.8)
- React-jsi (= 0.68.2) - React-jsi (= 0.69.8)
- React-perflogger (= 0.68.2) - React-perflogger (= 0.69.8)
- React-jsinspector (0.68.2) - React-jsinspector (0.69.8)
- React-logger (0.68.2): - React-logger (0.69.8):
- glog - glog
- react-native-update (7.4.2): - react-native-update (9.0.0):
- React - React
- react-native-update/HDiffPatch (= 7.4.2) - React-Core
- react-native-update/RCTPushy (= 7.4.2) - react-native-update/HDiffPatch (= 9.0.0)
- react-native-update/RCTPushy (= 9.0.0)
- SSZipArchive - SSZipArchive
- react-native-update/HDiffPatch (7.4.2): - react-native-update/HDiffPatch (9.0.0):
- React - React
- React-Core
- SSZipArchive - SSZipArchive
- react-native-update/RCTPushy (7.4.2): - react-native-update/RCTPushy (9.0.0):
- React - React
- React-Core
- SSZipArchive - SSZipArchive
- React-perflogger (0.68.2) - React-perflogger (0.69.8)
- React-RCTActionSheet (0.68.2): - React-RCTActionSheet (0.69.8):
- React-Core/RCTActionSheetHeaders (= 0.68.2) - React-Core/RCTActionSheetHeaders (= 0.69.8)
- React-RCTAnimation (0.68.2): - React-RCTAnimation (0.69.8):
- RCT-Folly (= 2021.06.28.00-v2) - RCT-Folly (= 2021.06.28.00-v2)
- RCTTypeSafety (= 0.68.2) - RCTTypeSafety (= 0.69.8)
- React-Codegen (= 0.68.2) - React-Codegen (= 0.69.8)
- React-Core/RCTAnimationHeaders (= 0.68.2) - React-Core/RCTAnimationHeaders (= 0.69.8)
- React-jsi (= 0.68.2) - React-jsi (= 0.69.8)
- ReactCommon/turbomodule/core (= 0.68.2) - ReactCommon/turbomodule/core (= 0.69.8)
- React-RCTBlob (0.68.2): - React-RCTBlob (0.69.8):
- RCT-Folly (= 2021.06.28.00-v2) - RCT-Folly (= 2021.06.28.00-v2)
- React-Codegen (= 0.68.2) - React-Codegen (= 0.69.8)
- React-Core/RCTBlobHeaders (= 0.68.2) - React-Core/RCTBlobHeaders (= 0.69.8)
- React-Core/RCTWebSocket (= 0.68.2) - React-Core/RCTWebSocket (= 0.69.8)
- React-jsi (= 0.68.2) - React-jsi (= 0.69.8)
- React-RCTNetwork (= 0.68.2) - React-RCTNetwork (= 0.69.8)
- ReactCommon/turbomodule/core (= 0.68.2) - ReactCommon/turbomodule/core (= 0.69.8)
- React-RCTImage (0.68.2): - React-RCTImage (0.69.8):
- RCT-Folly (= 2021.06.28.00-v2) - RCT-Folly (= 2021.06.28.00-v2)
- RCTTypeSafety (= 0.68.2) - RCTTypeSafety (= 0.69.8)
- React-Codegen (= 0.68.2) - React-Codegen (= 0.69.8)
- React-Core/RCTImageHeaders (= 0.68.2) - React-Core/RCTImageHeaders (= 0.69.8)
- React-jsi (= 0.68.2) - React-jsi (= 0.69.8)
- React-RCTNetwork (= 0.68.2) - React-RCTNetwork (= 0.69.8)
- ReactCommon/turbomodule/core (= 0.68.2) - ReactCommon/turbomodule/core (= 0.69.8)
- React-RCTLinking (0.68.2): - React-RCTLinking (0.69.8):
- React-Codegen (= 0.68.2) - React-Codegen (= 0.69.8)
- React-Core/RCTLinkingHeaders (= 0.68.2) - React-Core/RCTLinkingHeaders (= 0.69.8)
- React-jsi (= 0.68.2) - React-jsi (= 0.69.8)
- ReactCommon/turbomodule/core (= 0.68.2) - ReactCommon/turbomodule/core (= 0.69.8)
- React-RCTNetwork (0.68.2): - React-RCTNetwork (0.69.8):
- RCT-Folly (= 2021.06.28.00-v2) - RCT-Folly (= 2021.06.28.00-v2)
- RCTTypeSafety (= 0.68.2) - RCTTypeSafety (= 0.69.8)
- React-Codegen (= 0.68.2) - React-Codegen (= 0.69.8)
- React-Core/RCTNetworkHeaders (= 0.68.2) - React-Core/RCTNetworkHeaders (= 0.69.8)
- React-jsi (= 0.68.2) - React-jsi (= 0.69.8)
- ReactCommon/turbomodule/core (= 0.68.2) - ReactCommon/turbomodule/core (= 0.69.8)
- React-RCTSettings (0.68.2): - React-RCTSettings (0.69.8):
- RCT-Folly (= 2021.06.28.00-v2) - RCT-Folly (= 2021.06.28.00-v2)
- RCTTypeSafety (= 0.68.2) - RCTTypeSafety (= 0.69.8)
- React-Codegen (= 0.68.2) - React-Codegen (= 0.69.8)
- React-Core/RCTSettingsHeaders (= 0.68.2) - React-Core/RCTSettingsHeaders (= 0.69.8)
- React-jsi (= 0.68.2) - React-jsi (= 0.69.8)
- ReactCommon/turbomodule/core (= 0.68.2) - ReactCommon/turbomodule/core (= 0.69.8)
- React-RCTText (0.68.2): - React-RCTText (0.69.8):
- React-Core/RCTTextHeaders (= 0.68.2) - React-Core/RCTTextHeaders (= 0.69.8)
- React-RCTVibration (0.68.2): - React-RCTVibration (0.69.8):
- RCT-Folly (= 2021.06.28.00-v2) - RCT-Folly (= 2021.06.28.00-v2)
- React-Codegen (= 0.68.2) - React-Codegen (= 0.69.8)
- React-Core/RCTVibrationHeaders (= 0.68.2) - React-Core/RCTVibrationHeaders (= 0.69.8)
- React-jsi (= 0.68.2) - React-jsi (= 0.69.8)
- ReactCommon/turbomodule/core (= 0.68.2) - ReactCommon/turbomodule/core (= 0.69.8)
- React-runtimeexecutor (0.68.2): - React-runtimeexecutor (0.69.8):
- React-jsi (= 0.68.2) - React-jsi (= 0.69.8)
- ReactCommon/turbomodule/core (0.68.2): - ReactCommon/turbomodule/core (0.69.8):
- DoubleConversion - DoubleConversion
- glog - glog
- RCT-Folly (= 2021.06.28.00-v2) - RCT-Folly (= 2021.06.28.00-v2)
- React-callinvoker (= 0.68.2) - React-bridging (= 0.69.8)
- React-Core (= 0.68.2) - React-callinvoker (= 0.69.8)
- React-cxxreact (= 0.68.2) - React-Core (= 0.69.8)
- React-jsi (= 0.68.2) - React-cxxreact (= 0.69.8)
- React-logger (= 0.68.2) - React-jsi (= 0.69.8)
- React-perflogger (= 0.68.2) - React-logger (= 0.69.8)
- React-perflogger (= 0.69.8)
- SocketRocket (0.6.0) - SocketRocket (0.6.0)
- SSZipArchive (2.4.3) - SSZipArchive (2.4.3)
- Yoga (1.14.0) - Yoga (1.14.0)
@@ -371,10 +377,10 @@ DEPENDENCIES:
- FBReactNativeSpec (from `../node_modules/react-native/React/FBReactNativeSpec`) - FBReactNativeSpec (from `../node_modules/react-native/React/FBReactNativeSpec`)
- Flipper (= 0.125.0) - Flipper (= 0.125.0)
- Flipper-Boost-iOSX (= 1.76.0.1.11) - Flipper-Boost-iOSX (= 1.76.0.1.11)
- Flipper-DoubleConversion (= 3.2.0) - Flipper-DoubleConversion (= 3.2.0.1)
- Flipper-Fmt (= 7.1.7) - Flipper-Fmt (= 7.1.7)
- Flipper-Folly (= 2.6.10) - Flipper-Folly (= 2.6.10)
- Flipper-Glog (= 0.5.0.4) - Flipper-Glog (= 0.5.0.5)
- Flipper-PeerTalk (= 0.0.4) - Flipper-PeerTalk (= 0.0.4)
- Flipper-RSocket (= 1.4.3) - Flipper-RSocket (= 1.4.3)
- FlipperKit (= 0.125.0) - FlipperKit (= 0.125.0)
@@ -396,6 +402,7 @@ DEPENDENCIES:
- RCTRequired (from `../node_modules/react-native/Libraries/RCTRequired`) - RCTRequired (from `../node_modules/react-native/Libraries/RCTRequired`)
- RCTTypeSafety (from `../node_modules/react-native/Libraries/TypeSafety`) - RCTTypeSafety (from `../node_modules/react-native/Libraries/TypeSafety`)
- React (from `../node_modules/react-native/`) - React (from `../node_modules/react-native/`)
- React-bridging (from `../node_modules/react-native/ReactCommon`)
- React-callinvoker (from `../node_modules/react-native/ReactCommon/callinvoker`) - React-callinvoker (from `../node_modules/react-native/ReactCommon/callinvoker`)
- React-Codegen (from `build/generated/ios`) - React-Codegen (from `build/generated/ios`)
- React-Core (from `../node_modules/react-native/`) - React-Core (from `../node_modules/react-native/`)
@@ -407,7 +414,7 @@ DEPENDENCIES:
- React-jsiexecutor (from `../node_modules/react-native/ReactCommon/jsiexecutor`) - React-jsiexecutor (from `../node_modules/react-native/ReactCommon/jsiexecutor`)
- React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector`) - React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector`)
- React-logger (from `../node_modules/react-native/ReactCommon/logger`) - React-logger (from `../node_modules/react-native/ReactCommon/logger`)
- react-native-update (from `../../..`) - react-native-update (from `../node_modules/react-native-update`)
- React-perflogger (from `../node_modules/react-native/ReactCommon/reactperflogger`) - React-perflogger (from `../node_modules/react-native/ReactCommon/reactperflogger`)
- React-RCTActionSheet (from `../node_modules/react-native/Libraries/ActionSheetIOS`) - React-RCTActionSheet (from `../node_modules/react-native/Libraries/ActionSheetIOS`)
- React-RCTAnimation (from `../node_modules/react-native/Libraries/NativeAnimation`) - React-RCTAnimation (from `../node_modules/react-native/Libraries/NativeAnimation`)
@@ -460,6 +467,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native/Libraries/TypeSafety" :path: "../node_modules/react-native/Libraries/TypeSafety"
React: React:
:path: "../node_modules/react-native/" :path: "../node_modules/react-native/"
React-bridging:
:path: "../node_modules/react-native/ReactCommon"
React-callinvoker: React-callinvoker:
:path: "../node_modules/react-native/ReactCommon/callinvoker" :path: "../node_modules/react-native/ReactCommon/callinvoker"
React-Codegen: React-Codegen:
@@ -479,7 +488,7 @@ EXTERNAL SOURCES:
React-logger: React-logger:
:path: "../node_modules/react-native/ReactCommon/logger" :path: "../node_modules/react-native/ReactCommon/logger"
react-native-update: react-native-update:
:path: "../../.." :path: "../node_modules/react-native-update"
React-perflogger: React-perflogger:
:path: "../node_modules/react-native/ReactCommon/reactperflogger" :path: "../node_modules/react-native/ReactCommon/reactperflogger"
React-RCTActionSheet: React-RCTActionSheet:
@@ -510,53 +519,54 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS: SPEC CHECKSUMS:
boost: a7c83b31436843459a1961bfd74b96033dc77234 boost: a7c83b31436843459a1961bfd74b96033dc77234
CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99 CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99
DoubleConversion: 831926d9b8bf8166fd87886c4abab286c2422662 DoubleConversion: 5189b271737e1565bdce30deb4a08d647e3f5f54
FBLazyVector: a7a655862f6b09625d11c772296b01cd5164b648 FBLazyVector: c7b6997d41fffaaaf4d18c82bc93885df731e2d0
FBReactNativeSpec: 81ce99032d5b586fddd6a38d450f8595f7e04be4 FBReactNativeSpec: b1217c558a3ae84c2057d9c2ddce88af21379a68
Flipper: 26fc4b7382499f1281eb8cb921e5c3ad6de91fe0 Flipper: 26fc4b7382499f1281eb8cb921e5c3ad6de91fe0
Flipper-Boost-iOSX: fd1e2b8cbef7e662a122412d7ac5f5bea715403c Flipper-Boost-iOSX: fd1e2b8cbef7e662a122412d7ac5f5bea715403c
Flipper-DoubleConversion: 3d3d04a078d4f3a1b6c6916587f159dc11f232c4 Flipper-DoubleConversion: 2dc99b02f658daf147069aad9dbd29d8feb06d30
Flipper-Fmt: 60cbdd92fc254826e61d669a5d87ef7015396a9b Flipper-Fmt: 60cbdd92fc254826e61d669a5d87ef7015396a9b
Flipper-Folly: 584845625005ff068a6ebf41f857f468decd26b3 Flipper-Folly: 584845625005ff068a6ebf41f857f468decd26b3
Flipper-Glog: 87bc98ff48de90cb5b0b5114ed3da79d85ee2dd4 Flipper-Glog: 70c50ce58ddaf67dc35180db05f191692570f446
Flipper-PeerTalk: 116d8f857dc6ef55c7a5a75ea3ceaafe878aadc9 Flipper-PeerTalk: 116d8f857dc6ef55c7a5a75ea3ceaafe878aadc9
Flipper-RSocket: d9d9ade67cbecf6ac10730304bf5607266dd2541 Flipper-RSocket: d9d9ade67cbecf6ac10730304bf5607266dd2541
FlipperKit: cbdee19bdd4e7f05472a66ce290f1b729ba3cb86 FlipperKit: cbdee19bdd4e7f05472a66ce290f1b729ba3cb86
fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9 fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9
glog: 476ee3e89abb49e07f822b48323c51c57124b572 glog: 3d02b25ca00c2d456734d0bcff864cbc62f6ae1a
libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913 libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913
OpenSSL-Universal: ebc357f1e6bc71fa463ccb2fe676756aff50e88c OpenSSL-Universal: ebc357f1e6bc71fa463ccb2fe676756aff50e88c
RCT-Folly: 4d8508a426467c48885f1151029bc15fa5d7b3b8 RCT-Folly: b9d9fe1fc70114b751c076104e52f3b1b5e5a95a
RCTRequired: 3e917ea5377751094f38145fdece525aa90545a0 RCTRequired: 344fd6fb3c669da87e91294be7ee0199bf35c701
RCTTypeSafety: c43c072a4bd60feb49a9570b0517892b4305c45e RCTTypeSafety: ca608cc1d3a81229632bc0c1136b698b9337c1d8
React: 176dd882de001854ced260fad41bb68a31aa4bd0 React: 1d76bae8d73113b202224075f0b0bd546996b328
React-callinvoker: c2864d1818d6e64928d2faf774a3800dfc38fe1f React-bridging: 2eb62dc8ba31194d285705cb62e24a15753aeaec
React-Codegen: 98b6f97f0a7abf7d67e4ce435c77c05b7a95cf05 React-callinvoker: f3cfb045a0fb185445542555d88b6acf385cbedc
React-Core: fdaa2916b1c893f39f02cff0476d1fb0cab1e352 React-Codegen: 808e2d4d4201583ac89fb40d6862aaa26cb88999
React-CoreModules: fd8705b80699ec36c2cdd635c2ce9d874b9cfdfc React-Core: 82c5392ab182252ce4ffbc16794e0e38b32ea9a1
React-cxxreact: 1832d971f7b0cb2c7b943dc0ec962762c90c906e React-CoreModules: 4e891a6c0a59b01ca8406e041c7e49ab12e51d48
React-jsi: 72af715135abe8c3f0dcf3b2548b71d048b69a7e React-cxxreact: 0dc4ba3d97839bd36d422592ddb0bdfa9940a990
React-jsiexecutor: b7b553412f2ec768fe6c8f27cd6bafdb9d8719e6 React-jsi: dcd936ff5e580dba0d8644ac9ee4ca47bb166df1
React-jsinspector: c5989c77cb89ae6a69561095a61cce56a44ae8e8 React-jsiexecutor: 2cf8ea3753afb81dfcc386613dbbb0b5d155fb34
React-logger: a0833912d93b36b791b7a521672d8ee89107aff1 React-jsinspector: 0eda09e9cf22bbb5dbb1d23143b03a31acf37d67
react-native-update: 35b44bdcfd37e0f0bbef8ceb1bdda85067e591ff React-logger: 5997ab008583826c10ffe4e1ff990363e975639d
React-perflogger: a18b4f0bd933b8b24ecf9f3c54f9bf65180f3fe6 react-native-update: 2b5ef06bfeaa668614c8deb7ec4d20dcf56f9278
React-RCTActionSheet: 547fe42fdb4b6089598d79f8e1d855d7c23e2162 React-perflogger: ad1416a715d86b32f456e5d0aed99c3b52f1de37
React-RCTAnimation: bc9440a1c37b06ae9ebbb532d244f607805c6034 React-RCTActionSheet: cbf7c6a953982562418ee72a1084ff7b9447b558
React-RCTBlob: a1295c8e183756d7ef30ba6e8f8144dfe8a19215 React-RCTAnimation: 33df3e25824dd7313edec28dded2745542f9352b
React-RCTImage: a30d1ee09b1334067fbb6f30789aae2d7ac150c9 React-RCTBlob: 2434411df0d2d0e6567445a995f6678e2cc1d8e3
React-RCTLinking: ffc6d5b88d1cb9aca13c54c2ec6507fbf07f2ac4 React-RCTImage: 0b912ab4255ea5ec903d06c77f5a23cea9e9c988
React-RCTNetwork: f807a2facab6cf5cf36d592e634611de9cf12d81 React-RCTLinking: eb239c24f4f5fe79c57a2fedf45f34f40481dda3
React-RCTSettings: 861806819226ed8332e6a8f90df2951a34bb3e7f React-RCTNetwork: db173a6c35c1212909944920a5aa03eb8b7b9cf4
React-RCTText: f3fb464cc41a50fc7a1aba4deeb76a9ad8282cb9 React-RCTSettings: 687fa7538972467d80cd7729b6f86598e1369813
React-RCTVibration: 79040b92bfa9c3c2d2cb4f57e981164ec7ab9374 React-RCTText: 605ef414f8e72bd111945d3612cd0518de612b24
React-runtimeexecutor: b960b687d2dfef0d3761fbb187e01812ebab8b23 React-RCTVibration: 5462287ee85304ba1a00474665ab292e63a41663
ReactCommon: 095366164a276d91ea704ce53cb03825c487a3f2 React-runtimeexecutor: 9df680f18497367bcf5c15b6b6406c0f2dfa2b6a
ReactCommon: c10f046f3ef8561e7c8e7e9b9dae2ecc9ffc48ef
SocketRocket: fccef3f9c5cedea1353a9ef6ada904fde10d6608 SocketRocket: fccef3f9c5cedea1353a9ef6ada904fde10d6608
SSZipArchive: fe6a26b2a54d5a0890f2567b5cc6de5caa600aef SSZipArchive: fe6a26b2a54d5a0890f2567b5cc6de5caa600aef
Yoga: 99652481fcd320aefa4a7ef90095b95acd181952 Yoga: d3820731e0ca3a4933f061ad29defaf7726e3251
YogaKit: f782866e155069a2cca2517aafea43200b01fd5a YogaKit: f782866e155069a2cca2517aafea43200b01fd5a
PODFILE CHECKSUM: 3360a41d7ffd204bbb0ce92d9f9025f372649143 PODFILE CHECKSUM: 618d17df10f335f1d113daac849a7997894646b2
COCOAPODS: 1.11.3 COCOAPODS: 1.11.3

View File

@@ -1,6 +1,7 @@
const path = require('path'); const path = require('path');
const extraNodeModules = { const extraNodeModules = {
react: path.resolve(__dirname, 'node_modules/react'),
'react-native': path.resolve(__dirname, 'node_modules/react-native'), 'react-native': path.resolve(__dirname, 'node_modules/react-native'),
'react-native-update': path.resolve(__dirname, '../..'), 'react-native-update': path.resolve(__dirname, '../..'),
'@babel/runtime': path.resolve(__dirname, 'node_modules/@babel/runtime'), '@babel/runtime': path.resolve(__dirname, 'node_modules/@babel/runtime'),

View File

@@ -1,5 +1,5 @@
{ {
"name": "testhotupdate", "name": "testHotUpdate",
"version": "0.0.1", "version": "0.0.1",
"private": true, "private": true,
"scripts": { "scripts": {
@@ -7,23 +7,30 @@
"ios": "react-native run-ios", "ios": "react-native run-ios",
"start": "react-native start", "start": "react-native start",
"test": "jest", "test": "jest",
"test:e2e": "detox test --configuration android.emu.debug",
"lint": "eslint .", "lint": "eslint .",
"apk": "(cd android && ./gradlew aR)" "postinstall": "patch-package"
}, },
"dependencies": { "dependencies": {
"react": "17.0.2", "patch-package": "^6.5.1",
"react-native": "0.68.5", "postinstall-postinstall": "^2.1.0",
"react": "18.0.0",
"react-native": "0.69.8",
"react-native-update": "link:../.." "react-native-update": "link:../.."
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.12.9", "@babel/core": "^7.21.0",
"@babel/runtime": "^7.12.5", "@babel/runtime": "^7.21.0",
"@react-native-community/eslint-config": "^2.0.0", "@react-native-community/eslint-config": "^3.2.0",
"babel-jest": "^26.6.3", "babel-jest": "^29.5.0",
"eslint": "^7.32.0", "detox": "^20.5.0",
"jest": "^26.6.3", "eslint": "^8.36.0",
"metro-react-native-babel-preset": "^0.67.0", "jest": "^29.5.0",
"react-test-renderer": "17.0.2" "metro-react-native-babel-preset": "^0.76.0",
"pod-install": "^0.1.37",
"prettier": "^2.8.4",
"react-test-renderer": "18.2.0",
"ts-jest": "^29.0.5"
}, },
"jest": { "jest": {
"preset": "react-native" "preset": "react-native"

View File

@@ -0,0 +1,13 @@
diff --git a/node_modules/react-native/scripts/react_native_pods.rb b/node_modules/react-native/scripts/react_native_pods.rb
index e7c59ad..1461d45 100644
--- a/node_modules/react-native/scripts/react_native_pods.rb
+++ b/node_modules/react-native/scripts/react_native_pods.rb
@@ -420,7 +420,7 @@ def get_react_codegen_spec(options={})
'source' => { :git => '' },
'header_mappings_dir' => './',
'platforms' => {
- 'ios' => '11.0',
+ 'ios' => '12.0',
},
'source_files' => "**/*.{h,mm,cpp}",
'pod_target_xcconfig' => { "HEADER_SEARCH_PATHS" =>

View File

@@ -0,0 +1,10 @@
#!/usr/bin/env bash
trap 'kill $RN_PID' EXIT
PLATFORM=$1
kill -9 $(lsof -i :8081 | awk '{print $2}' | tail -n +2) & npm start &
RN_PID=$!
sleep 2 && curl>/dev/null http://localhost:8081/index.bundle
wait $RN_PID

View File

@@ -1,21 +1,146 @@
import React from 'react'; /* eslint-disable react-native/no-inline-styles */
/* eslint-disable react/react-in-jsx-scope */
import {useCallback, useMemo, useState} from 'react';
import { import {
ActivityIndicator, ActivityIndicator,
Alert,
Modal, Modal,
TextInput, TextInput,
Button, Button,
NativeModules,
StyleSheet, StyleSheet,
SafeAreaView, SafeAreaView,
Text, Text,
View, View,
TouchableOpacity,
} from 'react-native'; } from 'react-native';
const Pushy = NativeModules.Pushy; import {PushyModule} from 'react-native-update';
const Hash = '9D5CE6EBA420717BE7E7D308B11F8207681B066C951D68F3994D19828F342474';
const UUID = '00000000-0000-0000-0000-000000000000';
const DownloadUrl =
'http://cos.pgyer.com/697913e94d7441f20c686e2b0996a1aa.apk?sign=7a8f11b1df82cba45c8ac30b1acec88c&t=1680404102&response-content-disposition=attachment%3Bfilename%3DtestHotupdate_1.0.apk';
const CustomDialog = ({title, visible, onConfirm}) => {
if (!visible) {
return null;
}
return (
<View style={styles.overlay}>
<View style={styles.dialog}>
<Text style={styles.title}>{title}</Text>
<TouchableOpacity testID='done' style={styles.button} onLongPress={onConfirm}>
<Text style={styles.buttonText}>确认</Text>
</TouchableOpacity>
</View>
</View>
);
};
export default function TestConsole({visible}) { export default function TestConsole({visible}) {
const [text, setText] = React.useState(''); const [text, setText] = useState('');
const [running, setRunning] = React.useState(false); const [running, setRunning] = useState(false);
const [options, setOptions] = useState();
const [alertVisible, setAlertVisible] = useState(false);
const [alertMsg, setAlertMsg] = useState('');
const NativeTestMethod = useMemo(() => {
return [
{
name: 'setLocalHashInfo',
invoke: () => {
setText(
`setLocalHashInfo\n${Hash}\n{\"version\":\"1.0.0\",\"size\":\"19M\"}`,
);
},
},
{
name: 'getLocalHashInfo',
invoke: () => {
setText(`getLocalHashInfo\n${Hash}`);
},
},
{
name: 'setUuid',
invoke: () => {
setText(`setUuid\n${UUID}`);
},
},
{
name: 'setBlockUpdate',
invoke: () => {
setText('setBlockUpdate');
setOptions({reason: 'application has been block', until: 1673082950});
},
},
{
name: 'reloadUpdate',
invoke: () => {
setText('reloadUpdate');
setOptions({hash: Hash});
},
},
{
name: 'setNeedUpdate',
invoke: () => {
setText('setNeedUpdate');
setOptions({hash: Hash});
},
},
{
name: 'markSuccess',
invoke: () => {
setText('markSuccess');
setOptions(undefined);
},
},
{
name: 'downloadPatchFromPpk',
invoke: () => {
setText('downloadPatchFromPpk');
setOptions({updateUrl: DownloadUrl, hash: Hash, originHash: Hash});
},
},
{
name: 'downloadPatchFromPackage',
invoke: () => {
setText('downloadPatchFromPackage');
setOptions({updateUrl: DownloadUrl, hash: Hash});
},
},
{
name: 'downloadFullUpdate',
invoke: () => {
setText('downloadFullUpdate');
setOptions({updateUrl: DownloadUrl, hash: Hash});
},
},
{
name: 'downloadAndInstallApk',
invoke: () => {
setText('downloadAndInstallApk');
setOptions({url: DownloadUrl, target: Hash, hash: Hash});
},
},
];
}, []);
const renderTestView = useCallback(() => {
const views = [];
for (let i = 0; i < NativeTestMethod.length; i++) {
views.push(
<TouchableOpacity
key={i}
testID={NativeTestMethod[i].name}
onLongPress={() => {
NativeTestMethod[i].invoke();
}}
>
<Text>{NativeTestMethod[i].name}</Text>
</TouchableOpacity>,
);
}
return <View>{views}</View>;
}, [NativeTestMethod]);
return ( return (
<Modal visible={visible}> <Modal visible={visible}>
<SafeAreaView style={{flex: 1, padding: 10}}> <SafeAreaView style={{flex: 1, padding: 10}}>
@@ -38,39 +163,90 @@ export default function TestConsole({visible}) {
onChangeText={setText} onChangeText={setText}
/> />
{running && <ActivityIndicator />} {running && <ActivityIndicator />}
<Button <TouchableOpacity
title="执行" style={{backgroundColor:'rgb(0,140,237)', justifyContent: 'center',
onPress={async () => { alignItems: 'center',paddingTop:10,paddingBottom:10,marginBottom:5}}
testID="submit"
onLongPress={async () => {
setRunning(true); setRunning(true);
try { try {
const inputs = text.split('\n'); const inputs = text.split('\n');
const methodName = inputs[0]; const methodName = inputs[0];
let params; let params = [];
if (inputs.length === 1) { if (inputs.length === 1) {
await Pushy[methodName](); if (options) {
await PushyModule[methodName](options);
} else {
await PushyModule[methodName]();
}
} else { } else {
if (inputs.length === 2) { if (inputs.length === 2) {
params = inputs[1]; params = [inputs[1]];
} else { } else {
params = {}; params = [inputs[1], inputs[2]];
for (let i = 1; i < inputs.length; i += 2) {
params[inputs[i]] = inputs[i + 1];
}
console.log({inputs, params}); console.log({inputs, params});
} }
await Pushy[methodName](params); await PushyModule[methodName](...params);
} }
Alert.alert('done'); setAlertVisible(true);
setAlertMsg('done');
} catch (e) { } catch (e) {
Alert.alert(e.message); setAlertVisible(true);
setAlertMsg(e.message);
} }
setRunning(false); setRunning(false);
}} }}
/> >
<View style={{marginTop: 15}}> <Text style={{color:'white'}}>执行</Text>
<Button title="重置" onPress={() => setText('')} /> </TouchableOpacity>
</View> <Button title="重置" onPress={() => setText('')} />
{renderTestView()}
<CustomDialog
title={alertMsg}
visible={alertVisible}
onConfirm={()=>{setAlertVisible(false)}}
/>
</SafeAreaView> </SafeAreaView>
</Modal> </Modal>
); );
} }
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
overlay: {
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
backgroundColor: 'rgba(0, 0, 0, 0.5)',
justifyContent: 'center',
alignItems: 'center',
},
dialog: {
backgroundColor: 'white',
borderRadius: 10,
padding: 20,
width: '80%',
alignItems: 'center',
},
title: {
fontSize: 18,
fontWeight: 'bold',
marginBottom: 20,
},
button: {
backgroundColor: '#2196F3',
borderRadius: 5,
paddingVertical: 10,
paddingHorizontal: 20,
},
buttonText: {
color: 'white',
fontWeight: 'bold',
},
});

View File

@@ -170,6 +170,7 @@ export default class App extends Component {
</TouchableOpacity> </TouchableOpacity>
<TouchableOpacity <TouchableOpacity
testID="testcase"
style={{marginTop: 15}} style={{marginTop: 15}}
onLongPress={() => { onLongPress={() => {
this.setState({showTestConsole: true}); this.setState({showTestConsole: true});

View File

@@ -0,0 +1,10 @@
{
"ios": {
"appId": 10976,
"appKey": "p5q_rPYNOE0WdCf-i9ZCGPw-DUGUCMvY"
},
"android": {
"appId": 10977,
"appKey": "bUYKfZgtC9VirZsQbAt8qken2Gq2uxe3"
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -10,7 +10,7 @@
1. 基于阿里云高速 CDN 分发,对比其他服务器在国外的热更新服务,分发更稳定,更新成功率极高。 1. 基于阿里云高速 CDN 分发,对比其他服务器在国外的热更新服务,分发更稳定,更新成功率极高。
2. 基于 bsdiff/hdiff 算法创建的**超小更新包**,通常版本迭代后在几十 KB 级别(其他全量热更新服务所需流量通常在几十 MB 级别)。 2. 基于 bsdiff/hdiff 算法创建的**超小更新包**,通常版本迭代后在几十 KB 级别(其他全量热更新服务所需流量通常在几十 MB 级别)。
3. 始终跟进 RN 最新正式版本,第一时间提供支持。支持 hermes 字节码格式。(暂不支持新架构,会待其相对稳定后跟进) 3. 始终跟进 RN 最新正式版本,第一时间提供支持。支持 hermes 字节码格式。支持新架构
4. 跨越多个版本进行更新时,只需要下载**一个更新包**,不需要逐版本依次更新。 4. 跨越多个版本进行更新时,只需要下载**一个更新包**,不需要逐版本依次更新。
5. 命令行工具 & 网页双端管理,版本发布过程简单便捷,完全可以集成 CI。 5. 命令行工具 & 网页双端管理,版本发布过程简单便捷,完全可以集成 CI。
6. 支持崩溃回滚,安全可靠。 6. 支持崩溃回滚,安全可靠。
@@ -33,3 +33,4 @@ $ yarn start
本组件由[React Native 中文网](https://reactnative.cn/)独家发布,如有定制需求可以[联系我们](https://reactnative.cn/about.html#content)。 本组件由[React Native 中文网](https://reactnative.cn/)独家发布,如有定制需求可以[联系我们](https://reactnative.cn/about.html#content)。
关于此插件发现任何问题,可以前往[Issues](https://github.com/reactnativecn/react-native-pushy/issues)发帖提问。 关于此插件发现任何问题,可以前往[Issues](https://github.com/reactnativecn/react-native-pushy/issues)发帖提问。

View File

@@ -5,7 +5,15 @@ def safeExtGet(prop, fallback) {
rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
} }
def isNewArchitectureEnabled() {
return project.hasProperty("newArchEnabled") && project.newArchEnabled == "true"
}
apply plugin: 'com.android.library' apply plugin: 'com.android.library'
if (isNewArchitectureEnabled()) {
apply plugin: 'com.facebook.react'
}
android { android {
compileSdkVersion safeExtGet('compileSdkVersion', 28) compileSdkVersion safeExtGet('compileSdkVersion', 28)
@@ -17,11 +25,17 @@ android {
versionCode 1 versionCode 1
versionName "1.0" versionName "1.0"
consumerProguardFiles "proguard.pro" consumerProguardFiles "proguard.pro"
buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
} }
sourceSets { sourceSets {
main { main {
// let gradle pack the shared library into apk // let gradle pack the shared library into apk
jniLibs.srcDirs = ['./lib'] jniLibs.srcDirs = ['./lib']
if (isNewArchitectureEnabled()) {
java.srcDirs += ['src/newarch']
} else {
java.srcDirs += ['src/oldarch']
}
} }
} }
@@ -44,4 +58,12 @@ repositories {
dependencies { dependencies {
implementation 'com.facebook.react:react-native:+' implementation 'com.facebook.react:react-native:+'
implementation 'com.fasterxml.jackson.core:jackson-databind:2.13.0'
}
if (isNewArchitectureEnabled()) {
react {
jsRootDir = file("../lib/")
libraryName = "update"
codegenJavaPackageName = "cn.reactnative.modules.update"
}
} }

View File

@@ -1,7 +1,5 @@
package cn.reactnative.modules.update; package cn.reactnative.modules.update;
import android.content.Context;
import java.io.File; import java.io.File;
/** /**

View File

@@ -0,0 +1,265 @@
package cn.reactnative.modules.update;
import android.app.Activity;
import android.app.Application;
import android.util.Log;
import com.facebook.react.ReactApplication;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.bridge.JSBundleLoader;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.UiThreadUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.json.JSONObject;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class UpdateModuleImpl {
public static final String NAME = "Pushy";
public static void downloadFullUpdate(UpdateContext updateContext, ReadableMap options, Promise promise) {
String url = options.getString("updateUrl");
String hash = options.getString("hash");
updateContext.downloadFullUpdate(url, hash, new UpdateContext.DownloadFileListener() {
@Override
public void onDownloadCompleted(DownloadTaskParams params) {
promise.resolve(null);
}
@Override
public void onDownloadFailed(Throwable error) {
promise.reject(error);
}
});
}
public static void downloadAndInstallApk(UpdateContext updateContext, ReadableMap options, Promise promise) {
String url = options.getString("url");
String hash = options.getString("hash");
String target = options.getString("target");
updateContext.downloadFile(url, hash, target, new UpdateContext.DownloadFileListener() {
@Override
public void onDownloadCompleted(DownloadTaskParams params) {
UpdateModule.installApk(params.targetFile);
promise.resolve(null);
}
@Override
public void onDownloadFailed(Throwable error) {
promise.reject(error);
}
});
}
public static void installApk(String url) {
File toInstall = new File(url);
UpdateModule.installApk(toInstall);
}
public static void downloadPatchFromPackage(UpdateContext updateContext, ReadableMap options, Promise promise) {
String url = options.getString("updateUrl");
String hash = options.getString("hash");
updateContext.downloadPatchFromApk(url, hash, new UpdateContext.DownloadFileListener() {
@Override
public void onDownloadCompleted(DownloadTaskParams params) {
promise.resolve(null);
}
@Override
public void onDownloadFailed(Throwable error) {
promise.reject(error);
}
});
}
public static void downloadPatchFromPpk(UpdateContext updateContext, ReadableMap options, Promise promise) {
try {
String url = options.getString("updateUrl");
String hash = options.getString("hash");
String originHash = options.getString("originHash");
updateContext.downloadPatchFromPpk(url, hash, originHash, new UpdateContext.DownloadFileListener() {
@Override
public void onDownloadCompleted(DownloadTaskParams params) {
promise.resolve(null);
}
@Override
public void onDownloadFailed(Throwable error) {
promise.reject(error);
}
});
}catch (Exception e){
promise.reject("执行报错:"+e.getMessage());
}
}
public static void reloadUpdate(UpdateContext updateContext, ReactApplicationContext mContext, ReadableMap options,Promise promise) {
final String hash = options.getString("hash");
if(hash==null || hash.isEmpty()){
promise.reject("hash不能为空");
return;
}
UiThreadUtil.runOnUiThread(new Runnable() {
@Override
public void run() {
try {
updateContext.switchVersion(hash);
Activity activity = mContext.getCurrentActivity();
Application application = activity.getApplication();
ReactInstanceManager instanceManager = updateContext.getCustomReactInstanceManager();
if (instanceManager == null) {
instanceManager = ((ReactApplication) application).getReactNativeHost().getReactInstanceManager();
}
try {
JSBundleLoader loader = JSBundleLoader.createFileLoader(UpdateContext.getBundleUrl(application));
Field loadField = instanceManager.getClass().getDeclaredField("mBundleLoader");
loadField.setAccessible(true);
loadField.set(instanceManager, loader);
} catch (Throwable err) {
promise.reject("pushy:"+err.getMessage());
Field jsBundleField = instanceManager.getClass().getDeclaredField("mJSBundleFile");
jsBundleField.setAccessible(true);
jsBundleField.set(instanceManager, UpdateContext.getBundleUrl(application));
}
try {
instanceManager.recreateReactContextInBackground();
promise.resolve(true);
} catch (Throwable err) {
promise.reject("pushy:"+err.getMessage());
activity.recreate();
}
} catch (Throwable err) {
promise.reject("pushy:switchVersion failed"+err.getMessage());
Log.e("pushy", "switchVersion failed", err);
}
}
});
}
public static void setNeedUpdate(UpdateContext updateContext, ReadableMap options,Promise promise) {
try {
final String hash = options.getString("hash");
if(hash==null || hash.isEmpty()){
promise.reject("hash不能为空");
return;
}
UiThreadUtil.runOnUiThread(new Runnable() {
@Override
public void run() {
try {
updateContext.switchVersion(hash);
promise.resolve(true);
} catch (Throwable err) {
promise.reject("switchVersionLater failed:"+err.getMessage());
Log.e("pushy", "switchVersionLater failed", err);
}
}
});
}catch (Exception e){
promise.reject("执行报错:"+e.getMessage());
}
}
public static void markSuccess(UpdateContext updateContext,Promise promise) {
try {
UiThreadUtil.runOnUiThread(new Runnable() {
@Override
public void run() {
updateContext.markSuccess();
promise.resolve(true);
}
});
}catch (Exception e){
promise.reject("执行报错:"+e.getMessage());
}
}
public static void setBlockUpdate(UpdateContext updateContext, ReadableMap options,Promise promise) {
try {
final int until = options.getInt("until");
final String reason = options.getString("reason");
UiThreadUtil.runOnUiThread(new Runnable() {
@Override
public void run() {
updateContext.setBlockUpdate(until, reason);
}
});
promise.resolve(true);
}catch (Exception e){
promise.reject("执行报错:"+e.getMessage());
}
}
public static void setUuid(UpdateContext updateContext, String uuid, Promise promise) {
try {
UiThreadUtil.runOnUiThread(new Runnable() {
@Override
public void run() {
updateContext.setKv("uuid", uuid);
promise.resolve(true);
}
});
}catch (Exception e){
promise.reject("执行报错:"+e.getMessage());
}
}
public static boolean check(String json) {
ObjectMapper mapper = new ObjectMapper();
try {
mapper.readValue(json, Map.class);
System.out.println("String can be converted to Map");
return true;
} catch (IOException e) {
System.out.println("String cannot be converted to Map");
return false;
}
}
public static void setLocalHashInfo(UpdateContext updateContext, final String hash, final String info, Promise promise) {
UiThreadUtil.runOnUiThread(new Runnable() {
@Override
public void run() {
if(!check(info)){
updateContext.setKv("hash_" + hash, info);
promise.reject("校验报错:json字符串格式错误");
}else {
updateContext.setKv("hash_" + hash, info);
promise.resolve(true);
}
}
});
}
public static void getLocalHashInfo(UpdateContext updateContext, final String hash, Promise promise) {
String value = updateContext.getKv("hash_" + hash);
if(check(value)){
promise.resolve(value);
}else {
promise.reject("校验报错:json字符串格式错误");
}
}
}

View File

@@ -1,34 +1,45 @@
package cn.reactnative.modules.update; package cn.reactnative.modules.update;
import com.facebook.react.ReactPackage; import androidx.annotation.Nullable;
import com.facebook.react.bridge.JavaScriptModule; import com.facebook.react.TurboReactPackage;
import com.facebook.react.bridge.NativeModule; import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager; import com.facebook.react.module.model.ReactModuleInfo;
import com.facebook.react.module.model.ReactModuleInfoProvider;
import java.util.Arrays; import java.util.HashMap;
import java.util.Collections; import java.util.Map;
import java.util.List;
/** /**
* Created by tdzl2003 on 3/31/16. * Created by tdzl2003 on 3/31/16.
*/ */
public class UpdatePackage implements ReactPackage { public class UpdatePackage extends TurboReactPackage {
@Nullable
@Override @Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) { public NativeModule getModule(String name, ReactApplicationContext reactContext) {
return Arrays.asList(new NativeModule[]{ if (name.equals(UpdateModuleImpl.NAME)) {
// Modules from third-party return new UpdateModule(reactContext);
new UpdateModule(reactContext), } else {
}); return null;
} }
public List<Class<? extends JavaScriptModule>> createJSModules() {
return Collections.emptyList();
} }
@Override @Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) { public ReactModuleInfoProvider getReactModuleInfoProvider() {
return Collections.emptyList(); return () -> {
final Map<String, ReactModuleInfo> moduleInfos = new HashMap<>();
boolean isTurboModule = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED;
moduleInfos.put(
UpdateModuleImpl.NAME,
new ReactModuleInfo(
UpdateModuleImpl.NAME,
UpdateModuleImpl.NAME,
false, // canOverrideExistingModule
false, // needsEagerInit
true, // hasConstants
false, // isCxxModule
isTurboModule // isTurboModule
));
return moduleInfos;
};
} }
} }

View File

@@ -0,0 +1,147 @@
package cn.reactnative.modules.update;
import static androidx.core.content.FileProvider.getUriForFile;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.modules.core.DeviceEventManagerModule;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
public class UpdateModule extends NativeUpdateSpec {
UpdateContext updateContext;
public static ReactApplicationContext mContext;
public UpdateModule(ReactApplicationContext reactContext, UpdateContext updateContext) {
super(reactContext);
this.updateContext = updateContext;
mContext = reactContext;
}
public UpdateModule(ReactApplicationContext reactContext) {
this(reactContext, new UpdateContext(reactContext.getApplicationContext()));
}
@Override
protected Map<String, Object> getTypedExportedConstants() {
final Map<String, Object> constants = new HashMap<>();
constants.put("downloadRootDir", updateContext.getRootDir());
constants.put("packageVersion", updateContext.getPackageVersion());
constants.put("currentVersion", updateContext.getCurrentVersion());
constants.put("buildTime", updateContext.getBuildTime());
constants.put("isUsingBundleUrl", updateContext.getIsUsingBundleUrl());
boolean isFirstTime = updateContext.isFirstTime();
constants.put("isFirstTime", isFirstTime);
if (isFirstTime) {
updateContext.clearFirstTime();
}
String rolledBackVersion = updateContext.rolledBackVersion();
constants.put("rolledBackVersion", rolledBackVersion);
if (rolledBackVersion != null) {
updateContext.clearRollbackMark();
}
constants.put("blockUpdate", updateContext.getBlockUpdate());
constants.put("uuid", updateContext.getKv("uuid"));
return constants;
}
@Override
public String getName() {
return UpdateModuleImpl.NAME;
}
@Override
public void downloadFullUpdate(ReadableMap options, final Promise promise) {
UpdateModuleImpl.downloadFullUpdate(this.updateContext,options,promise);
}
@Override
public void downloadAndInstallApk(ReadableMap options, final Promise promise) {
UpdateModuleImpl.downloadAndInstallApk(this.updateContext,options,promise);
}
public static void installApk(File toInstall) {
Uri apkUri;
Intent intent;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
apkUri = getUriForFile(mContext, mContext.getPackageName() + ".pushy.fileprovider", toInstall);
intent = new Intent(Intent.ACTION_INSTALL_PACKAGE);
intent.setData(apkUri);
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
} else {
apkUri = Uri.fromFile(toInstall);
intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
mContext.startActivity(intent);
}
@Override
public void downloadPatchFromPackage(ReadableMap options, final Promise promise) {
UpdateModuleImpl.downloadPatchFromPackage(updateContext,options,promise);
}
@Override
public void downloadPatchFromPpk(ReadableMap options, final Promise promise) {
UpdateModuleImpl.downloadPatchFromPpk(updateContext,options,promise);
}
@Override
public void reloadUpdate(ReadableMap options,Promise promise) {
UpdateModuleImpl.reloadUpdate(updateContext, mContext, options,promise);
}
@Override
public void setNeedUpdate(ReadableMap options,Promise promise) {
UpdateModuleImpl.setNeedUpdate(updateContext, options,promise);
}
@Override
public void markSuccess(Promise promise) {
UpdateModuleImpl.markSuccess(updateContext,promise);
}
@Override
public void setBlockUpdate(ReadableMap options,Promise promise) {
UpdateModuleImpl.setBlockUpdate(updateContext,options,promise);
}
@Override
public void setUuid(final String uuid, Promise promise) {
UpdateModuleImpl.setUuid(updateContext,uuid,promise);
}
@Override
public void setLocalHashInfo(final String hash, final String info, final Promise promise) {
UpdateModuleImpl.setLocalHashInfo(updateContext,hash,info,promise);
}
@Override
public void getLocalHashInfo(final String hash, final Promise promise) {
UpdateModuleImpl.getLocalHashInfo(updateContext,hash,promise);
}
@Override
public void addListener(String eventName) {
// Set up any upstream listeners or background tasks as necessary
}
@Override
public void removeListeners(double count) {
// Remove upstream listeners, stop unnecessary background tasks
}
/* 发送事件*/
public static void sendEvent(String eventName, WritableMap params) {
((ReactContext) mContext).getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit(eventName,
params);
}
}

View File

@@ -66,7 +66,7 @@ public class UpdateModule extends ReactContextBaseJavaModule {
@Override @Override
public String getName() { public String getName() {
return "RCTPushy"; return UpdateModuleImpl.NAME;
} }
@ReactMethod @ReactMethod
@@ -169,7 +169,7 @@ public class UpdateModule extends ReactContextBaseJavaModule {
} }
@ReactMethod @ReactMethod
public void reloadUpdate(ReadableMap options) { public void reloadUpdate(ReadableMap options, final Promise promise) {
final String hash = options.getString("hash"); final String hash = options.getString("hash");
UiThreadUtil.runOnUiThread(new Runnable() { UiThreadUtil.runOnUiThread(new Runnable() {
@@ -191,6 +191,7 @@ public class UpdateModule extends ReactContextBaseJavaModule {
loadField.setAccessible(true); loadField.setAccessible(true);
loadField.set(instanceManager, loader); loadField.set(instanceManager, loader);
} catch (Throwable err) { } catch (Throwable err) {
promise.reject(err);
Field jsBundleField = instanceManager.getClass().getDeclaredField("mJSBundleFile"); Field jsBundleField = instanceManager.getClass().getDeclaredField("mJSBundleFile");
jsBundleField.setAccessible(true); jsBundleField.setAccessible(true);
jsBundleField.set(instanceManager, UpdateContext.getBundleUrl(application)); jsBundleField.set(instanceManager, UpdateContext.getBundleUrl(application));
@@ -198,11 +199,14 @@ public class UpdateModule extends ReactContextBaseJavaModule {
try { try {
instanceManager.recreateReactContextInBackground(); instanceManager.recreateReactContextInBackground();
promise.resolve(null);
} catch (Throwable err) { } catch (Throwable err) {
activity.recreate(); activity.recreate();
promise.reject(err);
} }
} catch (Throwable err) { } catch (Throwable err) {
promise.reject(err);
Log.e("pushy", "switchVersion failed", err); Log.e("pushy", "switchVersion failed", err);
} }
} }

12
e2e/jest.config.js Normal file
View File

@@ -0,0 +1,12 @@
/** @type {import('@jest/types').Config.InitialOptions} */
module.exports = {
rootDir: '..',
testMatch: ['<rootDir>/e2e/**/*.test.js'],
testTimeout: 120000,
maxWorkers: 1,
globalSetup: 'detox/runners/jest/globalSetup',
globalTeardown: 'detox/runners/jest/globalTeardown',
reporters: ['detox/runners/jest/reporter'],
testEnvironment: 'detox/runners/jest/testEnvironment',
verbose: true,
};

23
e2e/starter.test.js Normal file
View File

@@ -0,0 +1,23 @@
describe('Example', () => {
beforeAll(async () => {
await device.launchApp();
});
beforeEach(async () => {
await device.reloadReactNative();
});
it('should have welcome screen', async () => {
await expect(element(by.id('welcome'))).toBeVisible();
});
it('should show hello screen after tap', async () => {
await element(by.id('hello_button')).tap();
await expect(element(by.text('Hello!!!'))).toBeVisible();
});
it('should show world screen after tap', async () => {
await element(by.id('world_button')).tap();
await expect(element(by.text('World!!!'))).toBeVisible();
});
});

View File

@@ -1,7 +1,10 @@
#import "RCTPushy.h" #import "RCTPushy.h"
#import "RCTPushyDownloader.h" #import "RCTPushyDownloader.h"
#import "RCTPushyManager.h" #import "RCTPushyManager.h"
// Thanks to this guard, we won't import this header when we build for the old architecture.
#ifdef RCT_NEW_ARCH_ENABLED
#import "RCTPushySpec.h"
#endif
#import <React/RCTConvert.h> #import <React/RCTConvert.h>
#import <React/RCTLog.h> #import <React/RCTLog.h>
@@ -189,29 +192,53 @@ RCT_EXPORT_MODULE(RCTPushy);
return self; return self;
} }
RCT_EXPORT_METHOD(setBlockUpdate:(NSDictionary *)options) RCT_EXPORT_METHOD(setBlockUpdate:(NSDictionary *)options
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject)
{ {
// NSMutableDictionary *blockUpdateInfo = [NSMutableDictionary new]; // NSMutableDictionary *blockUpdateInfo = [NSMutableDictionary new];
// blockUpdateInfo[@"reason"] = options[@"reason"]; // blockUpdateInfo[@"reason"] = options[@"reason"];
// blockUpdateInfo[@"until"] = options[@"until"]; // blockUpdateInfo[@"until"] = options[@"until"];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; @try {
[defaults setObject:options forKey:keyBlockUpdate]; NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults synchronize]; [defaults setObject:options forKey:keyBlockUpdate];
[defaults synchronize];
resolve(@true);
}
@catch (NSException *exception) {
reject(@"执行报错", nil, nil);
}
} }
RCT_EXPORT_METHOD(setUuid:(NSString *)uuid) RCT_EXPORT_METHOD(setUuid:(NSString *)uuid resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject)
{ {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; @try {
[defaults setObject:uuid forKey:keyUuid]; NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults synchronize]; [defaults setObject:uuid forKey:keyUuid];
[defaults synchronize];
resolve(@true);
}
@catch (NSException *exception) {
reject(@"json格式校验报错", nil, nil);
}
} }
RCT_EXPORT_METHOD(setLocalHashInfo:(NSString *)hash RCT_EXPORT_METHOD(setLocalHashInfo:(NSString *)hash
value:(NSString *)value) value:(NSString *)value resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject)
{ {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; NSData *data = [value dataUsingEncoding:NSUTF8StringEncoding];
[defaults setObject:value forKey:[keyHashInfo stringByAppendingString:hash]]; NSError *error = nil;
[defaults synchronize]; id object = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
if (object && [object isKindOfClass:[NSDictionary class]]) {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:value forKey:[keyHashInfo stringByAppendingString:hash]];
[defaults synchronize];
resolve(@true);
} else {
reject(@"json格式校验报错", nil, nil);
}
} }
@@ -266,7 +293,9 @@ RCT_EXPORT_METHOD(downloadPatchFromPpk:(NSDictionary *)options
}]; }];
} }
RCT_EXPORT_METHOD(setNeedUpdate:(NSDictionary *)options) RCT_EXPORT_METHOD(setNeedUpdate:(NSDictionary *)options
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject)
{ {
NSString *hash = options[@"hash"]; NSString *hash = options[@"hash"];
@@ -287,45 +316,66 @@ RCT_EXPORT_METHOD(setNeedUpdate:(NSDictionary *)options)
[defaults setObject:newInfo forKey:keyPushyInfo]; [defaults setObject:newInfo forKey:keyPushyInfo];
[defaults synchronize]; [defaults synchronize];
resolve(@true);
}else{
reject(@"执行报错", nil, nil);
} }
} }
RCT_EXPORT_METHOD(reloadUpdate:(NSDictionary *)options) RCT_EXPORT_METHOD(reloadUpdate:(NSDictionary *)options
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject)
{ {
NSString *hash = options[@"hash"]; @try {
NSString *hash = options[@"hash"];
if (hash.length) {
[self setNeedUpdate:options resolver:resolve rejecter:reject];
if (hash.length) { // reload 0.62+
[self setNeedUpdate:options]; // RCTReloadCommandSetBundleURL([[self class] bundleURL]);
// RCTTriggerReloadCommandListeners(@"pushy reload");
// reload 0.62+ dispatch_async(dispatch_get_main_queue(), ^{
// RCTReloadCommandSetBundleURL([[self class] bundleURL]); [self.bridge setValue:[[self class] bundleURL] forKey:@"bundleURL"];
// RCTTriggerReloadCommandListeners(@"pushy reload"); [self.bridge reload];
});
dispatch_async(dispatch_get_main_queue(), ^{ resolve(@true);
[self.bridge setValue:[[self class] bundleURL] forKey:@"bundleURL"]; }else{
[self.bridge reload]; reject(@"执行报错", nil, nil);
}); }
}
@catch (NSException *exception) {
reject(@"执行报错", nil, nil);
} }
} }
RCT_EXPORT_METHOD(markSuccess) RCT_EXPORT_METHOD(markSuccess:
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject)
{ {
// up package info
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSMutableDictionary *pushyInfo = [[NSMutableDictionary alloc] initWithDictionary:[defaults objectForKey:keyPushyInfo]];
[pushyInfo setObject:@(NO) forKey:paramIsFirstTime];
[pushyInfo setObject:@(YES) forKey:paramIsFirstLoadOk];
NSString *lastVersion = pushyInfo[paramLastVersion]; @try {
NSString *curVersion = pushyInfo[paramCurrentVersion]; // up package info
if (lastVersion != nil && ![lastVersion isEqualToString:curVersion]) { NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[pushyInfo removeObjectForKey:[keyHashInfo stringByAppendingString:lastVersion]]; NSMutableDictionary *pushyInfo = [[NSMutableDictionary alloc] initWithDictionary:[defaults objectForKey:keyPushyInfo]];
[pushyInfo setObject:@(NO) forKey:paramIsFirstTime];
[pushyInfo setObject:@(YES) forKey:paramIsFirstLoadOk];
NSString *lastVersion = pushyInfo[paramLastVersion];
NSString *curVersion = pushyInfo[paramCurrentVersion];
if (lastVersion != nil && ![lastVersion isEqualToString:curVersion]) {
[pushyInfo removeObjectForKey:[keyHashInfo stringByAppendingString:lastVersion]];
}
[defaults setObject:pushyInfo forKey:keyPushyInfo];
[defaults synchronize];
// clear other package dir
[self clearInvalidFiles];
resolve(@true);
}
@catch (NSException *exception) {
reject(@"执行报错", nil, nil);
} }
[defaults setObject:pushyInfo forKey:keyPushyInfo];
[defaults synchronize];
// clear other package dir
[self clearInvalidFiles];
} }
@@ -351,6 +401,19 @@ RCT_EXPORT_METHOD(markSuccess)
// Remove upstream listeners, stop unnecessary background tasks // Remove upstream listeners, stop unnecessary background tasks
} }
- (BOOL) isBlankString:(NSString *)string {
if (string == nil || string == NULL) {
return YES;
}
if ([string isKindOfClass:[NSNull class]]) {
return YES;
}
if ([[string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] length]==0) {
return YES;
}
return NO;
}
- (void)doPushy:(PushyType)type options:(NSDictionary *)options callback:(void (^)(NSError *error))callback - (void)doPushy:(PushyType)type options:(NSDictionary *)options callback:(void (^)(NSError *error))callback
{ {
@@ -362,7 +425,7 @@ RCT_EXPORT_METHOD(markSuccess)
return; return;
} }
NSString *originHash = [RCTConvert NSString:options[@"originHash"]]; NSString *originHash = [RCTConvert NSString:options[@"originHash"]];
if (type == PushyTypePatchFromPpk && originHash <= 0) { if (type == PushyTypePatchFromPpk && [self isBlankString:originHash]) {
callback([self errorWithMessage:ERROR_OPTIONS]); callback([self errorWithMessage:ERROR_OPTIONS]);
return; return;
} }
@@ -562,4 +625,13 @@ RCT_EXPORT_METHOD(markSuccess)
#endif #endif
} }
// Thanks to this guard, we won't compile this code when we build for the old architecture.
#ifdef RCT_NEW_ARCH_ENABLED
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
(const facebook::react::ObjCTurboModule::InitParams &)params
{
return std::make_shared<facebook::react::NativeUpdateSpecJSI>(params);
}
#endif
@end @end

View File

@@ -1 +1 @@
1574665292 1680488830

45
lib/NativeUpdate.ts Normal file
View File

@@ -0,0 +1,45 @@
import type { TurboModule } from 'react-native/Libraries/TurboModule/RCTExport';
import { TurboModuleRegistry } from 'react-native';
export interface Spec extends TurboModule {
getConstants: () => {
downloadRootDir: string;
packageVersion: string;
currentVersion: string;
isFirstTime: boolean;
rolledBackVersion: string;
buildTime: string;
blockUpdate: Object;
uuid: string;
isUsingBundleUrl: boolean;
};
setLocalHashInfo(hash: string, info: string): Promise<void>;
getLocalHashInfo(hash: string): Promise<string>;
setUuid(uuid: string): Promise<void>;
setBlockUpdate(options: { reason: string; until: number }): Promise<void>;
reloadUpdate(options: { hash: string }): Promise<void>;
setNeedUpdate(options: { hash: string }): Promise<void>;
markSuccess(): Promise<void>;
downloadPatchFromPpk(options: {
updateUrl: string;
hash: string;
originHash: string;
}): Promise<void>;
downloadPatchFromPackage(options: {
updateUrl: string;
hash: string;
}): Promise<void>;
downloadFullUpdate(options: {
updateUrl: string;
hash: string;
}): Promise<void>;
downloadAndInstallApk(options: {
url: string;
target: string;
hash: string;
}): Promise<void>;
addListener(eventName: string): void;
removeListeners(count: number): void;
}
export default TurboModuleRegistry.get<Spec>('Pushy') as Spec | null;

View File

@@ -1,6 +1,6 @@
let currentEndpoint = 'https://update.react-native.cn/api'; let currentEndpoint = 'https://update.react-native.cn/api';
function ping(url, rejectImmediate) { function ping(url: string, rejectImmediate?: boolean) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest(); const xhr = new XMLHttpRequest();
xhr.onreadystatechange = (e) => { xhr.onreadystatechange = (e) => {
@@ -20,12 +20,12 @@ function ping(url, rejectImmediate) {
}); });
} }
function logger(...args) { function logger(...args: any[]) {
// console.warn('pushy', ...args); console.log('Pushy: ', ...args);
} }
let backupEndpoints = []; let backupEndpoints: string[] = [];
let backupEndpointsQueryUrl = let backupEndpointsQueryUrl: string | null =
'https://cdn.jsdelivr.net/gh/reactnativecn/react-native-pushy@master/endpoints.json'; 'https://cdn.jsdelivr.net/gh/reactnativecn/react-native-pushy@master/endpoints.json';
export async function tryBackupEndpoints() { export async function tryBackupEndpoints() {
@@ -34,10 +34,10 @@ export async function tryBackupEndpoints() {
} }
try { try {
await ping(getStatusUrl(), true); await ping(getStatusUrl(), true);
logger('current endpoint ok'); logger('current endpoint ok', currentEndpoint);
return; return;
} catch (e) { } catch (e) {
logger('current endpoint failed'); logger('current endpoint failed', currentEndpoint);
} }
if (!backupEndpoints.length && backupEndpointsQueryUrl) { if (!backupEndpoints.length && backupEndpointsQueryUrl) {
try { try {
@@ -76,11 +76,21 @@ export function getCheckUrl(APPKEY, endpoint = currentEndpoint) {
return `${endpoint}/checkUpdate/${APPKEY}`; return `${endpoint}/checkUpdate/${APPKEY}`;
} }
export function getReportUrl(endpoint = currentEndpoint) { /**
return `${endpoint}/report`; * @param {string} main - The main api endpoint
} * @param {string[]} [backups] - The back up endpoints.
* @param {string} [backupQueryUrl] - An url that return a json file containing an array of endpoint.
export function setCustomEndpoints({ main, backups, backupQueryUrl }) { * like: ["https://backup.api/1", "https://backup.api/2"]
*/
export function setCustomEndpoints({
main,
backups,
backupQueryUrl,
}: {
main: string;
backups?: string[];
backupQueryUrl?: string;
}) {
currentEndpoint = main; currentEndpoint = main;
backupEndpointsQueryUrl = null; backupEndpointsQueryUrl = null;
if (Array.isArray(backups) && backups.length > 0) { if (Array.isArray(backups) && backups.length > 0) {

94
lib/index.d.ts vendored
View File

@@ -1,94 +0,0 @@
export const downloadRootDir: string;
export const packageVersion: string;
export const currentVersion: string;
export const isFirstTime: boolean;
export const isRolledBack: boolean;
export interface ExpiredResult {
upToDate?: false;
expired: true;
downloadUrl: string;
}
export interface UpTodateResult {
expired?: false;
upToDate: true;
paused?: 'app' | 'package';
}
export interface UpdateAvailableResult {
expired?: false;
upToDate?: false;
update: true;
name: string; // version name
hash: string;
description: string;
metaInfo: string;
pdiffUrl: string;
diffUrl?: string;
}
export type CheckResult =
| ExpiredResult
| UpTodateResult
| UpdateAvailableResult;
export function checkUpdate(appkey: string): Promise<CheckResult>;
export function downloadUpdate(
info: UpdateAvailableResult,
eventListeners?: {
onDownloadProgress?: (data: ProgressData) => void;
},
): Promise<undefined | string>;
export function switchVersion(hash: string): void;
export function switchVersionLater(hash: string): void;
export function markSuccess(): void;
export function downloadAndInstallApk({
url,
onDownloadProgress,
}: {
url: string;
onDownloadProgress?: (data: ProgressData) => void;
}): Promise<void>;
/**
* @param {string} main - The main api endpoint
* @param {string[]} [backups] - The back up endpoints.
* @param {string} [backupQueryUrl] - An url that return a json file containing an array of endpoint.
* like: ["https://backup.api/1", "https://backup.api/2"]
*/
export function setCustomEndpoints({
main,
backups,
backupQueryUrl,
}: {
main: string;
backups?: string[];
backupQueryUrl?: string;
}): void;
export function getCurrentVersionInfo(): Promise<{
name?: string;
description?: string;
metaInfo?: string;
}>;
interface ProgressData {
hash: string;
received: number;
total: number;
}
interface SimpleUpdateOptions {
appKey: string;
}
export function simpleUpdate(
wrappedComponent: any,
options: SimpleUpdateOptions,
): any;

View File

@@ -15,3 +15,4 @@ export const downloadAndInstallApk = noop;
export const setCustomEndpoints = noop; export const setCustomEndpoints = noop;
export const getCurrentVersionInfo = noop; export const getCurrentVersionInfo = noop;
export const simpleUpdate = noop; export const simpleUpdate = noop;
export const onEvents = noop;

View File

@@ -2,7 +2,6 @@ import {
tryBackupEndpoints, tryBackupEndpoints,
getCheckUrl, getCheckUrl,
setCustomEndpoints, setCustomEndpoints,
getReportUrl,
} from './endpoint'; } from './endpoint';
import { import {
NativeEventEmitter, NativeEventEmitter,
@@ -10,82 +9,115 @@ import {
Platform, Platform,
PermissionsAndroid, PermissionsAndroid,
} from 'react-native'; } from 'react-native';
import {
CheckResult,
EventType,
ProgressData,
UpdateAvailableResult,
UpdateEventsListener,
} from './type';
export { setCustomEndpoints }; export { setCustomEndpoints };
const { const {
version: v, version: v,
} = require('react-native/Libraries/Core/ReactNativeVersion'); } = require('react-native/Libraries/Core/ReactNativeVersion');
const RNVersion = `${v.major}.${v.minor}.${v.patch}`; const RNVersion = `${v.major}.${v.minor}.${v.patch}`;
const isTurboModuleEnabled = global.__turboModuleProxy != null;
let Pushy = NativeModules.Pushy; export const PushyModule = isTurboModuleEnabled
? require('./NativeUpdate').default
: NativeModules.Pushy;
if (!Pushy) { if (!PushyModule) {
throw new Error('react-native-update模块无法加载请对照安装文档检查配置。'); throw new Error('react-native-update模块无法加载请对照安装文档检查配置。');
} }
const PushyConstants = isTurboModuleEnabled
? PushyModule.getConstants()
: PushyModule;
export const downloadRootDir = Pushy.downloadRootDir; export const downloadRootDir = PushyConstants.downloadRootDir;
export const packageVersion = Pushy.packageVersion; export const packageVersion = PushyConstants.packageVersion;
export const currentVersion = Pushy.currentVersion; export const currentVersion = PushyConstants.currentVersion;
export const isFirstTime = Pushy.isFirstTime; export const isFirstTime = PushyConstants.isFirstTime;
const rolledBackVersion = Pushy.rolledBackVersion; const rolledBackVersion = PushyConstants.rolledBackVersion;
export const isRolledBack = typeof rolledBackVersion === 'string'; export const isRolledBack = typeof rolledBackVersion === 'string';
export const buildTime = Pushy.buildTime; export const buildTime = PushyConstants.buildTime;
let blockUpdate = Pushy.blockUpdate; let blockUpdate = PushyConstants.blockUpdate;
let uuid = Pushy.uuid; let uuid = PushyConstants.uuid;
if (Platform.OS === 'android' && !Pushy.isUsingBundleUrl) { if (Platform.OS === 'android' && !PushyConstants.isUsingBundleUrl) {
throw new Error( throw new Error(
'react-native-update模块无法加载请对照文档检查Bundle URL的配置', 'react-native-update模块无法加载请对照文档检查Bundle URL的配置',
); );
} }
function setLocalHashInfo(hash, info) { function setLocalHashInfo(hash: string, info: Record<string, any>) {
Pushy.setLocalHashInfo(hash, JSON.stringify(info)); PushyModule.setLocalHashInfo(hash, JSON.stringify(info));
} }
async function getLocalHashInfo(hash) { async function getLocalHashInfo(hash: string) {
return JSON.parse(await Pushy.getLocalHashInfo(hash)); return JSON.parse(await PushyModule.getLocalHashInfo(hash));
} }
export async function getCurrentVersionInfo() { export async function getCurrentVersionInfo(): Promise<{
name?: string;
description?: string;
metaInfo?: string;
}> {
return currentVersion ? (await getLocalHashInfo(currentVersion)) || {} : {}; return currentVersion ? (await getLocalHashInfo(currentVersion)) || {} : {};
} }
const eventEmitter = new NativeEventEmitter(Pushy); const eventEmitter = new NativeEventEmitter(PushyModule);
if (!uuid) { if (!uuid) {
uuid = require('nanoid/non-secure').nanoid(); uuid = require('nanoid/non-secure').nanoid();
Pushy.setUuid(uuid); PushyModule.setUuid(uuid);
} }
function logger(text) { function logger(...args: string[]) {
console.log(`Pushy: ${text}`); console.log('Pushy: ', ...args);
} }
function report(hash, type) { const noop = () => {};
logger(type); let reporter: UpdateEventsListener = noop;
fetch(getReportUrl(), {
method: 'POST', export function onEvents(customReporter: UpdateEventsListener) {
headers: { reporter = customReporter;
Accept: 'application/json', if (isRolledBack) {
'Content-Type': 'application/json', report({
}, type: 'rollback',
body: JSON.stringify({ data: {
hash, rolledBackVersion,
type, },
});
}
}
function report({
type,
message = '',
data = {},
}: {
type: EventType;
message?: string;
data?: Record<string, string | number>;
}) {
logger(type + ' ' + message);
reporter({
type,
data: {
currentVersion,
cInfo, cInfo,
packageVersion, packageVersion,
buildTime, buildTime,
}), message,
}).catch((_e) => {}); ...data,
},
});
} }
logger('uuid: ' + uuid); logger('uuid: ' + uuid);
if (isRolledBack) {
report(rolledBackVersion, 'rollback');
}
export const cInfo = { export const cInfo = {
pushy: require('../package.json').version, pushy: require('../package.json').version,
rn: RNVersion, rn: RNVersion,
@@ -99,28 +131,27 @@ function assertRelease() {
} }
} }
let checkingThrottling = false; let lastChecking;
export async function checkUpdate(APPKEY, isRetry) { const empty = {};
let lastResult: CheckResult;
export async function checkUpdate(APPKEY: string, isRetry?: boolean) {
assertRelease(); assertRelease();
if (checkingThrottling) { const now = Date.now();
logger('repeated checking, ignored'); if (lastResult && lastChecking && now - lastChecking < 1000 * 60) {
return; // logger('repeated checking, ignored');
return lastResult || empty;
} }
checkingThrottling = true; lastChecking = now;
setTimeout(() => {
checkingThrottling = false;
}, 3000);
if (blockUpdate && blockUpdate.until > Date.now() / 1000) { if (blockUpdate && blockUpdate.until > Date.now() / 1000) {
throw new Error( report({
`热更新已暂停,原因:${blockUpdate.reason}。请在"${new Date( type: 'errorChecking',
message: `热更新已暂停,原因:${blockUpdate.reason}。请在"${new Date(
blockUpdate.until * 1000, blockUpdate.until * 1000,
).toLocaleString()}"`, ).toLocaleString()}"`,
); });
return lastResult || empty;
} }
if (typeof APPKEY !== 'string') { report({ type: 'checking' });
throw new Error('未检查到合法的APPKEY请查看update.json文件是否正确生成');
}
logger('checking update');
let resp; let resp;
try { try {
resp = await fetch(getCheckUrl(APPKEY), { resp = await fetch(getCheckUrl(APPKEY), {
@@ -138,22 +169,36 @@ export async function checkUpdate(APPKEY, isRetry) {
}); });
} catch (e) { } catch (e) {
if (isRetry) { if (isRetry) {
throw new Error('无法连接更新服务器,请检查网络连接后重试'); report({
type: 'errorChecking',
message: '无法连接更新服务器,请检查网络连接后重试',
});
return lastResult || empty;
} }
await tryBackupEndpoints(); await tryBackupEndpoints();
return checkUpdate(APPKEY, true); return checkUpdate(APPKEY, true);
} }
const result = await resp.json(); const result: CheckResult = await resp.json();
lastResult = result;
// @ts-ignore
checkOperation(result.op); checkOperation(result.op);
if (resp.status !== 200) { if (resp.status !== 200) {
throw new Error(result.message); report({
type: 'errorChecking',
//@ts-ignore
message: result.message,
});
return lastResult;
} }
return result; return result;
} }
function checkOperation(op) { function checkOperation(
op: { type: string; reason: string; duration: number }[],
) {
if (!Array.isArray(op)) { if (!Array.isArray(op)) {
return; return;
} }
@@ -163,14 +208,19 @@ function checkOperation(op) {
reason: action.reason, reason: action.reason,
until: Math.round((Date.now() + action.duration) / 1000), until: Math.round((Date.now() + action.duration) / 1000),
}; };
Pushy.setBlockUpdate(blockUpdate); PushyModule.setBlockUpdate(blockUpdate);
} }
}); });
} }
let downloadingThrottling = false; let downloadingThrottling = false;
let downloadedHash; let downloadedHash: string;
export async function downloadUpdate(options, eventListeners) { export async function downloadUpdate(
options: UpdateAvailableResult,
eventListeners?: {
onDownloadProgress?: (data: ProgressData) => void;
},
) {
assertRelease(); assertRelease();
if (!options.update) { if (!options.update) {
return; return;
@@ -206,10 +256,11 @@ export async function downloadUpdate(options, eventListeners) {
} }
} }
let succeeded = false; let succeeded = false;
report({ type: 'downloading' });
if (options.diffUrl) { if (options.diffUrl) {
logger('downloading diff'); logger('downloading diff');
try { try {
await Pushy.downloadPatchFromPpk({ await PushyModule.downloadPatchFromPpk({
updateUrl: options.diffUrl, updateUrl: options.diffUrl,
hash: options.hash, hash: options.hash,
originHash: currentVersion, originHash: currentVersion,
@@ -222,7 +273,7 @@ export async function downloadUpdate(options, eventListeners) {
if (!succeeded && options.pdiffUrl) { if (!succeeded && options.pdiffUrl) {
logger('downloading pdiff'); logger('downloading pdiff');
try { try {
await Pushy.downloadPatchFromPackage({ await PushyModule.downloadPatchFromPackage({
updateUrl: options.pdiffUrl, updateUrl: options.pdiffUrl,
hash: options.hash, hash: options.hash,
}); });
@@ -234,7 +285,7 @@ export async function downloadUpdate(options, eventListeners) {
if (!succeeded && options.updateUrl) { if (!succeeded && options.updateUrl) {
logger('downloading full patch'); logger('downloading full patch');
try { try {
await Pushy.downloadFullUpdate({ await PushyModule.downloadFullUpdate({
updateUrl: options.updateUrl, updateUrl: options.updateUrl,
hash: options.hash, hash: options.hash,
}); });
@@ -245,8 +296,7 @@ export async function downloadUpdate(options, eventListeners) {
} }
progressHandler && progressHandler.remove(); progressHandler && progressHandler.remove();
if (!succeeded) { if (!succeeded) {
report(options.hash, 'error'); return report({ type: 'errorUpdate', data: { newVersion: options.hash } });
throw new Error('all update attempts failed');
} }
setLocalHashInfo(options.hash, { setLocalHashInfo(options.hash, {
name: options.name, name: options.name,
@@ -257,7 +307,7 @@ export async function downloadUpdate(options, eventListeners) {
return options.hash; return options.hash;
} }
function assertHash(hash) { function assertHash(hash: string) {
if (!downloadedHash) { if (!downloadedHash) {
logger(`no downloaded hash`); logger(`no downloaded hash`);
return; return;
@@ -269,19 +319,19 @@ function assertHash(hash) {
return true; return true;
} }
export function switchVersion(hash) { export function switchVersion(hash: string) {
assertRelease(); assertRelease();
if (assertHash(hash)) { if (assertHash(hash)) {
logger('switchVersion: ' + hash); logger('switchVersion: ' + hash);
Pushy.reloadUpdate({ hash }); PushyModule.reloadUpdate({ hash });
} }
} }
export function switchVersionLater(hash) { export function switchVersionLater(hash: string) {
assertRelease(); assertRelease();
if (assertHash(hash)) { if (assertHash(hash)) {
logger('switchVersionLater: ' + hash); logger('switchVersionLater: ' + hash);
Pushy.setNeedUpdate({ hash }); PushyModule.setNeedUpdate({ hash });
} }
} }
@@ -293,22 +343,31 @@ export function markSuccess() {
return; return;
} }
marked = true; marked = true;
Pushy.markSuccess(); PushyModule.markSuccess();
report(currentVersion, 'success'); report({ type: 'markSuccess' });
} }
export async function downloadAndInstallApk({ url, onDownloadProgress }) { export async function downloadAndInstallApk({
logger('downloadAndInstallApk'); url,
if (Platform.OS === 'android' && Platform.Version <= 23) { onDownloadProgress,
}: {
url: string;
onDownloadProgress?: (data: ProgressData) => void;
}) {
if (Platform.OS !== 'android') {
return;
}
report({ type: 'downloadingApk' });
if (Platform.Version <= 23) {
try { try {
const granted = await PermissionsAndroid.request( const granted = await PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE, PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE,
); );
if (granted !== PermissionsAndroid.RESULTS.GRANTED) { if (granted !== PermissionsAndroid.RESULTS.GRANTED) {
return; return report({ type: 'rejectStoragePermission' });
} }
} catch (err) { } catch (err) {
console.warn(err); return report({ type: 'errorStoragePermission' });
} }
} }
let hash = Date.now().toString(); let hash = Date.now().toString();
@@ -316,17 +375,19 @@ export async function downloadAndInstallApk({ url, onDownloadProgress }) {
if (onDownloadProgress) { if (onDownloadProgress) {
progressHandler = eventEmitter.addListener( progressHandler = eventEmitter.addListener(
'RCTPushyDownloadProgress', 'RCTPushyDownloadProgress',
(progressData) => { (progressData: ProgressData) => {
if (progressData.hash === hash) { if (progressData.hash === hash) {
onDownloadProgress(progressData); onDownloadProgress(progressData);
} }
}, },
); );
} }
await Pushy.downloadAndInstallApk({ await PushyModule.downloadAndInstallApk({
url, url,
target: 'update.apk', target: 'update.apk',
hash, hash,
}).catch(() => {
report({ type: 'errowDownloadAndInstallApk' });
}); });
progressHandler && progressHandler.remove(); progressHandler && progressHandler.remove();
} }

View File

@@ -1,5 +1,11 @@
import React, { Component } from 'react'; import React, { PureComponent, ComponentType } from 'react';
import { Platform, Alert, Linking, AppState } from 'react-native'; import {
Platform,
Alert,
Linking,
AppState,
NativeEventSubscription,
} from 'react-native';
import { import {
isFirstTime, isFirstTime,
@@ -10,16 +16,25 @@ import {
switchVersionLater, switchVersionLater,
markSuccess, markSuccess,
downloadAndInstallApk, downloadAndInstallApk,
onEvents,
} from './main'; } from './main';
import { UpdateEventsListener } from './type';
export function simpleUpdate(WrappedComponent, options = {}) { export function simpleUpdate(
const { appKey } = options; WrappedComponent: ComponentType,
options: { appKey?: string; onEvents?: UpdateEventsListener } = {},
) {
const { appKey, onEvents: eventListeners } = options;
if (!appKey) { if (!appKey) {
throw new Error('appKey is required for simpleUpdate()'); throw new Error('appKey is required for simpleUpdate()');
} }
if (typeof eventListeners === 'function') {
onEvents(eventListeners);
}
return __DEV__ return __DEV__
? WrappedComponent ? WrappedComponent
: class AppUpdate extends Component { : class AppUpdate extends PureComponent {
stateListener: NativeEventSubscription;
componentDidMount() { componentDidMount() {
if (isRolledBack) { if (isRolledBack) {
Alert.alert('抱歉', '刚刚更新遭遇错误,已为您恢复到更新前版本'); Alert.alert('抱歉', '刚刚更新遭遇错误,已为您恢复到更新前版本');
@@ -70,7 +85,7 @@ export function simpleUpdate(WrappedComponent, options = {}) {
checkUpdate = async () => { checkUpdate = async () => {
let info; let info;
try { try {
info = await checkUpdate(appKey); info = await checkUpdate(appKey!);
} catch (err) { } catch (err) {
Alert.alert('更新检查失败', err.message); Alert.alert('更新检查失败', err.message);
return; return;

71
lib/type.ts Normal file
View File

@@ -0,0 +1,71 @@
export interface ExpiredResult {
upToDate?: false;
expired: true;
downloadUrl: string;
}
export interface UpTodateResult {
expired?: false;
upToDate: true;
paused?: 'app' | 'package';
}
export interface UpdateAvailableResult {
expired?: false;
upToDate?: false;
update: true;
name: string; // version name
hash: string;
description: string;
metaInfo: string;
pdiffUrl: string;
diffUrl?: string;
updateUrl?: string;
}
export type CheckResult =
| ExpiredResult
| UpTodateResult
| UpdateAvailableResult
| {};
export interface ProgressData {
hash: string;
received: number;
total: number;
}
export type EventType =
| 'rollback'
| 'errorChecking'
| 'checking'
| 'downloading'
| 'errorUpdate'
| 'markSuccess'
| 'downloadingApk'
| 'rejectStoragePermission'
| 'errorStoragePermission'
| 'errowDownloadAndInstallApk';
export interface EventData {
currentVersion: string;
cInfo: {
pushy: string;
rn: string;
os: string;
uuid: string;
};
packageVersion: string;
buildTime: number;
message?: string;
rolledBackVersion?: string;
newVersion?: string;
[key: string]: any;
}
export type UpdateEventsListener = ({
type,
data,
}: {
type: EventType;
data: EventData;
}) => void;

View File

@@ -1,13 +1,27 @@
{ {
"name": "react-native-update", "name": "react-native-update",
"version": "8.1.0", "version": "9.0.5",
"description": "react-native hot update", "description": "react-native hot update",
"main": "lib/index.js", "main": "lib/index.ts",
"scripts": { "scripts": {
"prepublish": "yarn submodule", "prepublish": "yarn submodule",
"submodule": "git submodule update --init --recursive", "submodule": "git submodule update --init --recursive",
"test": "echo \"Error: no test specified\" && exit 1", "test": "echo \"Error: no test specified\" && exit 1",
"build-lib": "yarn submodule && $ANDROID_HOME/ndk/20.1.5948944/ndk-build NDK_PROJECT_PATH=android APP_BUILD_SCRIPT=android/jni/Android.mk NDK_APPLICATION_MK=android/jni/Application.mk NDK_LIBS_OUT=android/lib" "build-lib": "yarn submodule && $ANDROID_HOME/ndk/20.1.5948944/ndk-build NDK_PROJECT_PATH=android APP_BUILD_SCRIPT=android/jni/Android.mk NDK_APPLICATION_MK=android/jni/Application.mk NDK_LIBS_OUT=android/lib",
"build:ios-debug": "cd Example/testHotUpdate && yarn && detox build --configuration ios.sim.debug",
"build:ios-release": "cd Example/testHotUpdate && yarn && detox build --configuration ios.sim.release",
"test:ios-debug": "cd Example/testHotUpdate && detox test --configuration ios.sim.debug",
"test:ios-release": "cd Example/testHotUpdate && yarn detox test --configuration ios.sim.release",
"build:android-debug": "cd Example/testHotUpdate && yarn && detox build --configuration android.emu.debug",
"build:android-release": "cd Example/testHotUpdate && yarn && detox build --configuration android.emu.release",
"test:android-release": "cd Example/testHotUpdate && yarn detox test --configuration android.emu.release --headless --record-logs all",
"test:android-debug": "cd Example/testHotUpdate && detox test --configuration android.emu.debug --headless --record-logs all",
"e2e:ios": "npm run build:ios-release && npm run test:ios-release",
"e2e:android": "npm run build:android-release && npm run test:android-release",
"tests:emulator:prepare": "cd .github/workflows/scripts/functions && yarn && yarn build",
"tests:emulator:start-ci": "yarn tests:emulator:prepare && cd ./.github/workflows/scripts && ./start-firebase-emulator.sh",
"tests:packager:jet-ci": "cd Example/testHotUpdate && cross-env TMPDIR=$HOME/.metro REACT_DEBUGGER=\"echo nope\" node_modules/.bin/react-native start --no-interactive",
"tests:ios:pod:install": "cd Example/testHotUpdate && yarn && yarn pod-install"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
@@ -30,5 +44,25 @@
"homepage": "https://github.com/reactnativecn/react-native-pushy#readme", "homepage": "https://github.com/reactnativecn/react-native-pushy#readme",
"dependencies": { "dependencies": {
"nanoid": "^3.3.3" "nanoid": "^3.3.3"
},
"codegenConfig": {
"libraries": [
{
"name": "RCTPushySpec",
"type": "modules",
"jsSrcsDir": "lib"
}
]
},
"devDependencies": {
"@types/fs-extra": "^9.0.13",
"@types/jest": "^29.2.1",
"detox": "^20.5.0",
"firebase-tools": "^11.24.1",
"fs-extra": "^9.1.0",
"jest": "^29.2.1",
"pod-install": "^0.1.37",
"ts-jest": "^29.0.3",
"typescript": "^4.1.3"
} }
} }

View File

@@ -13,7 +13,9 @@ Pod::Spec.new do |s|
s.cocoapods_version = '>= 1.6.0' s.cocoapods_version = '>= 1.6.0'
s.platform = :ios, "8.0" s.platform = :ios, "8.0"
s.platforms = { :ios => "11.0" }
s.source = { :git => 'https://github.com/reactnativecn/react-native-pushy.git', :tag => '#{s.version}' } s.source = { :git => 'https://github.com/reactnativecn/react-native-pushy.git', :tag => '#{s.version}' }
s.source_files = "ios/**/*.{h,m,mm,swift}"
s.libraries = 'bz2', 'z' s.libraries = 'bz2', 'z'
s.vendored_libraries = 'RCTPushy/libRCTPushy.a' s.vendored_libraries = 'RCTPushy/libRCTPushy.a'
s.pod_target_xcconfig = { 'USER_HEADER_SEARCH_PATHS' => '"$(SRCROOT)/../node_modules/react-native-update/ios"' } s.pod_target_xcconfig = { 'USER_HEADER_SEARCH_PATHS' => '"$(SRCROOT)/../node_modules/react-native-update/ios"' }
@@ -21,10 +23,11 @@ Pod::Spec.new do |s|
s.script_phase = { :name => 'Generate build time', :script => 'set -x;date +%s > ${PODS_ROOT}/../../node_modules/react-native-update/ios/pushy_build_time.txt', :execution_position => :before_compile } s.script_phase = { :name => 'Generate build time', :script => 'set -x;date +%s > ${PODS_ROOT}/../../node_modules/react-native-update/ios/pushy_build_time.txt', :execution_position => :before_compile }
s.dependency 'React' s.dependency 'React'
s.dependency "React-Core"
s.dependency 'SSZipArchive' s.dependency 'SSZipArchive'
s.subspec 'RCTPushy' do |ss| s.subspec 'RCTPushy' do |ss|
ss.source_files = 'ios/RCTPushy/*.{h,m}' ss.source_files = 'ios/RCTPushy/*.{h,m,mm,swift}'
ss.public_header_files = ['ios/RCTPushy/RCTPushy.h'] ss.public_header_files = ['ios/RCTPushy/RCTPushy.h']
end end
@@ -37,4 +40,5 @@ Pod::Spec.new do |s|
'android/jni/lzma/C/Lzma2Dec.{h,c}'] 'android/jni/lzma/C/Lzma2Dec.{h,c}']
ss.private_header_files = 'ios/RCTPushy/HDiffPatch/**/*.h' ss.private_header_files = 'ios/RCTPushy/HDiffPatch/**/*.h'
end end
install_modules_dependencies(s)
end end

6433
yarn.lock

File diff suppressed because it is too large Load Diff