├── .github
└── workflows
│ ├── ci.yml
│ └── pull_request.yml
├── .gitignore
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── HelloWorld
├── .babelrc
├── .bundle
│ └── config
├── .editorconfig
├── .eslintrc.js
├── .gitignore
├── .prettierrc.js
├── .watchmanconfig
├── Gemfile
├── README.md
├── __tests__
│ └── App-test.js
├── _bundle
│ └── config
├── _node-version
├── android
│ ├── app
│ │ ├── build.gradle
│ │ ├── debug.keystore
│ │ ├── proguard-rules.pro
│ │ └── src
│ │ │ ├── debug
│ │ │ ├── AndroidManifest.xml
│ │ │ └── java
│ │ │ │ └── com
│ │ │ │ └── helloworld
│ │ │ │ └── ReactNativeFlipper.java
│ │ │ ├── main
│ │ │ ├── AndroidManifest.xml
│ │ │ ├── java
│ │ │ │ └── com
│ │ │ │ │ └── helloworld
│ │ │ │ │ ├── MainActivity.java
│ │ │ │ │ └── MainApplication.java
│ │ │ └── res
│ │ │ │ ├── drawable
│ │ │ │ └── rn_edit_text_material.xml
│ │ │ │ ├── mipmap-hdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ │ ├── mipmap-mdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ │ ├── mipmap-xhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ │ ├── mipmap-xxhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ │ ├── mipmap-xxxhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ │ └── values
│ │ │ │ ├── strings.xml
│ │ │ │ └── styles.xml
│ │ │ └── release
│ │ │ └── java
│ │ │ └── com
│ │ │ └── helloworld
│ │ │ └── ReactNativeFlipper.java
│ ├── build.gradle
│ ├── gradle.properties
│ ├── gradle
│ │ └── wrapper
│ │ │ ├── gradle-wrapper.jar
│ │ │ └── gradle-wrapper.properties
│ ├── gradlew
│ ├── gradlew.bat
│ └── settings.gradle
├── app.json
├── babel.config.js
├── index.js
├── ios
│ ├── .xcode.env
│ ├── HelloWorld.xcodeproj
│ │ ├── project.pbxproj
│ │ └── xcshareddata
│ │ │ └── xcschemes
│ │ │ └── HelloWorld.xcscheme
│ ├── HelloWorld.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ └── IDEWorkspaceChecks.plist
│ ├── HelloWorld
│ │ ├── AppDelegate.h
│ │ ├── AppDelegate.mm
│ │ ├── Images.xcassets
│ │ │ ├── AppIcon.appiconset
│ │ │ │ └── Contents.json
│ │ │ └── Contents.json
│ │ ├── Info.plist
│ │ ├── LaunchScreen.storyboard
│ │ └── main.m
│ ├── HelloWorldTests
│ │ ├── HelloWorldTests.m
│ │ └── Info.plist
│ ├── Podfile
│ ├── Podfile.lock
│ └── _xcode.env
├── jsconfig.json
├── metro.config.js
├── mocker
│ ├── index.js
│ └── user.mock.js
├── package.json
└── src
│ ├── App.js
│ ├── components
│ ├── Footer
│ │ └── index.js
│ └── icons
│ │ └── signin.js
│ ├── config.js
│ ├── global.js
│ ├── hooks
│ └── users.js
│ ├── models
│ ├── global.js
│ └── index.js
│ ├── pages
│ ├── AuthLoading
│ │ └── index.js
│ ├── DevOptions
│ │ └── index.js
│ ├── MyHome
│ │ ├── Setting
│ │ │ └── index.js
│ │ └── index.js
│ ├── OrderHome
│ │ └── index.js
│ ├── SignIn
│ │ └── index.js
│ └── TransportHome
│ │ └── index.js
│ ├── routes
│ ├── index.js
│ └── tabs.js
│ ├── services
│ └── users.js
│ └── utils
│ ├── fetch.js
│ └── index.js
├── ISSUE_TEMPLATE.md
├── LICENSE
├── README.md
├── package.json
├── renovate.json
├── scripts
└── copied.mjs
└── template
├── .gitignore
├── README.md
├── package.json
├── template.config.js
└── template
├── Gemfile
├── README.md
├── __tests__
└── App-test.js
├── _babelrc
├── _bundle
└── config
├── _editorconfig
├── _eslintrc.js
├── _gitignore
├── _node-version
├── _prettierrc.js
├── _watchmanconfig
├── android
├── app
│ ├── build.gradle
│ ├── debug.keystore
│ ├── proguard-rules.pro
│ └── src
│ │ ├── debug
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ │ └── com
│ │ │ └── helloworld
│ │ │ └── ReactNativeFlipper.java
│ │ ├── main
│ │ ├── AndroidManifest.xml
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── helloworld
│ │ │ │ ├── MainActivity.java
│ │ │ │ └── MainApplication.java
│ │ └── res
│ │ │ ├── drawable
│ │ │ └── rn_edit_text_material.xml
│ │ │ ├── mipmap-hdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-mdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xhdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ │ └── values
│ │ │ ├── strings.xml
│ │ │ └── styles.xml
│ │ └── release
│ │ └── java
│ │ └── com
│ │ └── helloworld
│ │ └── ReactNativeFlipper.java
├── build.gradle
├── gradle.properties
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
├── app.json
├── babel.config.js
├── index.js
├── ios
├── .xcode.env
├── HelloWorld.xcodeproj
│ ├── project.pbxproj
│ └── xcshareddata
│ │ └── xcschemes
│ │ └── HelloWorld.xcscheme
├── HelloWorld.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
├── HelloWorld
│ ├── AppDelegate.h
│ ├── AppDelegate.mm
│ ├── Images.xcassets
│ │ ├── AppIcon.appiconset
│ │ │ └── Contents.json
│ │ └── Contents.json
│ ├── Info.plist
│ ├── LaunchScreen.storyboard
│ └── main.m
├── HelloWorldTests
│ ├── HelloWorldTests.m
│ └── Info.plist
├── Podfile
├── Podfile.lock
└── _xcode.env
├── jsconfig.json
├── metro.config.js
├── mocker
├── index.js
└── user.mock.js
├── package.json
└── src
├── App.js
├── components
├── Footer
│ └── index.js
└── icons
│ └── signin.js
├── config.js
├── global.js
├── hooks
└── users.js
├── models
├── global.js
└── index.js
├── pages
├── AuthLoading
│ └── index.js
├── DevOptions
│ └── index.js
├── MyHome
│ ├── Setting
│ │ └── index.js
│ └── index.js
├── OrderHome
│ └── index.js
├── SignIn
│ └── index.js
└── TransportHome
│ └── index.js
├── routes
├── index.js
└── tabs.js
├── services
└── users.js
└── utils
├── fetch.js
└── index.js
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: Build & Deploy
2 | on:
3 | push:
4 | branches:
5 | - master
6 |
7 | jobs:
8 | build-deploy:
9 | runs-on: ubuntu-latest
10 | steps:
11 | - uses: actions/checkout@v3
12 | - uses: actions/setup-node@v3
13 | with:
14 | node-version: 16
15 |
16 | - name: Generate Changelog
17 | uses: jaywcjlove/changelog-generator@main
18 | with:
19 | token: ${{ secrets.GITHUB_TOKEN }}
20 | head-ref: ${{ steps.create_tag.outputs.version }}
21 | filter: '[R|r]elease[d]\s+[v|V]\d(\.\d+){0,2}'
22 |
23 | - name: Generate Contributors Images
24 | uses: jaywcjlove/github-action-contributors@main
25 | id: contributors
26 | with:
27 | avatarSize: 42
28 |
29 | - name: Modify template/README.md
30 | uses: jaywcjlove/github-action-modify-file-content@main
31 | with:
32 | path: template/README.md
33 | openDelimiter: ''
34 | closeDelimiter: ''
35 | body: ${{steps.contributors.outputs.htmlList}}
36 |
37 | - run: yarn install
38 | # - name: HelloWorld -> Build Android Release
39 | # working-directory: HelloWorld
40 | # run: cd android && ./gradlew assembleRelease
41 |
42 | - run: yarn run start
43 | - run: git status
44 |
45 | - run: npm i markdown-to-html-cli -g
46 | - run: mkdir -p build
47 | - run: markdown-to-html --output build/index.html --title "React Native UIW Template" --github-corners https://github.com/uiwjs/react-native-template --description="React Native Template for @uiw/react-native." --keywords="react-native-template,react-native,template"
48 |
49 | - name: Deploy Website
50 | uses: peaceiris/actions-gh-pages@v3
51 | with:
52 | github_token: ${{ secrets.GITHUB_TOKEN }}
53 | publish_dir: ./build
54 |
55 | - run: npm install @jsdevtools/npm-publish -g
56 | - run: npm-publish --token="${{ secrets.NPM_TOKEN }}" ./template/package.json
57 |
58 | release:
59 | runs-on: ubuntu-latest
60 | needs: build-deploy
61 | steps:
62 | - uses: actions/checkout@v3
63 | - name: Is a tag created auto?
64 | id: create_tag
65 | uses: jaywcjlove/create-tag-action@main
66 | with:
67 | token: ${{ secrets.GITHUB_TOKEN }}
68 | package-path: ./template/package.json
69 |
70 | - name: Generate Changelog
71 | id: changelog
72 | uses: jaywcjlove/changelog-generator@main
73 | if: steps.create_tag.outputs.successful
74 | with:
75 | token: ${{ secrets.GITHUB_TOKEN }}
76 | head-ref: ${{ steps.create_tag.outputs.version }}
77 | filter-author: (renovate-bot|Renovate Bot)
78 | filter: '[R|r]elease[d]\s+[v|V]\d(\.\d+){0,2}'
79 |
80 | - name: Create Release
81 | uses: ncipollo/release-action@v1
82 | if: steps.create_tag.outputs.successful
83 | with:
84 | token: ${{ secrets.GITHUB_TOKEN }}
85 | name: ${{ steps.changelog.outputs.tag }}
86 | tag: ${{ steps.changelog.outputs.tag }}
87 | body: |
88 | [](https://uiwjs.github.io/npm-unpkg/#/pkg/@uiw/react-native-template@${{steps.changelog.outputs.version}}/file/README.md) [](https://www.npmjs.com/package/@uiw/react-native-template)
89 |
90 | ```bash
91 | npm i @uiw/react-native-template@${{steps.changelog.outputs.version}}
92 | ```
93 |
94 | ${{ steps.changelog.outputs.compareurl }}
95 |
96 | ${{ steps.changelog.outputs.changelog }}
97 |
--------------------------------------------------------------------------------
/.github/workflows/pull_request.yml:
--------------------------------------------------------------------------------
1 | name: Pull Request Build
2 | on:
3 | pull_request:
4 |
5 | jobs:
6 | build-deploy:
7 | runs-on: ubuntu-latest
8 | steps:
9 | - uses: actions/checkout@v3
10 | - uses: actions/setup-node@v3
11 | with:
12 | node-version: 16
13 |
14 | - run: yarn install
15 | - run: yarn run start
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # node.js
2 | node_modules/
3 | package-lock.json
4 | npm-debug.log
5 | yarn-error.log
6 | yarn.lock
7 | .vscode/
8 | .DS_Store
9 | .idea
10 | .gradle
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
6 |
7 | ## Our Standards
8 |
9 | Examples of behavior that contributes to creating a positive environment include:
10 |
11 | * Using welcoming and inclusive language
12 | * Being respectful of differing viewpoints and experiences
13 | * Gracefully accepting constructive criticism
14 | * Focusing on what is best for the community
15 | * Showing empathy towards other community members
16 |
17 | Examples of unacceptable behavior by participants include:
18 |
19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances
20 | * Trolling, insulting/derogatory comments, and personal or political attacks
21 | * Public or private harassment
22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission
23 | * Other conduct which could reasonably be considered inappropriate in a professional setting
24 |
25 | ## Our Responsibilities
26 |
27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
28 |
29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
30 |
31 | ## Scope
32 |
33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
34 |
35 | ## Enforcement
36 |
37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project owner at emin@emin.ch. The project owner will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project owner is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
38 |
39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
40 |
41 | ## Attribution
42 |
43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
44 |
45 | [homepage]: http://contributor-covenant.org
46 | [version]: http://contributor-covenant.org/version/1/4/
47 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | Contributing to this project should be as easy and transparent as possible.
4 |
5 | ## Workflow
6 |
7 | We use [GitHub Flow](https://guides.github.com/introduction/flow/), so all code changes happen through pull requests.
8 |
9 | 1. Fork the repository and create your branch from `master`.
10 | 2. If you've changed the functionality, update the documentation.
11 | 3. Issue that pull request! :tada:
12 |
13 | ## License
14 |
15 | By contributing, you agree that your contributions will be licensed under the [MIT License](https://choosealicense.com/licenses/mit/).
16 |
--------------------------------------------------------------------------------
/HelloWorld/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "plugins": [
3 | ["module-resolver", {
4 | "root": ["./"],
5 | "alias": {
6 | "@": "./src",
7 | "@components": "./src/components",
8 | "@utils": "./src/utils"
9 | }
10 | }]
11 | ]
12 | }
--------------------------------------------------------------------------------
/HelloWorld/.bundle/config:
--------------------------------------------------------------------------------
1 | BUNDLE_PATH: "vendor/bundle"
2 | BUNDLE_FORCE_RUBY_PLATFORM: 1
--------------------------------------------------------------------------------
/HelloWorld/.editorconfig:
--------------------------------------------------------------------------------
1 | # Windows files
2 | [*.bat]
3 | end_of_line = crlf
4 |
--------------------------------------------------------------------------------
/HelloWorld/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | extends: '@react-native-community',
4 | rules: {
5 | 'react/react-in-jsx-scope': 'off',
6 | 'react-hooks/exhaustive-deps': 'off',
7 | 'no-shadow': 'off',
8 | 'react-native/no-inline-styles': 0,
9 | 'prettier/prettier': [
10 | 'error',
11 | {
12 | 'no-inline-styles': false,
13 | },
14 | ],
15 | },
16 | };
17 |
--------------------------------------------------------------------------------
/HelloWorld/.gitignore:
--------------------------------------------------------------------------------
1 | # OSX
2 | #
3 | .DS_Store
4 |
5 | # Xcode
6 | #
7 | build/
8 | *.pbxuser
9 | !default.pbxuser
10 | *.mode1v3
11 | !default.mode1v3
12 | *.mode2v3
13 | !default.mode2v3
14 | *.perspectivev3
15 | !default.perspectivev3
16 | xcuserdata
17 | *.xccheckout
18 | *.moved-aside
19 | DerivedData
20 | *.hmap
21 | *.ipa
22 | *.xcuserstate
23 | ios/.xcode.env.local
24 |
25 | # Android/IntelliJ
26 | #
27 | build/
28 | .idea
29 | .gradle
30 | local.properties
31 | *.iml
32 | *.hprof
33 | .cxx/
34 | *.keystore
35 | !debug.keystore
36 |
37 | # node.js
38 | #
39 | node_modules/
40 | npm-debug.log
41 | yarn-error.log
42 |
43 | # fastlane
44 | #
45 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
46 | # screenshots whenever they are needed.
47 | # For more information about the recommended setup visit:
48 | # https://docs.fastlane.tools/best-practices/source-control/
49 |
50 | **/fastlane/report.xml
51 | **/fastlane/Preview.html
52 | **/fastlane/screenshots
53 | **/fastlane/test_output
54 |
55 | # Bundle artifact
56 | *.jsbundle
57 |
58 | # Ruby / CocoaPods
59 | /ios/Pods/
60 | /vendor/bundle/
61 |
62 |
63 | # Temporary files created by Metro to check the health of the file watcher
64 | .metro-health-check*
65 |
--------------------------------------------------------------------------------
/HelloWorld/.prettierrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | arrowParens: 'avoid',
3 | bracketSameLine: true,
4 | bracketSpacing: false,
5 | singleQuote: true,
6 | trailingComma: 'all',
7 | tabWidth: 2,
8 | printWidth: 160,
9 | };
10 |
--------------------------------------------------------------------------------
/HelloWorld/.watchmanconfig:
--------------------------------------------------------------------------------
1 | {}
--------------------------------------------------------------------------------
/HelloWorld/Gemfile:
--------------------------------------------------------------------------------
1 | source 'https://rubygems.org'
2 |
3 | # You may use http://rbenv.org/ or https://rvm.io/ to install and use this version
4 | ruby '>= 2.6.10'
5 |
6 | gem 'cocoapods', '>= 1.11.3'
7 |
--------------------------------------------------------------------------------
/HelloWorld/README.md:
--------------------------------------------------------------------------------
1 | HelloWorld
2 | ---
3 |
4 | React Native UIW Template
5 |
6 | ## Development
7 |
8 | ```bash
9 | cd ios/ && pod install && cd ../
10 |
11 | # Mocker API
12 | npm run api
13 |
14 | # Run the app with iOS.
15 | npm run ios
16 | ```
17 |
18 | **⚠️⚠️ MacBook Pro with a M1 ⚠️⚠️**
19 |
20 | ```bash
21 | # Install ffi
22 | sudo arch -x86_64 gem install ffi
23 |
24 | # Clear pods.
25 | pod deintegrate
26 | # pod rm Podfile.lock
27 | arch -x86_64 pod install
28 | # Re-install pods
29 | arch -x86_64 pod install --repo-update --verbose
30 | ```
31 |
32 | ## Main Directory Structure
33 |
34 | ```
35 | .
36 | ├── mocker # mocker data
37 | ├── android # native android code
38 | ├── ios # native ios code
39 | ├── src # code directory
40 | │ ├── components # react components
41 | │ ├── models # The models brings together state, reducers, async actions & action creators in one place
42 | │ ├── pages # route pages
43 | │ ├── routes # route configuration
44 | │ ├── services # api request
45 | │ ├── utils # public method
46 | │ ├── App.js # route entery page
47 | │ ├── config.js # app configuration
48 | │ └── global.js # Store some global objects for easy calling
49 | ├── .eslintrc # eslint configuration
50 | ├── index.js # app entry file
51 | └── package.json # This document is all you need to know about what’s required in your package.json file.
52 | ```
--------------------------------------------------------------------------------
/HelloWorld/__tests__/App-test.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @format
3 | */
4 |
5 | import 'react-native';
6 | import React from 'react';
7 | import App from '../App';
8 |
9 | // Note: test renderer must be required after react-native.
10 | import renderer from 'react-test-renderer';
11 |
12 | it('renders correctly', () => {
13 | renderer.create();
14 | });
15 |
--------------------------------------------------------------------------------
/HelloWorld/_bundle/config:
--------------------------------------------------------------------------------
1 | BUNDLE_PATH: "vendor/bundle"
2 | BUNDLE_FORCE_RUBY_PLATFORM: 1
3 |
--------------------------------------------------------------------------------
/HelloWorld/_node-version:
--------------------------------------------------------------------------------
1 | 18
--------------------------------------------------------------------------------
/HelloWorld/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: "com.android.application"
2 | apply plugin: "com.facebook.react"
3 | import com.android.build.OutputFile
4 |
5 |
6 | /**
7 | * This is the configuration block to customize your React Native Android app.
8 | * By default you don't need to apply any configuration, just uncomment the lines you need.
9 | */
10 | react {
11 | /* Folders */
12 | // The root of your project, i.e. where "package.json" lives. Default is '..'
13 | // root = file("../")
14 | // The folder where the react-native NPM package is. Default is ../node_modules/react-native
15 | // reactNativeDir = file("../node_modules/react-native")
16 | // The folder where the react-native Codegen package is. Default is ../node_modules/react-native-codegen
17 | // codegenDir = file("../node_modules/react-native-codegen")
18 | // The cli.js file which is the React Native CLI entrypoint. Default is ../node_modules/react-native/cli.js
19 | // cliFile = file("../node_modules/react-native/cli.js")
20 | /* Variants */
21 | // The list of variants to that are debuggable. For those we're going to
22 | // skip the bundling of the JS bundle and the assets. By default is just 'debug'.
23 | // If you add flavors like lite, prod, etc. you'll have to list your debuggableVariants.
24 | // debuggableVariants = ["liteDebug", "prodDebug"]
25 | /* Bundling */
26 | // A list containing the node command and its flags. Default is just 'node'.
27 | // nodeExecutableAndArgs = ["node"]
28 | //
29 | // The command to run when bundling. By default is 'bundle'
30 | // bundleCommand = "ram-bundle"
31 | //
32 | // The path to the CLI configuration file. Default is empty.
33 | // bundleConfig = file(../rn-cli.config.js)
34 | //
35 | // The name of the generated asset file containing your JS bundle
36 | // bundleAssetName = "MyApplication.android.bundle"
37 | //
38 | // The entry file for bundle generation. Default is 'index.android.js' or 'index.js'
39 | // entryFile = file("../js/MyApplication.android.js")
40 | //
41 | // A list of extra flags to pass to the 'bundle' commands.
42 | // See https://github.com/react-native-community/cli/blob/main/docs/commands.md#bundle
43 | // extraPackagerArgs = []
44 | /* Hermes Commands */
45 | // The hermes compiler command to run. By default it is 'hermesc'
46 | // hermesCommand = "$rootDir/my-custom-hermesc/bin/hermesc"
47 | //
48 | // The list of flags to pass to the Hermes compiler. By default is "-O", "-output-source-map"
49 | // hermesFlags = ["-O", "-output-source-map"]
50 | }
51 |
52 | /**
53 | * Set this to true to create four separate APKs instead of one,
54 | * one for each native architecture. This is useful if you don't
55 | * use App Bundles (https://developer.android.com/guide/app-bundle/)
56 | * and want to have separate APKs to upload to the Play Store.
57 |
58 |
59 | */
60 | def enableSeparateBuildPerCPUArchitecture = false
61 |
62 | /**
63 | * Set this to true to Run Proguard on Release builds to minify the Java bytecode.
64 | */
65 | def enableProguardInReleaseBuilds = false
66 | /**
67 | * The preferred build flavor of JavaScriptCore (JSC)
68 | *
69 | * For example, to use the international variant, you can use:
70 | * `def jscFlavor = 'org.webkit:android-jsc-intl:+'`
71 | *
72 | * The international variant includes ICU i18n library and necessary data
73 | * allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that
74 | * give correct results when using with locales other than en-US. Note that
75 | * this variant is about 6MiB larger per architecture than default.
76 | */
77 | def jscFlavor = 'org.webkit:android-jsc:+'
78 |
79 | /**
80 | * Private function to get the list of Native Architectures you want to build.
81 | * This reads the value from reactNativeArchitectures in your gradle.properties
82 | * file and works together with the --active-arch-only flag of react-native run-android.
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 | */
92 | def reactNativeArchitectures() {
93 | def value = project.getProperties().get("reactNativeArchitectures")
94 | return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"]
95 | }
96 |
97 | android {
98 | ndkVersion rootProject.ext.ndkVersion
99 |
100 | compileSdkVersion rootProject.ext.compileSdkVersion
101 | namespace "com.helloworld"
102 | defaultConfig {
103 | applicationId "com.helloworld"
104 | minSdkVersion rootProject.ext.minSdkVersion
105 | targetSdkVersion rootProject.ext.targetSdkVersion
106 | versionCode 1
107 | versionName "1.0"
108 | }
109 | splits {
110 | abi {
111 | reset()
112 | enable enableSeparateBuildPerCPUArchitecture
113 | universalApk false // If true, also generate a universal APK
114 | include (*reactNativeArchitectures())
115 | }
116 | }
117 | signingConfigs {
118 | debug {
119 | storeFile file('debug.keystore')
120 | storePassword 'android'
121 | keyAlias 'androiddebugkey'
122 | keyPassword 'android'
123 | }
124 | }
125 | buildTypes {
126 | debug {
127 | signingConfig signingConfigs.debug
128 | }
129 | release {
130 | // Caution! In production, you need to generate your own keystore file.
131 | // see https://reactnative.dev/docs/signed-apk-android.
132 | signingConfig signingConfigs.debug
133 | minifyEnabled enableProguardInReleaseBuilds
134 | proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
135 | }
136 | }
137 |
138 | // applicationVariants are e.g. debug, release
139 | applicationVariants.all { variant ->
140 | variant.outputs.each { output ->
141 | // For each separate APK per architecture, set a unique version code as described here:
142 | // https://developer.android.com/studio/build/configure-apk-splits.html
143 | // Example: versionCode 1 will generate 1001 for armeabi-v7a, 1002 for x86, etc.
144 | def versionCodes = ["armeabi-v7a": 1, "x86": 2, "arm64-v8a": 3, "x86_64": 4]
145 | def abi = output.getFilter(OutputFile.ABI)
146 | if (abi != null) { // null for the universal-debug, universal-release variants
147 | output.versionCodeOverride =
148 | defaultConfig.versionCode * 1000 + versionCodes.get(abi)
149 | }
150 |
151 | }
152 | }
153 | }
154 |
155 | dependencies {
156 | // The version of react-native is set by the React Native Gradle Plugin
157 | implementation("com.facebook.react:react-android")
158 | implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.0.0")
159 | debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}")
160 | debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") {
161 | exclude group:'com.squareup.okhttp3', module:'okhttp'
162 | }
163 | debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}")
164 | if (hermesEnabled.toBoolean()) {
165 | implementation("com.facebook.react:hermes-android")
166 | } else {
167 | implementation jscFlavor
168 | }
169 | }
170 | apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project)
171 |
172 |
--------------------------------------------------------------------------------
/HelloWorld/android/app/debug.keystore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uiwjs/react-native-template/cf63e26fd864fb54b13d52c8760a140ef81ca7ab/HelloWorld/android/app/debug.keystore
--------------------------------------------------------------------------------
/HelloWorld/android/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
--------------------------------------------------------------------------------
/HelloWorld/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/HelloWorld/android/app/src/debug/java/com/helloworld/ReactNativeFlipper.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) Meta Platforms, Inc. and affiliates.
3 | *
4 | *
This source code is licensed under the MIT license found in the LICENSE file in the root
5 | * directory of this source tree.
6 | */
7 | package com.helloworld;
8 |
9 | import android.content.Context;
10 | import com.facebook.flipper.android.AndroidFlipperClient;
11 | import com.facebook.flipper.android.utils.FlipperUtils;
12 | import com.facebook.flipper.core.FlipperClient;
13 | import com.facebook.flipper.plugins.crashreporter.CrashReporterPlugin;
14 | import com.facebook.flipper.plugins.databases.DatabasesFlipperPlugin;
15 | import com.facebook.flipper.plugins.fresco.FrescoFlipperPlugin;
16 | import com.facebook.flipper.plugins.inspector.DescriptorMapping;
17 | import com.facebook.flipper.plugins.inspector.InspectorFlipperPlugin;
18 | import com.facebook.flipper.plugins.network.FlipperOkhttpInterceptor;
19 | import com.facebook.flipper.plugins.network.NetworkFlipperPlugin;
20 |
21 | import com.facebook.flipper.plugins.sharedpreferences.SharedPreferencesFlipperPlugin;
22 | import com.facebook.react.ReactInstanceEventListener;
23 | import com.facebook.react.ReactInstanceManager;
24 | import com.facebook.react.bridge.ReactContext;
25 | import com.facebook.react.modules.network.NetworkingModule;
26 | import okhttp3.OkHttpClient;
27 |
28 | /**
29 | * Class responsible of loading Flipper inside your React Native application. This is the debug
30 | * flavor of it. Here you can add your own plugins and customize the Flipper setup.
31 | */
32 |
33 | public class ReactNativeFlipper {
34 | public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) {
35 | if (FlipperUtils.shouldEnableFlipper(context)) {
36 | final FlipperClient client = AndroidFlipperClient.getInstance(context);
37 |
38 | client.addPlugin(new InspectorFlipperPlugin(context, DescriptorMapping.withDefaults()));
39 |
40 | client.addPlugin(new DatabasesFlipperPlugin(context));
41 | client.addPlugin(new SharedPreferencesFlipperPlugin(context));
42 | client.addPlugin(CrashReporterPlugin.getInstance());
43 |
44 | NetworkFlipperPlugin networkFlipperPlugin = new NetworkFlipperPlugin();
45 | NetworkingModule.setCustomClientBuilder(
46 | new NetworkingModule.CustomClientBuilder() {
47 | @Override
48 | public void apply(OkHttpClient.Builder builder) {
49 | builder.addNetworkInterceptor(new FlipperOkhttpInterceptor(networkFlipperPlugin));
50 | }
51 | });
52 | client.addPlugin(networkFlipperPlugin);
53 | client.start();
54 |
55 | // Fresco Plugin needs to ensure that ImagePipelineFactory is initialized
56 | // Hence we run if after all native modules have been initialized
57 | ReactContext reactContext = reactInstanceManager.getCurrentReactContext();
58 | if (reactContext == null) {
59 | reactInstanceManager.addReactInstanceEventListener(
60 | new ReactInstanceEventListener() {
61 | @Override
62 | public void onReactContextInitialized(ReactContext reactContext) {
63 | reactInstanceManager.removeReactInstanceEventListener(this);
64 | reactContext.runOnNativeModulesQueueThread(
65 | new Runnable() {
66 | @Override
67 | public void run() {
68 | client.addPlugin(new FrescoFlipperPlugin());
69 | }
70 | });
71 | }
72 | });
73 | } else {
74 | client.addPlugin(new FrescoFlipperPlugin());
75 | }
76 | }
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/HelloWorld/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
12 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/HelloWorld/android/app/src/main/java/com/helloworld/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.helloworld;
2 |
3 | import com.facebook.react.ReactActivity;
4 | import com.facebook.react.ReactActivityDelegate;
5 | import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint;
6 | import com.facebook.react.defaults.DefaultReactActivityDelegate;
7 |
8 | public class MainActivity extends ReactActivity {
9 |
10 | /**
11 | * Returns the name of the main component registered from JavaScript. This is used to schedule
12 | * rendering of the component.
13 | */
14 | @Override
15 | protected String getMainComponentName() {
16 | return "HelloWorld";
17 | }
18 |
19 | /**
20 | * Returns the instance of the {@link ReactActivityDelegate}. Here we use a util class {@link
21 | * DefaultReactActivityDelegate} which allows you to easily enable Fabric and Concurrent React
22 | * (aka React 18) with two boolean flags.
23 | */
24 | @Override
25 | protected ReactActivityDelegate createReactActivityDelegate() {
26 | return new DefaultReactActivityDelegate(
27 | this,
28 | getMainComponentName(),
29 | // If you opted-in for the New Architecture, we enable the Fabric Renderer.
30 | DefaultNewArchitectureEntryPoint.getFabricEnabled(), // fabricEnabled
31 | // If you opted-in for the New Architecture, we enable Concurrent React (i.e. React 18).
32 | DefaultNewArchitectureEntryPoint.getConcurrentReactEnabled() // concurrentRootEnabled
33 | );
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/HelloWorld/android/app/src/main/java/com/helloworld/MainApplication.java:
--------------------------------------------------------------------------------
1 | package com.helloworld;
2 |
3 | import android.app.Application;
4 |
5 | import com.facebook.react.PackageList;
6 | import com.facebook.react.ReactApplication;
7 |
8 | import com.facebook.react.ReactNativeHost;
9 | import com.facebook.react.ReactPackage;
10 | import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint;
11 | import com.facebook.react.defaults.DefaultReactNativeHost;
12 | import com.facebook.soloader.SoLoader;
13 | import java.util.List;
14 |
15 | public class MainApplication extends Application implements ReactApplication {
16 |
17 | private final ReactNativeHost mReactNativeHost =
18 | new DefaultReactNativeHost(this) {
19 | @Override
20 | public boolean getUseDeveloperSupport() {
21 | return BuildConfig.DEBUG;
22 | }
23 |
24 | @Override
25 | protected List getPackages() {
26 | @SuppressWarnings("UnnecessaryLocalVariable")
27 | List packages = new PackageList(this).getPackages();
28 | // Packages that cannot be autolinked yet can be added manually here, for example:
29 | // packages.add(new MyReactNativePackage());
30 | return packages;
31 | }
32 |
33 | @Override
34 | protected String getJSMainModuleName() {
35 | return "index";
36 | }
37 | @Override
38 | protected boolean isNewArchEnabled() {
39 | return BuildConfig.IS_NEW_ARCHITECTURE_ENABLED;
40 | }
41 | @Override
42 | protected Boolean isHermesEnabled() {
43 | return BuildConfig.IS_HERMES_ENABLED;
44 | }
45 | };
46 | @Override
47 | public ReactNativeHost getReactNativeHost() {
48 | return mReactNativeHost;
49 | }
50 | @Override
51 | public void onCreate() {
52 | super.onCreate();
53 | SoLoader.init(this, /* native exopackage */ false);
54 | if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
55 | // If you opted-in for the New Architecture, we load the native entry point for this app.
56 | DefaultNewArchitectureEntryPoint.load();
57 | }
58 | ReactNativeFlipper.initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
59 | }
60 | }
--------------------------------------------------------------------------------
/HelloWorld/android/app/src/main/res/drawable/rn_edit_text_material.xml:
--------------------------------------------------------------------------------
1 |
2 |
16 |
21 |
22 |
23 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/HelloWorld/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uiwjs/react-native-template/cf63e26fd864fb54b13d52c8760a140ef81ca7ab/HelloWorld/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/HelloWorld/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uiwjs/react-native-template/cf63e26fd864fb54b13d52c8760a140ef81ca7ab/HelloWorld/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/HelloWorld/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uiwjs/react-native-template/cf63e26fd864fb54b13d52c8760a140ef81ca7ab/HelloWorld/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/HelloWorld/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uiwjs/react-native-template/cf63e26fd864fb54b13d52c8760a140ef81ca7ab/HelloWorld/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/HelloWorld/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uiwjs/react-native-template/cf63e26fd864fb54b13d52c8760a140ef81ca7ab/HelloWorld/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/HelloWorld/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uiwjs/react-native-template/cf63e26fd864fb54b13d52c8760a140ef81ca7ab/HelloWorld/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/HelloWorld/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uiwjs/react-native-template/cf63e26fd864fb54b13d52c8760a140ef81ca7ab/HelloWorld/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/HelloWorld/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uiwjs/react-native-template/cf63e26fd864fb54b13d52c8760a140ef81ca7ab/HelloWorld/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/HelloWorld/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uiwjs/react-native-template/cf63e26fd864fb54b13d52c8760a140ef81ca7ab/HelloWorld/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/HelloWorld/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uiwjs/react-native-template/cf63e26fd864fb54b13d52c8760a140ef81ca7ab/HelloWorld/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/HelloWorld/android/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | HelloWorld
3 |
4 |
--------------------------------------------------------------------------------
/HelloWorld/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/HelloWorld/android/app/src/release/java/com/helloworld/ReactNativeFlipper.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) Meta Platforms, Inc. and affiliates.
3 | *
4 | * This source code is licensed under the MIT license found in the LICENSE file in the root
5 | * directory of this source tree.
6 | */
7 | package com.helloworld;
8 | import android.content.Context;
9 | import com.facebook.react.ReactInstanceManager;
10 | /**
11 | * Class responsible of loading Flipper inside your React Native application. This is the release
12 | * flavor of it so it's empty as we don't want to load Flipper.
13 | */
14 | public class ReactNativeFlipper {
15 | public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) {
16 | // Do nothing as we don't want to initialize Flipper on Release.
17 | }
18 | }
--------------------------------------------------------------------------------
/HelloWorld/android/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | ext {
5 | buildToolsVersion = "33.0.0"
6 | minSdkVersion = 21
7 | compileSdkVersion = 33
8 | targetSdkVersion = 33
9 |
10 | // We use NDK 23 which has both M1 support and is the side-by-side NDK version from AGP.
11 | ndkVersion = "23.1.7779620"
12 | }
13 | repositories {
14 | google()
15 | mavenCentral()
16 | }
17 | dependencies {
18 | classpath("com.android.tools.build:gradle:7.3.1")
19 | classpath("com.facebook.react:react-native-gradle-plugin")
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/HelloWorld/android/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx512m -XX:MaxMetaspaceSize=256m
13 | org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
19 |
20 | # AndroidX package structure to make it clearer which packages are bundled with the
21 | # Android operating system, and which are packaged with your app's APK
22 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
23 | android.useAndroidX=true
24 | # Automatically convert third-party libraries to use AndroidX
25 | android.enableJetifier=true
26 |
27 | # Version of flipper SDK to use with React Native
28 | FLIPPER_VERSION=0.125.0
29 |
30 | # Use this property to specify which architecture you want to build.
31 | # You can also override it from the CLI using
32 | # ./gradlew -PreactNativeArchitectures=x86_64
33 | reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64
34 |
35 | # Use this property to enable support to the new architecture.
36 | # This will allow you to use TurboModules and the Fabric render in
37 | # your application. You should enable this flag either if you want
38 | # to write custom TurboModules/Fabric components OR use libraries that
39 | # are providing them.
40 | newArchEnabled=false
41 |
42 |
43 | # Use this property to enable or disable the Hermes JS engine.
44 | # If set to false, you will be using JSC instead.
45 | hermesEnabled=true
46 |
--------------------------------------------------------------------------------
/HelloWorld/android/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uiwjs/react-native-template/cf63e26fd864fb54b13d52c8760a140ef81ca7ab/HelloWorld/android/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/HelloWorld/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-all.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/HelloWorld/android/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/HelloWorld/android/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'HelloWorld'
2 | apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings)
3 | include ':app'
4 | includeBuild('../node_modules/react-native-gradle-plugin')
5 |
--------------------------------------------------------------------------------
/HelloWorld/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "HelloWorld",
3 | "displayName": "HelloWorld"
4 | }
--------------------------------------------------------------------------------
/HelloWorld/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: ['module:metro-react-native-babel-preset'],
3 | plugins: [
4 | 'react-native-reanimated/plugin'
5 | ]
6 | };
7 |
--------------------------------------------------------------------------------
/HelloWorld/index.js:
--------------------------------------------------------------------------------
1 | import {AppRegistry} from 'react-native';
2 | import App from './src/App';
3 | import {name as appName} from './app.json';
4 |
5 | AppRegistry.registerComponent(appName, () => App);
6 |
--------------------------------------------------------------------------------
/HelloWorld/ios/.xcode.env:
--------------------------------------------------------------------------------
1 | export NODE_BINARY=$(command -v node)
2 |
--------------------------------------------------------------------------------
/HelloWorld/ios/HelloWorld.xcodeproj/xcshareddata/xcschemes/HelloWorld.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
33 |
39 |
40 |
41 |
42 |
43 |
53 |
55 |
61 |
62 |
63 |
64 |
70 |
72 |
78 |
79 |
80 |
81 |
83 |
84 |
87 |
88 |
89 |
--------------------------------------------------------------------------------
/HelloWorld/ios/HelloWorld.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/HelloWorld/ios/HelloWorld.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/HelloWorld/ios/HelloWorld/AppDelegate.h:
--------------------------------------------------------------------------------
1 | #import
2 | #import
3 |
4 | @interface AppDelegate : RCTAppDelegate
5 |
6 | @end
7 |
--------------------------------------------------------------------------------
/HelloWorld/ios/HelloWorld/AppDelegate.mm:
--------------------------------------------------------------------------------
1 | #import "AppDelegate.h"
2 |
3 | #import
4 |
5 |
6 |
7 |
8 | @implementation AppDelegate
9 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
10 | {
11 | self.moduleName = @"HelloWorld";
12 | // You can add your custom initial props in the dictionary below.
13 | // They will be passed down to the ViewController used by React Native.
14 | self.initialProps = @{};
15 | return [super application:application didFinishLaunchingWithOptions:launchOptions];
16 | }
17 |
18 | - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
19 | {
20 | #if DEBUG
21 | return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"];
22 | #else
23 | return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
24 | #endif
25 | }
26 | /// This method controls whether the `concurrentRoot`feature of React18 is turned on or off.
27 | ///
28 | /// @see: https://reactjs.org/blog/2022/03/29/react-v18.html
29 | /// @note: This requires to be rendering on Fabric (i.e. on the New Architecture).
30 | /// @return: `true` if the `concurrentRoot` feature is enabled. Otherwise, it returns `false`.
31 | - (BOOL)concurrentRootEnabled
32 | {
33 | return true;
34 | }
35 | @end
36 |
--------------------------------------------------------------------------------
/HelloWorld/ios/HelloWorld/Images.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "scale" : "2x",
6 | "size" : "20x20"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "scale" : "3x",
11 | "size" : "20x20"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "scale" : "2x",
16 | "size" : "29x29"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "scale" : "3x",
21 | "size" : "29x29"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "scale" : "2x",
26 | "size" : "40x40"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "scale" : "3x",
31 | "size" : "40x40"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "scale" : "2x",
36 | "size" : "60x60"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "scale" : "3x",
41 | "size" : "60x60"
42 | },
43 | {
44 | "idiom" : "ios-marketing",
45 | "scale" : "1x",
46 | "size" : "1024x1024"
47 | }
48 | ],
49 | "info" : {
50 | "author" : "xcode",
51 | "version" : 1
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/HelloWorld/ios/HelloWorld/Images.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/HelloWorld/ios/HelloWorld/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleDisplayName
8 | HelloWorld
9 | CFBundleExecutable
10 | $(EXECUTABLE_NAME)
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | 1.0.0
21 | CFBundleSignature
22 | ????
23 | CFBundleVersion
24 | 1
25 | LSRequiresIPhoneOS
26 |
27 | NSAppTransportSecurity
28 |
29 | NSExceptionDomains
30 |
31 | localhost
32 |
33 | NSExceptionAllowsInsecureHTTPLoads
34 |
35 |
36 |
37 |
38 | NSLocationWhenInUseUsageDescription
39 |
40 | UILaunchStoryboardName
41 | LaunchScreen
42 | UIRequiredDeviceCapabilities
43 |
44 | armv7
45 |
46 | UISupportedInterfaceOrientations
47 |
48 | UIInterfaceOrientationPortrait
49 | UIInterfaceOrientationLandscapeLeft
50 | UIInterfaceOrientationLandscapeRight
51 |
52 | UIViewControllerBasedStatusBarAppearance
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/HelloWorld/ios/HelloWorld/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
24 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/HelloWorld/ios/HelloWorld/main.m:
--------------------------------------------------------------------------------
1 | #import
2 |
3 | #import "AppDelegate.h"
4 |
5 | int main(int argc, char *argv[])
6 | {
7 | @autoreleasepool {
8 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
9 | }
10 | }
--------------------------------------------------------------------------------
/HelloWorld/ios/HelloWorldTests/HelloWorldTests.m:
--------------------------------------------------------------------------------
1 | #import
2 | #import
3 |
4 | #import
5 | #import
6 |
7 | #define TIMEOUT_SECONDS 600
8 | #define TEXT_TO_LOOK_FOR @"Welcome to React"
9 |
10 | @interface HelloWorldTests : XCTestCase
11 |
12 | @end
13 |
14 | @implementation HelloWorldTests
15 |
16 | - (BOOL)findSubviewInView:(UIView *)view matching:(BOOL (^)(UIView *view))test
17 | {
18 | if (test(view)) {
19 | return YES;
20 | }
21 | for (UIView *subview in [view subviews]) {
22 | if ([self findSubviewInView:subview matching:test]) {
23 | return YES;
24 | }
25 | }
26 | return NO;
27 | }
28 |
29 | - (void)testRendersWelcomeScreen
30 | {
31 | UIViewController *vc = [[[RCTSharedApplication() delegate] window] rootViewController];
32 | NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS];
33 | BOOL foundElement = NO;
34 |
35 | __block NSString *redboxError = nil;
36 | #ifdef DEBUG
37 | RCTSetLogFunction(
38 | ^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) {
39 | if (level >= RCTLogLevelError) {
40 | redboxError = message;
41 | }
42 | });
43 | #endif
44 |
45 | while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) {
46 | [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
47 | [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
48 |
49 | foundElement = [self findSubviewInView:vc.view
50 | matching:^BOOL(UIView *view) {
51 | if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) {
52 | return YES;
53 | }
54 | return NO;
55 | }];
56 | }
57 |
58 | #ifdef DEBUG
59 | RCTSetLogFunction(RCTDefaultLogFunction);
60 | #endif
61 |
62 | XCTAssertNil(redboxError, @"RedBox error: %@", redboxError);
63 | XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS);
64 | }
65 |
66 | @end
67 |
--------------------------------------------------------------------------------
/HelloWorld/ios/HelloWorldTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/HelloWorld/ios/Podfile:
--------------------------------------------------------------------------------
1 | require_relative '../node_modules/react-native/scripts/react_native_pods'
2 | require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'
3 |
4 | platform :ios, min_ios_version_supported
5 | prepare_react_native_project!
6 | # If you are using a `react-native-flipper` your iOS build will fail when `NO_FLIPPER=1` is set.
7 | # because `react-native-flipper` depends on (FlipperKit,...) that will be excluded
8 | #
9 | # To fix this you can also exclude `react-native-flipper` using a `react-native.config.js`
10 | # ```js
11 | # module.exports = {
12 | # dependencies: {
13 | # ...(process.env.NO_FLIPPER ? { 'react-native-flipper': { platforms: { ios: null } } } : {}),
14 | # ```
15 | flipper_config = ENV['NO_FLIPPER'] == "1" ? FlipperConfiguration.disabled : FlipperConfiguration.enabled
16 | linkage = ENV['USE_FRAMEWORKS']
17 | if linkage != nil
18 | Pod::UI.puts "Configuring Pod with #{linkage}ally linked Frameworks".green
19 | use_frameworks! :linkage => linkage.to_sym
20 | end
21 |
22 |
23 | target 'HelloWorld' do
24 | config = use_native_modules!
25 |
26 | # Flags change depending on the env values.
27 | flags = get_default_flags()
28 |
29 | use_react_native!(
30 | :path => config[:reactNativePath],
31 | # Hermes is now enabled by default. Disable by setting this flag to false.
32 | # Upcoming versions of React Native may rely on get_default_flags(), but
33 | # we make it explicit here to aid in the React Native upgrade process.
34 | :hermes_enabled => false,
35 | :fabric_enabled => true,
36 | # Enables Flipper.
37 | #
38 | # Note that if you have use_frameworks! enabled, Flipper will not work and
39 | # you should disable the next line.
40 | :flipper_configuration => flipper_config,
41 | # An absolute path to your application root.
42 | :app_path => "#{Pod::Config.instance.installation_root}/.."
43 | )
44 |
45 | target 'HelloWorldTests' do
46 | inherit! :complete
47 | # Pods for testing
48 | end
49 |
50 | post_install do |installer|
51 | react_native_post_install(
52 | installer,
53 | # Set `mac_catalyst_enabled` to `true` in order to apply patches
54 | # necessary for Mac Catalyst builds
55 | :mac_catalyst_enabled => false
56 | )
57 | __apply_Xcode_12_5_M1_post_install_workaround(installer)
58 | end
59 | end
60 |
--------------------------------------------------------------------------------
/HelloWorld/ios/_xcode.env:
--------------------------------------------------------------------------------
1 | # This `.xcode.env` file is versioned and is used to source the environment
2 | # used when running script phases inside Xcode.
3 | # To customize your local environment, you can create an `.xcode.env.local`
4 | # file that is not versioned.
5 |
6 | # NODE_BINARY variable contains the PATH to the node executable.
7 | #
8 | # Customize the NODE_BINARY variable here.
9 | # For example, to use nvm with brew, add the following line
10 | # . "$(brew --prefix nvm)/nvm.sh" --no-use
11 | export NODE_BINARY=$(command -v node)
12 |
--------------------------------------------------------------------------------
/HelloWorld/jsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": ".",
4 | "paths": {
5 | "@": ["src/*"],
6 | "@components/*": ["src/components/*"],
7 | "@utils/*": ["src/utils/*"]
8 | }
9 | }
10 | }
--------------------------------------------------------------------------------
/HelloWorld/metro.config.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Metro configuration for React Native
3 | * https://github.com/facebook/react-native
4 | *
5 | * @format
6 | */
7 |
8 | module.exports = {
9 | transformer: {
10 | getTransformOptions: async () => ({
11 | transform: {
12 | experimentalImportSupport: false,
13 | inlineRequires: true,
14 | },
15 | }),
16 | },
17 | };
18 |
--------------------------------------------------------------------------------
/HelloWorld/mocker/index.js:
--------------------------------------------------------------------------------
1 | const delay = require('mocker-api/lib/delay');
2 | const user = require('./user.mock');
3 |
4 | // 是否禁用代理
5 | const noProxy = process.env.NO_PROXY === 'true';
6 |
7 | const proxy = {
8 | ...user,
9 | };
10 |
11 | module.exports = noProxy ? {...proxy} : delay(proxy, 1000);
12 | // module.exports = proxy;
13 |
--------------------------------------------------------------------------------
/HelloWorld/mocker/user.mock.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | 'POST /api/login': (req, res) => {
3 | let {username, password} = req.body;
4 | if (username === 'admin' && password === 'admin!') {
5 | return res.status(201).json({
6 | message: 'Login successful!',
7 | token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9',
8 | data: {
9 | nikename: 'Hello App',
10 | },
11 | });
12 | }
13 | res.status(401).json({
14 | message: 'username or password is error.',
15 | });
16 | },
17 | 'POST /api/logout': {
18 | message: 'Logout successful!',
19 | },
20 | 'GET /api/auth': {
21 | token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9',
22 | // token: '',
23 | },
24 | };
25 |
--------------------------------------------------------------------------------
/HelloWorld/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "HelloWorld",
3 | "version": "0.0.1",
4 | "private": true,
5 | "scripts": {
6 | "android": "react-native run-android",
7 | "ios": "react-native run-ios --simulator 'iPhone 14'",
8 | "start": "react-native start --reset-cache",
9 | "test": "jest",
10 | "api": "mocker ./mocker",
11 | "api2": "NO_PROXY=true mocker ./mocker",
12 | "lint": "eslint . --ext .js,.jsx",
13 | "prettier": "prettier --write '**/*.{js,jsx,md,json}'",
14 | "precommit": "npm run lint",
15 | "lint-staged": "lint-staged",
16 | "doc": "kktd @uiw/react-native-doc/doc/build"
17 | },
18 | "dependencies": {
19 | "@react-native-async-storage/async-storage": "~1.17.11",
20 | "@react-native-community/masked-view": "~0.1.11",
21 | "@react-navigation/bottom-tabs": "~6.3.2",
22 | "@react-navigation/native": "~6.0.11",
23 | "@react-navigation/stack": "~6.2.2",
24 | "react-native-safe-area-context": "~4.3.1",
25 | "react-native-reanimated": "3.1.0",
26 | "@rematch/core": "2.2.0",
27 | "@rematch/loading": "2.1.2",
28 | "@uiw/formatter": "~1.3.3",
29 | "@uiw/react-native": "^4.0.2",
30 | "react-native-gesture-handler": "2.8.0",
31 | "react-native-root-siblings":"4.1.1",
32 | "react-native-svg": "13.9.0",
33 | "react": "18.2.0",
34 | "react-native": "0.71.7",
35 | "react-native-device-info": "~10.0.2",
36 | "react-native-screens": "~3.15.0",
37 | "react-redux": "8.0.5",
38 | "redux": "4.1.2",
39 | "react-query": "~3.39.2",
40 | "@kkt/doc": "^1.0.0",
41 | "@uiw/react-native-doc": "^4.0.5"
42 | },
43 | "devDependencies": {
44 | "@babel/core": "~7.20.0",
45 | "@babel/preset-env": "^7.20.0",
46 | "@babel/runtime": "~7.20.0",
47 | "@react-native-community/eslint-config": "3.2.0",
48 | "@tsconfig/react-native": "^2.0.2",
49 | "@types/jest": "^29.2.1",
50 | "@types/react": "^18.0.24",
51 | "@types/react-test-renderer": "^18.0.0",
52 | "babel-jest": "~29.2.1",
53 | "babel-plugin-module-resolver": "^4.1.0",
54 | "eslint": "~8.21.0",
55 | "eslint-plugin-prettier": "~4.2.1",
56 | "husky": "^8.0.0",
57 | "jest": "29.2.1",
58 | "lint-staged": "~12.5.0",
59 | "metro-react-native-babel-preset": "^0.73.9",
60 | "mocker-api": "~2.9.5",
61 | "prettier": "^2.8.0",
62 | "react-test-renderer": "18.2.0",
63 | "typescript": "4.8.4"
64 | },
65 | "lint-staged": {
66 | "*.{js,jsx}": [
67 | "eslint --fix",
68 | "git add"
69 | ],
70 | "*.{js,jsx,md,json}": [
71 | "prettier --write"
72 | ]
73 | },
74 | "jest": {
75 | "preset": "react-native"
76 | }
77 | }
--------------------------------------------------------------------------------
/HelloWorld/src/App.js:
--------------------------------------------------------------------------------
1 | import 'react-native-gesture-handler';
2 | import React from 'react';
3 | import {StatusBar, useColorScheme} from 'react-native';
4 | import {NavigationContainer, useNavigationContainerRef, DefaultTheme, DarkTheme} from '@react-navigation/native';
5 | import {createStackNavigator} from '@react-navigation/stack';
6 | import {Provider} from 'react-redux';
7 | import {store} from './models';
8 | import AuthLoadingScreen from './pages/AuthLoading';
9 | import {stackPageData} from './routes';
10 | import {QueryClient, QueryClientProvider} from 'react-query';
11 | import {ThemeProvider, theme} from '@uiw/react-native';
12 |
13 | const Stack = createStackNavigator();
14 | const queryClient = new QueryClient();
15 |
16 | export default () => {
17 | const navigationRef = useNavigationContainerRef();
18 | const colorScheme = useColorScheme();
19 | return (
20 |
21 |
22 |
23 |
24 |
25 |
26 | {token => (
27 |
28 | {stackPageData.map((props, index) => {
29 | return (
30 | null
36 | // }}
37 | // component={Home}
38 | />
39 | );
40 | })}
41 |
42 | )}
43 |
44 |
45 |
46 |
47 |
48 | );
49 | };
50 |
--------------------------------------------------------------------------------
/HelloWorld/src/components/Footer/index.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 | import {Text, StyleSheet} from 'react-native';
3 | import {Flex, Icon} from '@uiw/react-native';
4 |
5 | export default class Footer extends Component {
6 | render() {
7 | const {style} = this.props;
8 | return (
9 |
10 | Shanghai xxx xxx xxx Co., Ltd.
11 | Copyright © 2020-2025
12 |
13 | );
14 | }
15 | }
16 |
17 | const styles = StyleSheet.create({
18 | footer: {
19 | fontSize: 12,
20 | paddingVertical: 10,
21 | },
22 | copyright: {
23 | color: '#C2C2C2',
24 | fontSize: 12,
25 | },
26 | company: {
27 | paddingTop: 10,
28 | paddingBottom: 3,
29 | color: '#C2C2C2',
30 | fontSize: 12,
31 | },
32 | });
33 |
--------------------------------------------------------------------------------
/HelloWorld/src/components/icons/signin.js:
--------------------------------------------------------------------------------
1 | export const logo = `
2 |
5 | `;
6 | export const logoLight = `
7 |
10 | `;
11 |
--------------------------------------------------------------------------------
/HelloWorld/src/config.js:
--------------------------------------------------------------------------------
1 | import {getUniqueId, getVersion} from 'react-native-device-info';
2 |
3 | export default {
4 | /**
5 | * AndroidX Support
6 | * This module defaults to AndroidX you should configure your library versions similar to
7 | * this in your `android/build.gradle` file's "ext" block
8 | * https://www.npmjs.com/package/react-native-device-info#androidx-support
9 | */
10 | uid: getUniqueId(),
11 | /**
12 | * Gets the application version.
13 | */
14 | version: getVersion(),
15 | /**
16 | * The production value is `true` and there is no host option interface.
17 | */
18 | production: false,
19 | /**
20 | * Default first.
21 | */
22 | hosts: [
23 | {
24 | label: 'Native Mock API',
25 | type: 'Test',
26 | url: 'http://localhost:3721',
27 | },
28 | {
29 | label: 'Production Environment',
30 | type: 'production',
31 | url: 'http://103.20.249.82:18901',
32 | },
33 | ],
34 | };
35 |
--------------------------------------------------------------------------------
/HelloWorld/src/global.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Store some global objects for easy calling
3 | *
4 | * - `navigation` Route go to page object
5 | */
6 |
7 | export default {};
8 |
--------------------------------------------------------------------------------
/HelloWorld/src/hooks/users.js:
--------------------------------------------------------------------------------
1 | import { Alert } from 'react-native';
2 | import AsyncStorage from '@react-native-async-storage/async-storage';
3 | import { userLogin, userAuth } from '../services/users';
4 | import { useQuery, useMutation } from 'react-query';
5 | import Global from '../global';
6 | import conf from '../config';
7 | import { useSelector, useDispatch } from 'react-redux'
8 | // 登录
9 | export const login = ({ mutationKey }) => {
10 | const dispatch = useDispatch()
11 | const mutation = useMutation({
12 | mutationKey,
13 | mutationFn: userLogin,
14 | onSuccess: async data => {
15 | if (data?.token && data?.data) {
16 | await AsyncStorage.setItem('token', data.token);
17 | await AsyncStorage.setItem('userData', JSON.stringify(data.data));
18 | dispatch({
19 | type: "global/update",
20 | payload: {
21 | token: data.token,
22 | userData: JSON.stringify(data.data)
23 | }
24 | })
25 | if (Global.navigation) {
26 | Global.navigation.replace('Tab');
27 | }
28 | } else if (data && data.message) {
29 | Alert.alert(`Login failed - ${data.error}`, data.message);
30 | }
31 | },
32 | });
33 | return mutation;
34 | };
35 |
36 | // 验证token
37 | export const useAuthToken = () => {
38 | const { token } = useSelector(state => state.global)
39 | const dispatch = useDispatch()
40 | const mutation = useMutation({
41 | mutationFn: userAuth,
42 | onMutate: async () => {
43 | let host = await AsyncStorage.getItem('apihost');
44 | if (!host && conf.hosts[0]) {
45 | await AsyncStorage.setItem('apihost', JSON.stringify(conf.hosts[0]));
46 | dispatch({
47 | type: "global/update",
48 | payload: {
49 | apihost: conf.hosts[0]
50 | }
51 | })
52 | }
53 | if (!token) {
54 | await AsyncStorage.removeItem('userData');
55 | await AsyncStorage.removeItem('token');
56 | }
57 | },
58 | onSuccess: async data => {
59 | if (data?.token) {
60 | dispatch({
61 | type: "global/update",
62 | payload: {
63 | token: data.token,
64 | authState: true
65 | }
66 | })
67 | } else {
68 | dispatch({
69 | type: "global/update",
70 | payload: {
71 | authState: true,
72 | token: null
73 | }
74 | })
75 | }
76 | },
77 | });
78 | return mutation;
79 | };
80 |
81 | // 退出
82 | export const logout = () => {
83 | const dispatch = useDispatch()
84 | AsyncStorage.removeItem('token');
85 | AsyncStorage.removeItem('userData');
86 | dispatch({
87 | type: "global/update",
88 | payload: {
89 | token: null,
90 | authState: null
91 | }
92 | })
93 | if (Global.navigation) {
94 | Global.navigation.navigate?.('SignIn');
95 | }
96 | };
97 |
--------------------------------------------------------------------------------
/HelloWorld/src/models/global.js:
--------------------------------------------------------------------------------
1 | import AsyncStorage from '@react-native-async-storage/async-storage';
2 | import { userAuth } from '../services/users';
3 | import conf from '../config';
4 |
5 | export default {
6 | state: {
7 | /**
8 | * 验证是否登录
9 | */
10 | authState: false,
11 | token: null,
12 | apihost: null,
13 | userData: null,
14 | },
15 | reducers: {
16 | update: (state, payload) => ({ ...state, ...payload }),
17 | },
18 | effects: dispatch => ({}),
19 | };
20 |
--------------------------------------------------------------------------------
/HelloWorld/src/models/index.js:
--------------------------------------------------------------------------------
1 | import {init} from '@rematch/core';
2 | import createLoadingPlugin from '@rematch/loading';
3 | import * as global from './global';
4 |
5 | const loadingPlugin = createLoadingPlugin({});
6 |
7 | export const store = init({
8 | models: {
9 | global: global.default,
10 | },
11 | plugins: [
12 | loadingPlugin,
13 | // {
14 | // middleware: () => next => async (action) => {
15 | // // if (typeof window !== 'undefined') {
16 | // // const token = cookie.get('token');
17 | // // if (token) {
18 | // // await cookie.set('token', token, 1);
19 | // // }
20 | // // }
21 | // // do something here
22 | // return next(action);
23 | // },
24 | // },
25 | ],
26 | });
27 |
--------------------------------------------------------------------------------
/HelloWorld/src/pages/AuthLoading/index.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from 'react';
2 | import { Text, StatusBar, StyleSheet, SafeAreaView } from 'react-native';
3 | import { useSelector } from 'react-redux';
4 | import { Flex, Loader, H3, Icon } from '@uiw/react-native';
5 | import Global from '../../global';
6 | import { logoLight } from '../../components/icons/signin';
7 | import Footer from '../../components/Footer';
8 | import { useAuthToken } from '../../hooks/users'
9 |
10 |
11 | const AuthLoadingScreen = ({
12 | navigation,
13 | children
14 | }) => {
15 | const { token, authState } = useSelector(state=>state.global)
16 | const { mutate, isLoading } = useAuthToken()
17 |
18 | useEffect(() => {
19 | if (navigation && Global) {
20 | Global.navigation = navigation;
21 | }
22 | mutate();
23 | }, [])
24 |
25 | if (children && typeof children === 'function' && authState) {
26 | return children(token);
27 | }
28 | return (
29 |
30 |
31 |
32 |
33 |
34 | My APP
35 |
36 |
37 | Verify login...} />
38 |
39 |
40 |
41 |
42 | );
43 | }
44 |
45 | export default AuthLoadingScreen
46 |
47 | const styles = StyleSheet.create({
48 | container: {
49 | flex: 1,
50 | backgroundColor: '#2F2F2F',
51 | },
52 | header: {
53 | marginTop: 110,
54 | },
55 | title: {
56 | marginTop: 30,
57 | fontWeight: '500',
58 | color: '#FFFFFF',
59 | },
60 | });
61 |
--------------------------------------------------------------------------------
/HelloWorld/src/pages/DevOptions/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { connect } from 'react-redux';
3 | import AsyncStorage from '@react-native-async-storage/async-storage';
4 | import { TextInput, SafeAreaView, View, Text, StatusBar, StyleSheet, ScrollView, Platform, KeyboardAvoidingView } from 'react-native';
5 | import { Button, WingBlank, Icon, Flex, Spacing, H4, List } from '@uiw/react-native';
6 | import conf from '../../config';
7 |
8 | class DevOptions extends React.Component {
9 | constructor(props) {
10 | super(props);
11 | this.state = {
12 | dataList: [...conf.hosts],
13 | selectUrl: {},
14 | height: 0,
15 | };
16 | }
17 | async componentDidMount() {
18 | // 选择的 API URL
19 | let apihost = await AsyncStorage.getItem('apihost');
20 | const cacheData = await AsyncStorage.getItem('cacheURLData');
21 | const state = {};
22 | if (cacheData) {
23 | state.dataList = JSON.parse(cacheData);
24 | } else {
25 | state.dataList = this.state.dataList;
26 | }
27 | if (apihost) {
28 | apihost = JSON.parse(apihost);
29 | const selectUrl = state.dataList.find(item => item.url === apihost.url);
30 | state.selectUrl = selectUrl || {};
31 | }
32 | // eslint-disable-next-line react/no-did-mount-set-state
33 | this.setState({ ...state });
34 | }
35 | async handleSelect(data) {
36 | await this.setState({ selectUrl: data });
37 | await AsyncStorage.setItem('apihost', JSON.stringify(data));
38 | this.props.update({ apihost: data });
39 | }
40 | async handleEndEditing(e) {
41 | const { dataList } = this.state;
42 | const text = e.nativeEvent.text;
43 | const isInclude = dataList.find(item => item.url === text);
44 | if (!isInclude && text) {
45 | const customUrl = { url: text, label: 'Custom URL', type: 'custom' };
46 | dataList.unshift(customUrl);
47 | await AsyncStorage.setItem('cacheURLData', JSON.stringify(dataList));
48 | this.setState({ dataList, selectUrl: customUrl, customUrl: '' });
49 | }
50 | }
51 | deleteCustomUrl = async () => {
52 | const { dataList, selectUrl } = this.state;
53 | const data = dataList.filter(item => item.url !== selectUrl.url);
54 | this.setState({ dataList: data, selectUrl: {} });
55 | await AsyncStorage.setItem('cacheURLData', JSON.stringify(data));
56 | };
57 | handleCustomUrl = async customUrl => {
58 | await this.setState({ customUrl });
59 | };
60 | measureContainer = event => {
61 | const { height } = event.nativeEvent.layout;
62 | this.setState({ height });
63 | };
64 | render() {
65 | const { navigation } = this.props;
66 | const DataSourceView = (
67 |
68 |
69 |
81 |
82 |
83 | {this.state.dataList.map((item, idx) => (
84 |
90 | {item.url === this.state.selectUrl.url && }
91 | {item.label}
92 |
93 | ))}
94 |
95 |
96 | );
97 | return (
98 |
99 |
100 |
101 |
102 |
105 |
106 |
107 |
108 | Select Host
109 |
110 |
111 | {Platform.OS === 'ios' ? (
112 |
113 | {DataSourceView}
114 |
115 | ) : (
116 | DataSourceView
117 | )}
118 | {this.state.selectUrl.type === 'custom' && (
119 |
120 |
123 |
124 | )}
125 |
126 |
127 |
128 | );
129 | }
130 | }
131 |
132 | export default connect(
133 | ({ }) => ({}),
134 | ({ global }) => ({
135 | update: global.update,
136 | }),
137 | )(DevOptions);
138 |
139 | const styles = StyleSheet.create({
140 | block: {
141 | flex: 1,
142 | backgroundColor: '#2F2F2F',
143 | },
144 | title: {
145 | color: '#fff',
146 | },
147 | urlListIcon: {
148 | marginRight: 5,
149 | },
150 | input: {
151 | backgroundColor: '#636363',
152 | paddingHorizontal: 10,
153 | paddingVertical: 10,
154 | borderRadius: 5,
155 | color: '#fff',
156 | fontWeight: '200',
157 | fontSize: 16,
158 | },
159 | header: {
160 | paddingTop: 53,
161 | paddingBottom: 30,
162 | },
163 | content: {
164 | backgroundColor: '#efefef',
165 | borderRadius: 8,
166 | },
167 | btn: {
168 | width: '100%',
169 | paddingHorizontal: 5,
170 | paddingVertical: 16,
171 | textAlign: 'center',
172 | fontSize: 20,
173 | },
174 | footer: {
175 | borderWidth: 1,
176 | },
177 | });
178 |
--------------------------------------------------------------------------------
/HelloWorld/src/pages/MyHome/Setting/index.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 | import {View, SafeAreaView} from 'react-native';
3 |
4 | export default class MyScreen extends Component {
5 | render() {
6 | return (
7 |
8 | );
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/HelloWorld/src/pages/MyHome/index.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 | import {View, SafeAreaView} from 'react-native';
3 | import {Button, List, Icon, Text} from '@uiw/react-native';
4 |
5 | export default class MyScreen extends Component {
6 | render() {
7 | const {navigation} = this.props;
8 | return (
9 |
10 |
11 | navigation.navigate('MyHomeSetting')},
17 | {title: '退出登录', onPress: () => navigation.replace('SignIn')},
18 | ]}
19 | renderItem={({item, index}) => {
20 | return (
21 | }
24 | size="large"
25 | paddingLeft={15}
26 | style={{borderBottomWidth: 0}}
27 | onPress={item.onPress || null}>
28 |
29 | {item.title}
30 |
31 |
32 | );
33 | }}
34 | />
35 |
36 |
37 | );
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/HelloWorld/src/pages/OrderHome/index.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 | import {SafeAreaView} from 'react-native';
3 |
4 | export default class MyScreen extends Component {
5 | render() {
6 | return ;
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/HelloWorld/src/pages/SignIn/index.js:
--------------------------------------------------------------------------------
1 | import React, { Component, useState, useEffect } from 'react';
2 | import { connect } from 'react-redux';
3 | import AsyncStorage from '@react-native-async-storage/async-storage';
4 | import { TextInput, SafeAreaView, StyleSheet, StatusBar, Text } from 'react-native';
5 | import { Button, H4, Flex, Spacing, P, Icon, CheckBox, Badge } from '@uiw/react-native';
6 | import Global from '../../global';
7 | import Footer from '../../components/Footer';
8 | import { logoLight } from '../../components/icons/signin';
9 | import conf from '../../config';
10 | import { login } from '../../hooks/users'
11 |
12 | const SigninScreen = ({
13 | navigation,
14 | }) => {
15 | const [store, setStore] = useState({
16 | hostType: '',
17 | formData: {
18 | username: 'admin',
19 | password: 'admin!',
20 | },
21 | })
22 | const { hostType, formData } = store
23 |
24 | const { mutate, isLoading } = login({ mutationKey: ['userLogin', formData] })
25 |
26 | useEffect(() => {
27 | if (navigation && Global) {
28 | Global.navigation = navigation;
29 | }
30 | _getHostType();
31 | }, [])
32 |
33 | const _getHostType = async () => {
34 | if (conf.production) {
35 | const productionOptions = conf.hosts.find(itm => itm.type === 'production');
36 | await AsyncStorage.setItem('apihost', JSON.stringify(productionOptions));
37 | } else {
38 | const host = await AsyncStorage.getItem('apihost');
39 | setStore({ ...store, hostType: JSON.parse(host).type })
40 | }
41 | };
42 |
43 | const loginIn = () => mutate?.(formData)
44 |
45 | return (
46 |
47 |
48 | {!conf.production && (
49 |
50 |
53 |
54 | )}
55 |
56 |
57 |
58 |
59 | Sign In
60 | {!conf.production && {hostType}}
61 | Enter username and password.
62 |
63 |
64 |
65 | setStore({ ...store, formData: { ...formData, username: text } })}
72 | />
73 |
74 | setStore({ ...store, formData: { ...formData, password: text } })}
81 | />
82 |
83 |
93 |
94 |
95 |
96 |
97 |
98 | );
99 | }
100 |
101 | export default SigninScreen
102 |
103 | const styles = StyleSheet.create({
104 | block: {
105 | flex: 1,
106 | backgroundColor: '#2F2F2F',
107 | },
108 | setting: {
109 | marginRight: 16,
110 | },
111 | header: {
112 | paddingTop: 43,
113 | paddingBottom: 20,
114 | },
115 | titie: {
116 | color: '#fff',
117 | marginTop: 26,
118 | marginBottom: 0,
119 | },
120 | description: {
121 | color: '#fff',
122 | fontSize: 12,
123 | marginBottom: 0,
124 | fontWeight: '200',
125 | },
126 | input: {
127 | width: 243,
128 | backgroundColor: '#636363',
129 | paddingHorizontal: 10,
130 | paddingVertical: 10,
131 | borderRadius: 6,
132 | color: '#fff',
133 | fontWeight: '200',
134 | fontSize: 16,
135 | },
136 | button: {
137 | // marginTop: 10,
138 | paddingHorizontal: 35,
139 | paddingVertical: 4,
140 | },
141 | hostNotice: {
142 | right: -60,
143 | top: -30,
144 | width: 40,
145 | height: 20,
146 | borderRadius: 3,
147 | overflow: 'hidden',
148 | color: '#fff',
149 | fontSize: 14,
150 | textAlign: 'center',
151 | backgroundColor: '#FFCB00',
152 | },
153 | });
154 |
--------------------------------------------------------------------------------
/HelloWorld/src/pages/TransportHome/index.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { SafeAreaView } from 'react-native';
3 |
4 | export default function MyScreen() {
5 | return (
6 |
7 | );
8 | }
9 |
--------------------------------------------------------------------------------
/HelloWorld/src/routes/index.js:
--------------------------------------------------------------------------------
1 | import SignIn from '../pages/SignIn';
2 | import DevOptions from '../pages/DevOptions';
3 | import MyHomeSetting from '../pages/MyHome/Setting';
4 | import TabsScreen from './tabs';
5 |
6 | export const stackPageData = [
7 | {
8 | name: 'Tab',
9 | component: TabsScreen,
10 | options: {
11 | headerShown: false,
12 | title: '首页',
13 | },
14 | },
15 | {
16 | name: 'SignIn',
17 | component: SignIn,
18 | options: {
19 | headerShown: false,
20 | header: () => null,
21 | },
22 | },
23 | {
24 | name: 'DevOptions',
25 | component: DevOptions,
26 | options: {
27 | headerShown: false,
28 | header: () => null,
29 | },
30 | },
31 | {
32 | name: 'MyHomeSetting',
33 | component: MyHomeSetting,
34 | options: {
35 | title: '设置',
36 | },
37 | },
38 | ];
39 |
--------------------------------------------------------------------------------
/HelloWorld/src/routes/tabs.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {StatusBar} from 'react-native';
3 | import {useTheme, Text, Icon} from '@uiw/react-native';
4 | import {createBottomTabNavigator} from '@react-navigation/bottom-tabs';
5 | import MyHome from '../pages/MyHome';
6 | import OrderHome from '../pages/OrderHome';
7 | import TransportHome from '../pages/TransportHome';
8 |
9 | const BottomTabs = createBottomTabNavigator();
10 | const tabs = [
11 | {
12 | name: 'TransportHome',
13 | component: TransportHome,
14 | label: '发货',
15 | icon: 'inbox',
16 | },
17 | {
18 | name: 'OrderHome',
19 | component: OrderHome,
20 | label: '订单',
21 | icon: 'file-text',
22 | },
23 | {
24 | name: 'MyHome',
25 | component: MyHome,
26 | label: '我的',
27 | icon: 'user',
28 | },
29 | ];
30 | const TabsScreen = props => {
31 | const theme = useTheme();
32 | return (
33 |
34 |
35 |
40 | {tabs.map((item, idx) => {
41 | return (
42 | (
52 |
57 | {item?.label}
58 |
59 | ),
60 | // eslint-disable-next-line react/no-unstable-nested-components
61 | tabBarIcon: ({focused}) => ,
62 | }}
63 | />
64 | );
65 | })}
66 |
67 |
68 | );
69 | };
70 |
71 | export default TabsScreen;
72 |
--------------------------------------------------------------------------------
/HelloWorld/src/services/users.js:
--------------------------------------------------------------------------------
1 | import {fetch} from '../utils';
2 |
3 | /**
4 | * Auth token
5 | */
6 | export async function userAuth(params) {
7 | return fetch('/api/auth', {
8 | method: 'GET',
9 | body: params,
10 | });
11 | }
12 |
13 | /**
14 | * login
15 | */
16 | export async function userLogin(params) {
17 | return fetch('/api/login', {
18 | body: params,
19 | });
20 | }
21 |
22 | /**
23 | * logout
24 | */
25 | export async function userLogout(params) {
26 | return fetch('/api/logout', {
27 | body: params,
28 | });
29 | }
30 |
--------------------------------------------------------------------------------
/HelloWorld/src/utils/fetch.js:
--------------------------------------------------------------------------------
1 | import AsyncStorage from '@react-native-async-storage/async-storage';
2 | import {Alert} from 'react-native';
3 | import Global from '../global';
4 |
5 | export default async function request(url, options) {
6 | let {method = 'POST', body = '', serverId = 'projectId', formdataBody, headers, ...params} = options || {};
7 | if (typeof body !== 'string') {
8 | body = JSON.stringify(body);
9 | }
10 | const header = {
11 | Accept: 'application/json',
12 | 'content-type': 'application/json',
13 | ...headers,
14 | };
15 | const token = await AsyncStorage.getItem('token');
16 |
17 | let host = await AsyncStorage.getItem('apihost');
18 | if (host) {
19 | host = JSON.parse(host);
20 | host = host.url;
21 | }
22 | if (token) {
23 | header.Authorization = token;
24 | }
25 | if (formdataBody) {
26 | // header['content-type'] = 'application/x-www-form-urlencoded';
27 | header['content-type'] = 'multipart/form-data';
28 | params.processData = false;
29 | params.contentType = false;
30 | let formdata = new FormData();
31 | Object.keys(formdataBody).forEach(keyName => {
32 | formdata.append(keyName, String(formdataBody[keyName]));
33 | });
34 | body = formdata;
35 | }
36 | const fetchURL = `${host}/${url.replace(/^\//, '')}`;
37 | // console.log('=> body:', method, fetchURL, body);
38 | // console.log('=> header:', header);
39 | // console.log('=> header:', header['x-auth']);
40 | return fetch(fetchURL, {
41 | method,
42 | body: body,
43 | headers: {...header},
44 | ...params,
45 | })
46 | .then(async response => {
47 | const data = await response.json();
48 | if (/(200|201)/.test(response.status)) {
49 | return data;
50 | }
51 | if (/(401)/.test(response.status)) {
52 | Global.navigation.navigate('SignIn');
53 | return;
54 | }
55 | Alert.alert(`Request Error ${response.status}`, `E2111: ${data.message} - ${fetchURL} - ${JSON.stringify(data)}`);
56 | })
57 | .catch(error => {
58 | Alert.alert('Service abnormal please check server', `E2112:${fetchURL} \n\n ${error.toString()} ${JSON.stringify(body)}`);
59 | });
60 | }
61 |
--------------------------------------------------------------------------------
/HelloWorld/src/utils/index.js:
--------------------------------------------------------------------------------
1 | import fetch from './fetch';
2 |
3 | export {fetch};
4 |
5 | /**
6 | * Sleep second
7 | * @param {Number} ms second
8 | * @example
9 | * ```js
10 | * async function sleepyWork() {
11 | * console.log("I'm going to sleep for 1 second.");
12 | * await sleep(1000);
13 | * console.log('I woke up after 1 second.');
14 | * }
15 | * ```
16 | */
17 | export const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
18 |
--------------------------------------------------------------------------------
/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | ## Expected results
2 |
3 | What did you expect to happen?
4 |
5 | ## Observed results
6 |
7 | What happened?
8 |
9 | ### Logs
10 |
11 | Please add the log output here.
12 |
13 | ## Steps to reproduce
14 |
15 | 1.
16 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 uiw
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | template/README.md
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "license": "MIT",
3 | "private": true,
4 | "scripts": {
5 | "start": "node scripts/copied.mjs"
6 | },
7 | "devDependencies": {
8 | "fs-extra": "10.0.0"
9 | },
10 | "workspaces": {
11 | "packages": [
12 | "HelloWorld"
13 | ],
14 | "nohoist": [
15 | "**/@rematch",
16 | "**/@rematch/**",
17 | "**/react",
18 | "**/react*",
19 | "**/react/**",
20 | "**/react*/**",
21 | "**/@react-navigation",
22 | "**/@react-navigation/**",
23 | "**/@react-native-community",
24 | "**/@react-native-community/**",
25 | "**/@react-native-async-storage",
26 | "**/@react-native-async-storage/**",
27 | "**/@babel",
28 | "**/@babel/**",
29 | "**/@kkt/doc",
30 | "**/@kkt/doc/**",
31 | "**/@uiw/react-native-doc",
32 | "**/@uiw/react-native-doc/**"
33 | ]
34 | }
35 | }
--------------------------------------------------------------------------------
/renovate.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": [
3 | "config:base"
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/scripts/copied.mjs:
--------------------------------------------------------------------------------
1 | import fs from 'fs';
2 | import FS from 'fs-extra';
3 | import path from 'path';
4 |
5 | async function getPaths(from, regx, paths = []) {
6 | try {
7 | const pathStr = (await fs.promises.readdir(from)).map(item => path.join(from, item))
8 | .map(item => regx.test(item) ? false : item)
9 | .filter(Boolean);
10 |
11 | await Promise.all(pathStr.map(async (item) => {
12 | const stat = await fs.promises.stat(item);
13 | if (stat.isDirectory()) {
14 | paths.push({
15 | path: item,
16 | isDir: true,
17 | });
18 | return getPaths(item, regx, paths)
19 | }
20 | paths.push({
21 | path: item,
22 | isFile: true,
23 | })
24 | }));
25 | } catch (error) {
26 | console.error(error);
27 | }
28 | return paths;
29 | }
30 |
31 | async function copyDir(from, to, options = {}) {
32 | try {
33 | await FS.emptyDir(to);
34 | const pathArr = await getPaths(from, new RegExp('(/node_modules|/ios/Pods|Podfile\.lock)'));
35 | await Promise.all(pathArr.map(async (item) => {
36 | const toPath = item.path.replace(new RegExp(`^${from}`), to);
37 | if (item.isDir) {
38 | await FS.ensureDir(toPath);
39 | } else if (item.isFile) {
40 | let relativePath = toPath.replace(new RegExp(`^${to}${path.sep}`), '');
41 | if (/^\./.test(relativePath)) {
42 | relativePath = relativePath.replace(/^\./, '_');
43 | }
44 | await FS.copy(item.path, path.join(to, relativePath));
45 | console.log(` ✅ ${relativePath}`);
46 | } else {
47 | console.log(' ⁉️ ‼️ :toPath',item, item.path)
48 | }
49 | }));
50 | } catch (error) {
51 | console.error(error)
52 | }
53 | }
54 |
55 | copyDir(path.resolve(process.cwd(), 'HelloWorld'), path.resolve(process.cwd(), 'template/template'));
--------------------------------------------------------------------------------
/template/.gitignore:
--------------------------------------------------------------------------------
1 | # OSX
2 | #
3 | .DS_Store
4 |
5 | # Xcode
6 | #
7 | build/
8 | *.pbxuser
9 | !default.pbxuser
10 | *.mode1v3
11 | !default.mode1v3
12 | *.mode2v3
13 | !default.mode2v3
14 | *.perspectivev3
15 | !default.perspectivev3
16 | xcuserdata
17 | *.xccheckout
18 | *.moved-aside
19 | DerivedData
20 | *.hmap
21 | *.ipa
22 | *.xcuserstate
23 |
24 | # Android/IntelliJ
25 | #
26 | build/
27 | .idea
28 | .gradle
29 | local.properties
30 | *.iml
31 |
32 | # node.js
33 | #
34 | node_modules/
35 | npm-debug.log
36 | yarn-error.log
37 |
38 | # BUCK
39 | buck-out/
40 | \.buckd/
41 | *.keystore
42 | !debug.keystore
43 |
44 | # fastlane
45 | #
46 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
47 | # screenshots whenever they are needed.
48 | # For more information about the recommended setup visit:
49 | # https://docs.fastlane.tools/best-practices/source-control/
50 |
51 | */fastlane/report.xml
52 | */fastlane/Preview.html
53 | */fastlane/screenshots
54 |
55 | # Bundle artifact
56 | *.jsbundle
57 |
58 | # CocoaPods
59 | */ios/Pods/
60 |
--------------------------------------------------------------------------------
/template/README.md:
--------------------------------------------------------------------------------
1 | # React Native UIW Template
2 |
3 | [](https://www.npmjs.com/package/@uiw/react-native-template)
4 | [](https://github.com/uiwjs/react-native-template/issues)
5 | [](https://github.com/uiwjs/react-native-template/network)
6 | [](https://github.com/uiwjs/react-native-template/stargazers)
7 | [](https://uimjs.github.io/#/docs/react-native-template/releases)
8 |
9 | [React Native](https://github.com/facebook/react-native) Template for [@uiw/react-native](https://github.com/uiwjs/react-native-uiw).
10 |
11 |
12 | > Migrate from @uiw/react-native-template 0.1.2 to [v1.1.0](https://github.com/uiwjs/react-native-template/releases/tag/v1.1.0)
13 |
14 | ## Features
15 |
16 | This template includes the following:
17 |
18 | - Elegant usage directly within the [React Native CLI](https://github.com/react-native-community/cli)
19 | - [React Native](https://github.com/facebook/react-native) 0.60 support (now with Hooks! 🙌).
20 | - Easy to use and understand folder structure to get you up and running as fast as possible.
21 | - [@uiw/react-native](https://github.com/uiwjs/react-native-uiw) component framework and themes.
22 | - Using [react-navigation](https://github.com/react-navigation/react-navigation) to routing and navigate your React Native applications.
23 | - [Redux](https://github.com/reduxjs/redux) support (with [@rematch](https://github.com/rematch/rematch) example)
24 | - [ESLint](https://github.com/eslint/eslint), and [Prettier](https://github.com/prettier/prettier) configured out-of-the-box
25 | - Using [mocker-api](https://github.com/jaywcjlove/mocker-api) that creates mocks for REST APIs.
26 |
27 | ## Installation and Usage
28 |
29 | 🚧 This template only works with the new CLI. This template is intended for React Native versions `>= 0.61`. It has not been tested with previous versions.
30 |
31 | **Note on the legacy CLI**
32 |
33 | 🚧 There seems to be quite some confusion about the legacy CLI. This template only works with the new CLI. Make sure you have uninstalled the legacy `react-native-cli` first (`npm uninstall -g react-native-cli`), for the below command to work.
34 |
35 | ```bash
36 | npm uninstall -g react-native-cli
37 | ```
38 |
39 | Further information can be found here: https://github.com/react-native-community/cli#about
40 |
41 |
42 | **🚧🚧 If you wish to not use `react-native@0.70.0` or higher**
43 | [help](https://github.com/facebook/react-native/issues/34608#)
44 | ```
45 | Check whether your ruby version is higher than 2.7.5
46 | ```
47 |
48 | ```
49 | bundle install
50 | cd ios && bundle exec pod install
51 | ```
52 |
53 | **🚧🚧 MacBook Pro with a M1 🚧🚧**
54 |
55 | ```bash
56 | # Install ffi
57 | sudo arch -x86_64 gem install ffi
58 |
59 | rm -rf Pods Podfile.lock
60 |
61 | # Clear pods.
62 | pod deintegrate
63 | # pod rm Podfile.lock
64 | arch -x86_64 pod install
65 | # Re-install pods
66 | arch -x86_64 pod install --repo-update --verbose
67 |
68 | yarn run ios # Run instructions for iOS
69 | yarn run api
70 | ```
71 |
72 | **`react-native@0.61.0` or higher**
73 |
74 | ```sh
75 | npx react-native init MyApp --template @uiw/react-native-template
76 | # npx react-native init MyApp --template @uiw/react-native-template@v1.0.0
77 | ```
78 |
79 | **If you wish to not use `npx`**
80 |
81 | you can also install the new CLI globally (`npm i -g @react-native-community/cli` or `yarn global add @react-native-community/cli`).
82 |
83 | ```bash
84 | npx react-native init MyApp --template @uiw/react-native-template
85 |
86 | cd MyApp/ios
87 | # Installing CocoaPods dependencies
88 | pod install
89 | ```
90 |
91 | ```bash
92 | # This will initialize new project using template from TEMPLATE_NAME package
93 | npx react-native init ProjectName --template ${TEMPLATE_NAME}
94 |
95 | # This will initialize new project using init command from react-native@VERSION
96 | # but will use TEMPLATE_NAME custom template
97 | npx react-native@${VERSION} init ProjectName --template ${TEMPLATE_NAME}
98 | ```
99 | ## @uiw/react-native-uiw文档本地预览
100 | ```bash
101 | yarn run doc
102 | ```
103 |
104 | ## Use husky
105 |
106 | Edit package.json > prepare script and run it once:
107 | ```bash
108 | npm pkg set scripts.prepare="husky install"
109 | npm run prepare
110 | ```
111 | Add a hook:
112 | ```bash
113 | npx husky add .husky/pre-commit "npm run precommit"
114 | git add .husky/pre-commit
115 | ```
116 |
117 | Make a commit:
118 | ```bash
119 | git commit -m "Keep calm and commit"
120 | # `npm precommit` will run
121 | ```
122 |
123 | ## Dependencies
124 |
125 | ```bash
126 | @react-navigation/native
127 | ├──react-native-gesture-handler
128 | ├──react-native-reanimated
129 | ├──react-native-screens
130 | ├──react-native-safe-area-context
131 | └──@react-native-community/masked-view
132 | ```
133 |
134 | ## 目录结构
135 | ```
136 | ├── Gemfile
137 | ├── README.md
138 | ├── __tests__
139 | │ └── App-test.js
140 | ├── _bundle
141 | │ └── config
142 | ├── _node-version
143 | ├── android
144 | │ ├── app
145 | │ ├── build.gradle
146 | │ ├── gradle
147 | │ ├── gradle.properties
148 | │ ├── gradlew
149 | │ ├── gradlew.bat
150 | │ └── settings.gradle
151 | ├── app.json
152 | ├── babel.config.js
153 | ├── index.js
154 | ├── ios
155 | │ ├── HelloWorld
156 | │ ├── HelloWorld.xcodeproj
157 | │ ├── HelloWorld.xcworkspace
158 | │ ├── HelloWorldTests
159 | │ ├── Podfile
160 | │ ├── Podfile.lock
161 | │ ├── Pods
162 | │ ├── _xcode.env
163 | │ └── build
164 | ├── jsconfig.json
165 | ├── metro.config.js
166 | ├── mocker
167 | │ ├── index.js
168 | │ └── user.mock.js
169 | ├── package.json
170 | └── src
171 | ├── App.js
172 | ├── components
173 | ├── config.js
174 | ├── global.js
175 | ├── hooks
176 | ├── models
177 | ├── pages
178 | ├── routes
179 | ├── services
180 | └── utils
181 | ```
182 |
183 | ## Links
184 |
185 | - [React Native upgrade helper](https://react-native-community.github.io/upgrade-helper/)
186 |
187 | ## Contributors
188 |
189 | As always, thanks to our amazing contributors!
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 | Made with [contributors](https://github.com/jaywcjlove/github-action-contributors).
223 |
224 |
225 | ## License
226 |
227 | This project is [MIT](LICENSE) licensed.
228 |
--------------------------------------------------------------------------------
/template/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@uiw/react-native-template",
3 | "version": "5.4.0",
4 | "description": "React Native template for react-native-uiw.",
5 | "homepage": "https://uimjs.github.io/#/docs/react-native-template",
6 | "scripts": {
7 | "prepublishOnly": "npm --no-git-tag-version version $TRAVIS_TAG"
8 | },
9 | "files": [
10 | "template",
11 | "template.config.js"
12 | ],
13 | "repository": {
14 | "type": "git",
15 | "url": "https://github.com/uiwjs/react-native-template.git"
16 | },
17 | "keywords": [
18 | "react-native-template",
19 | "react-native",
20 | "jest",
21 | "template",
22 | "uiw",
23 | "redux",
24 | "react",
25 | "react-navigation",
26 | "navigation",
27 | "boilerplate",
28 | "rematch"
29 | ],
30 | "author": "Kenny Wong ",
31 | "license": "MIT"
32 | }
33 |
--------------------------------------------------------------------------------
/template/template.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | placeholderName: 'HelloWorld',
3 | templateDir: './template',
4 | }
5 |
--------------------------------------------------------------------------------
/template/template/Gemfile:
--------------------------------------------------------------------------------
1 | source 'https://rubygems.org'
2 |
3 | # You may use http://rbenv.org/ or https://rvm.io/ to install and use this version
4 | ruby '>= 2.6.10'
5 |
6 | gem 'cocoapods', '>= 1.11.3'
7 |
--------------------------------------------------------------------------------
/template/template/README.md:
--------------------------------------------------------------------------------
1 | HelloWorld
2 | ---
3 |
4 | React Native UIW Template
5 |
6 | ## Development
7 |
8 | ```bash
9 | cd ios/ && pod install && cd ../
10 |
11 | # Mocker API
12 | npm run api
13 |
14 | # Run the app with iOS.
15 | npm run ios
16 | ```
17 |
18 | **⚠️⚠️ MacBook Pro with a M1 ⚠️⚠️**
19 |
20 | ```bash
21 | # Install ffi
22 | sudo arch -x86_64 gem install ffi
23 |
24 | # Clear pods.
25 | pod deintegrate
26 | # pod rm Podfile.lock
27 | arch -x86_64 pod install
28 | # Re-install pods
29 | arch -x86_64 pod install --repo-update --verbose
30 | ```
31 |
32 | ## Main Directory Structure
33 |
34 | ```
35 | .
36 | ├── mocker # mocker data
37 | ├── android # native android code
38 | ├── ios # native ios code
39 | ├── src # code directory
40 | │ ├── components # react components
41 | │ ├── models # The models brings together state, reducers, async actions & action creators in one place
42 | │ ├── pages # route pages
43 | │ ├── routes # route configuration
44 | │ ├── services # api request
45 | │ ├── utils # public method
46 | │ ├── App.js # route entery page
47 | │ ├── config.js # app configuration
48 | │ └── global.js # Store some global objects for easy calling
49 | ├── .eslintrc # eslint configuration
50 | ├── index.js # app entry file
51 | └── package.json # This document is all you need to know about what’s required in your package.json file.
52 | ```
--------------------------------------------------------------------------------
/template/template/__tests__/App-test.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @format
3 | */
4 |
5 | import 'react-native';
6 | import React from 'react';
7 | import App from '../App';
8 |
9 | // Note: test renderer must be required after react-native.
10 | import renderer from 'react-test-renderer';
11 |
12 | it('renders correctly', () => {
13 | renderer.create();
14 | });
15 |
--------------------------------------------------------------------------------
/template/template/_babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "plugins": [
3 | ["module-resolver", {
4 | "root": ["./"],
5 | "alias": {
6 | "@": "./src",
7 | "@components": "./src/components",
8 | "@utils": "./src/utils"
9 | }
10 | }]
11 | ]
12 | }
--------------------------------------------------------------------------------
/template/template/_bundle/config:
--------------------------------------------------------------------------------
1 | BUNDLE_PATH: "vendor/bundle"
2 | BUNDLE_FORCE_RUBY_PLATFORM: 1
3 |
--------------------------------------------------------------------------------
/template/template/_editorconfig:
--------------------------------------------------------------------------------
1 | # Windows files
2 | [*.bat]
3 | end_of_line = crlf
4 |
--------------------------------------------------------------------------------
/template/template/_eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | extends: '@react-native-community',
4 | rules: {
5 | 'react/react-in-jsx-scope': 'off',
6 | 'react-hooks/exhaustive-deps': 'off',
7 | 'no-shadow': 'off',
8 | 'react-native/no-inline-styles': 0,
9 | 'prettier/prettier': [
10 | 'error',
11 | {
12 | 'no-inline-styles': false,
13 | },
14 | ],
15 | },
16 | };
17 |
--------------------------------------------------------------------------------
/template/template/_gitignore:
--------------------------------------------------------------------------------
1 | # OSX
2 | #
3 | .DS_Store
4 |
5 | # Xcode
6 | #
7 | build/
8 | *.pbxuser
9 | !default.pbxuser
10 | *.mode1v3
11 | !default.mode1v3
12 | *.mode2v3
13 | !default.mode2v3
14 | *.perspectivev3
15 | !default.perspectivev3
16 | xcuserdata
17 | *.xccheckout
18 | *.moved-aside
19 | DerivedData
20 | *.hmap
21 | *.ipa
22 | *.xcuserstate
23 | ios/.xcode.env.local
24 |
25 | # Android/IntelliJ
26 | #
27 | build/
28 | .idea
29 | .gradle
30 | local.properties
31 | *.iml
32 | *.hprof
33 | .cxx/
34 | *.keystore
35 | !debug.keystore
36 | # node.js
37 | #
38 | node_modules/
39 | npm-debug.log
40 | yarn-error.log
41 |
42 |
43 | # fastlane
44 | #
45 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
46 | # screenshots whenever they are needed.
47 | # For more information about the recommended setup visit:
48 | # https://docs.fastlane.tools/best-practices/source-control/
49 |
50 | **/fastlane/report.xml
51 | **/fastlane/Preview.html
52 | **/fastlane/screenshots
53 | **/fastlane/test_output
54 |
55 | # Bundle artifact
56 | *.jsbundle
57 |
58 | # Ruby / CocoaPods
59 | /ios/Pods/
60 | /vendor/bundle/
61 |
62 |
63 | # Temporary files created by Metro to check the health of the file watcher
64 | .metro-health-check*
65 |
--------------------------------------------------------------------------------
/template/template/_node-version:
--------------------------------------------------------------------------------
1 | 18
--------------------------------------------------------------------------------
/template/template/_prettierrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | arrowParens: 'avoid',
3 | bracketSameLine: true,
4 | bracketSpacing: false,
5 | singleQuote: true,
6 | trailingComma: 'all',
7 | tabWidth: 2,
8 | printWidth: 160,
9 | };
10 |
--------------------------------------------------------------------------------
/template/template/_watchmanconfig:
--------------------------------------------------------------------------------
1 | {}
--------------------------------------------------------------------------------
/template/template/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: "com.android.application"
2 | apply plugin: "com.facebook.react"
3 |
4 | import com.android.build.OutputFile
5 | /**
6 | * This is the configuration block to customize your React Native Android app.
7 | * By default you don't need to apply any configuration, just uncomment the lines you need.
8 | */
9 | react {
10 | /* Folders */
11 | // The root of your project, i.e. where "package.json" lives. Default is '..'
12 | // root = file("../")
13 | // The folder where the react-native NPM package is. Default is ../node_modules/react-native
14 | // reactNativeDir = file("../node_modules/react-native")
15 | // The folder where the react-native Codegen package is. Default is ../node_modules/react-native-codegen
16 | // codegenDir = file("../node_modules/react-native-codegen")
17 | // The cli.js file which is the React Native CLI entrypoint. Default is ../node_modules/react-native/cli.js
18 | // cliFile = file("../node_modules/react-native/cli.js")
19 | /* Variants */
20 | // The list of variants to that are debuggable. For those we're going to
21 | // skip the bundling of the JS bundle and the assets. By default is just 'debug'.
22 | // If you add flavors like lite, prod, etc. you'll have to list your debuggableVariants.
23 | // debuggableVariants = ["liteDebug", "prodDebug"]
24 | /* Bundling */
25 | // A list containing the node command and its flags. Default is just 'node'.
26 | // nodeExecutableAndArgs = ["node"]
27 | //
28 | // The command to run when bundling. By default is 'bundle'
29 | // bundleCommand = "ram-bundle"
30 | //
31 | // The path to the CLI configuration file. Default is empty.
32 | // bundleConfig = file(../rn-cli.config.js)
33 | //
34 | // The name of the generated asset file containing your JS bundle
35 | // bundleAssetName = "MyApplication.android.bundle"
36 | //
37 | // The entry file for bundle generation. Default is 'index.android.js' or 'index.js'
38 | // entryFile = file("../js/MyApplication.android.js")
39 | //
40 | // A list of extra flags to pass to the 'bundle' commands.
41 | // See https://github.com/react-native-community/cli/blob/main/docs/commands.md#bundle
42 | // extraPackagerArgs = []
43 | /* Hermes Commands */
44 | // The hermes compiler command to run. By default it is 'hermesc'
45 | // hermesCommand = "$rootDir/my-custom-hermesc/bin/hermesc"
46 | //
47 | // The list of flags to pass to the Hermes compiler. By default is "-O", "-output-source-map"
48 | // hermesFlags = ["-O", "-output-source-map"]
49 | }
50 | /**
51 | * Set this to true to create four separate APKs instead of one,
52 | * one for each native architecture. This is useful if you don't
53 | * use App Bundles (https://developer.android.com/guide/app-bundle/)
54 | * and want to have separate APKs to upload to the Play Store.
55 | */
56 | def enableSeparateBuildPerCPUArchitecture = false
57 | /**
58 | * Set this to true to Run Proguard on Release builds to minify the Java bytecode.
59 | */
60 | def enableProguardInReleaseBuilds = false
61 | /**
62 | * The preferred build flavor of JavaScriptCore (JSC)
63 | *
64 | * For example, to use the international variant, you can use:
65 | * `def jscFlavor = 'org.webkit:android-jsc-intl:+'`
66 | *
67 | * The international variant includes ICU i18n library and necessary data
68 | * allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that
69 | * give correct results when using with locales other than en-US. Note that
70 | * this variant is about 6MiB larger per architecture than default.
71 | */
72 | def jscFlavor = 'org.webkit:android-jsc:+'
73 | /**
74 | * Private function to get the list of Native Architectures you want to build.
75 | * This reads the value from reactNativeArchitectures in your gradle.properties
76 | * file and works together with the --active-arch-only flag of react-native run-android.
77 | */
78 | def reactNativeArchitectures() {
79 | def value = project.getProperties().get("reactNativeArchitectures")
80 | return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"]
81 | }
82 |
83 | android {
84 | ndkVersion rootProject.ext.ndkVersion
85 |
86 | compileSdkVersion rootProject.ext.compileSdkVersion
87 |
88 | namespace "com.helloworld"
89 |
90 | defaultConfig {
91 | applicationId "com.helloworld"
92 | minSdkVersion rootProject.ext.minSdkVersion
93 | targetSdkVersion rootProject.ext.targetSdkVersion
94 | versionCode 1
95 | versionName "1.0"
96 | }
97 |
98 | splits {
99 | abi {
100 | reset()
101 | enable enableSeparateBuildPerCPUArchitecture
102 | universalApk false // If true, also generate a universal APK
103 | include (*reactNativeArchitectures())
104 | }
105 | }
106 | signingConfigs {
107 | debug {
108 | storeFile file('debug.keystore')
109 | storePassword 'android'
110 | keyAlias 'androiddebugkey'
111 | keyPassword 'android'
112 | }
113 | }
114 | buildTypes {
115 | debug {
116 | signingConfig signingConfigs.debug
117 | }
118 | release {
119 | // Caution! In production, you need to generate your own keystore file.
120 | // see https://reactnative.dev/docs/signed-apk-android.
121 | signingConfig signingConfigs.debug
122 | minifyEnabled enableProguardInReleaseBuilds
123 | proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
124 | }
125 | }
126 |
127 | // applicationVariants are e.g. debug, release
128 | applicationVariants.all { variant ->
129 | variant.outputs.each { output ->
130 | // For each separate APK per architecture, set a unique version code as described here:
131 | // https://developer.android.com/studio/build/configure-apk-splits.html
132 | // Example: versionCode 1 will generate 1001 for armeabi-v7a, 1002 for x86, etc.
133 | def versionCodes = ["armeabi-v7a": 1, "x86": 2, "arm64-v8a": 3, "x86_64": 4]
134 | def abi = output.getFilter(OutputFile.ABI)
135 | if (abi != null) { // null for the universal-debug, universal-release variants
136 | output.versionCodeOverride =
137 | defaultConfig.versionCode * 1000 + versionCodes.get(abi)
138 | }
139 |
140 | }
141 | }
142 | }
143 |
144 | dependencies {
145 | // The version of react-native is set by the React Native Gradle Plugin
146 | implementation("com.facebook.react:react-android")
147 | implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.0.0")
148 | debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}")
149 |
150 | debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") {
151 | exclude group:'com.squareup.okhttp3', module:'okhttp'
152 | }
153 |
154 | debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}")
155 |
156 | debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}")
157 | if (hermesEnabled.toBoolean()) {
158 | implementation("com.facebook.react:hermes-android")
159 | } else {
160 | implementation jscFlavor
161 | }
162 | }
163 |
164 | apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project)
165 |
166 |
--------------------------------------------------------------------------------
/template/template/android/app/debug.keystore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uiwjs/react-native-template/cf63e26fd864fb54b13d52c8760a140ef81ca7ab/template/template/android/app/debug.keystore
--------------------------------------------------------------------------------
/template/template/android/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
--------------------------------------------------------------------------------
/template/template/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/template/template/android/app/src/debug/java/com/helloworld/ReactNativeFlipper.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) Meta Platforms, Inc. and affiliates.
3 | *
4 | * This source code is licensed under the MIT license found in the LICENSE file in the root
5 | * directory of this source tree.
6 | */
7 | package com.helloworld;
8 |
9 | import android.content.Context;
10 | import com.facebook.flipper.android.AndroidFlipperClient;
11 | import com.facebook.flipper.android.utils.FlipperUtils;
12 | import com.facebook.flipper.core.FlipperClient;
13 | import com.facebook.flipper.plugins.crashreporter.CrashReporterPlugin;
14 | import com.facebook.flipper.plugins.databases.DatabasesFlipperPlugin;
15 | import com.facebook.flipper.plugins.fresco.FrescoFlipperPlugin;
16 | import com.facebook.flipper.plugins.inspector.DescriptorMapping;
17 | import com.facebook.flipper.plugins.inspector.InspectorFlipperPlugin;
18 | import com.facebook.flipper.plugins.network.FlipperOkhttpInterceptor;
19 | import com.facebook.flipper.plugins.network.NetworkFlipperPlugin;
20 |
21 | import com.facebook.flipper.plugins.sharedpreferences.SharedPreferencesFlipperPlugin;
22 | import com.facebook.react.ReactInstanceEventListener;
23 | import com.facebook.react.ReactInstanceManager;
24 | import com.facebook.react.bridge.ReactContext;
25 | import com.facebook.react.modules.network.NetworkingModule;
26 | import okhttp3.OkHttpClient;
27 |
28 | /**
29 | * Class responsible of loading Flipper inside your React Native application. This is the debug
30 | * flavor of it. Here you can add your own plugins and customize the Flipper setup.
31 | */
32 |
33 | public class ReactNativeFlipper {
34 | public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) {
35 | if (FlipperUtils.shouldEnableFlipper(context)) {
36 | final FlipperClient client = AndroidFlipperClient.getInstance(context);
37 |
38 | client.addPlugin(new InspectorFlipperPlugin(context, DescriptorMapping.withDefaults()));
39 |
40 | client.addPlugin(new DatabasesFlipperPlugin(context));
41 | client.addPlugin(new SharedPreferencesFlipperPlugin(context));
42 | client.addPlugin(CrashReporterPlugin.getInstance());
43 |
44 | NetworkFlipperPlugin networkFlipperPlugin = new NetworkFlipperPlugin();
45 | NetworkingModule.setCustomClientBuilder(
46 | new NetworkingModule.CustomClientBuilder() {
47 | @Override
48 | public void apply(OkHttpClient.Builder builder) {
49 | builder.addNetworkInterceptor(new FlipperOkhttpInterceptor(networkFlipperPlugin));
50 | }
51 | });
52 | client.addPlugin(networkFlipperPlugin);
53 | client.start();
54 |
55 | // Fresco Plugin needs to ensure that ImagePipelineFactory is initialized
56 | // Hence we run if after all native modules have been initialized
57 | ReactContext reactContext = reactInstanceManager.getCurrentReactContext();
58 | if (reactContext == null) {
59 | reactInstanceManager.addReactInstanceEventListener(
60 | new ReactInstanceEventListener() {
61 | @Override
62 | public void onReactContextInitialized(ReactContext reactContext) {
63 | reactInstanceManager.removeReactInstanceEventListener(this);
64 | reactContext.runOnNativeModulesQueueThread(
65 | new Runnable() {
66 | @Override
67 | public void run() {
68 | client.addPlugin(new FrescoFlipperPlugin());
69 | }
70 | });
71 | }
72 | });
73 | } else {
74 | client.addPlugin(new FrescoFlipperPlugin());
75 | }
76 | }
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/template/template/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
12 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/template/template/android/app/src/main/java/com/helloworld/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.helloworld;
2 |
3 | import com.facebook.react.ReactActivity;
4 | import com.facebook.react.ReactActivityDelegate;
5 | import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint;
6 | import com.facebook.react.defaults.DefaultReactActivityDelegate;
7 |
8 | public class MainActivity extends ReactActivity {
9 |
10 | /**
11 | * Returns the name of the main component registered from JavaScript. This is used to schedule
12 | * rendering of the component.
13 | */
14 | @Override
15 | protected String getMainComponentName() {
16 | return "HelloWorld";
17 | }
18 |
19 | /**
20 | * Returns the instance of the {@link ReactActivityDelegate}. Here we use a util class {@link
21 | * DefaultReactActivityDelegate} which allows you to easily enable Fabric and Concurrent React
22 | * (aka React 18) with two boolean flags.
23 | */
24 | @Override
25 | protected ReactActivityDelegate createReactActivityDelegate() {
26 | return new DefaultReactActivityDelegate(
27 | this,
28 | getMainComponentName(),
29 | // If you opted-in for the New Architecture, we enable the Fabric Renderer.
30 | DefaultNewArchitectureEntryPoint.getFabricEnabled(), // fabricEnabled
31 | // If you opted-in for the New Architecture, we enable Concurrent React (i.e. React 18).
32 | DefaultNewArchitectureEntryPoint.getConcurrentReactEnabled() // concurrentRootEnabled
33 | );
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/template/template/android/app/src/main/java/com/helloworld/MainApplication.java:
--------------------------------------------------------------------------------
1 | package com.helloworld;
2 |
3 | import android.app.Application;
4 |
5 | import com.facebook.react.PackageList;
6 | import com.facebook.react.ReactApplication;
7 |
8 | import com.facebook.react.ReactNativeHost;
9 | import com.facebook.react.ReactPackage;
10 | import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint;
11 | import com.facebook.react.defaults.DefaultReactNativeHost;
12 | import com.facebook.soloader.SoLoader;
13 | import java.util.List;
14 |
15 | public class MainApplication extends Application implements ReactApplication {
16 |
17 | private final ReactNativeHost mReactNativeHost =
18 | new DefaultReactNativeHost(this) {
19 | @Override
20 | public boolean getUseDeveloperSupport() {
21 | return BuildConfig.DEBUG;
22 | }
23 |
24 | @Override
25 | protected List getPackages() {
26 | @SuppressWarnings("UnnecessaryLocalVariable")
27 | List packages = new PackageList(this).getPackages();
28 | // Packages that cannot be autolinked yet can be added manually here, for example:
29 | // packages.add(new MyReactNativePackage());
30 | return packages;
31 | }
32 |
33 | @Override
34 | protected String getJSMainModuleName() {
35 | return "index";
36 | }
37 | @Override
38 | protected boolean isNewArchEnabled() {
39 | return BuildConfig.IS_NEW_ARCHITECTURE_ENABLED;
40 | }
41 | @Override
42 | protected Boolean isHermesEnabled() {
43 | return BuildConfig.IS_HERMES_ENABLED;
44 | }
45 | };
46 | @Override
47 | public ReactNativeHost getReactNativeHost() {
48 | return mReactNativeHost;
49 | }
50 | @Override
51 | public void onCreate() {
52 | super.onCreate();
53 | SoLoader.init(this, /* native exopackage */ false);
54 | if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
55 | // If you opted-in for the New Architecture, we load the native entry point for this app.
56 | DefaultNewArchitectureEntryPoint.load();
57 | }
58 | ReactNativeFlipper.initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
59 | }
60 | }
--------------------------------------------------------------------------------
/template/template/android/app/src/main/res/drawable/rn_edit_text_material.xml:
--------------------------------------------------------------------------------
1 |
2 |
16 |
21 |
22 |
23 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/template/template/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uiwjs/react-native-template/cf63e26fd864fb54b13d52c8760a140ef81ca7ab/template/template/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/template/template/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uiwjs/react-native-template/cf63e26fd864fb54b13d52c8760a140ef81ca7ab/template/template/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/template/template/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uiwjs/react-native-template/cf63e26fd864fb54b13d52c8760a140ef81ca7ab/template/template/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/template/template/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uiwjs/react-native-template/cf63e26fd864fb54b13d52c8760a140ef81ca7ab/template/template/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/template/template/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uiwjs/react-native-template/cf63e26fd864fb54b13d52c8760a140ef81ca7ab/template/template/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/template/template/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uiwjs/react-native-template/cf63e26fd864fb54b13d52c8760a140ef81ca7ab/template/template/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/template/template/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uiwjs/react-native-template/cf63e26fd864fb54b13d52c8760a140ef81ca7ab/template/template/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/template/template/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uiwjs/react-native-template/cf63e26fd864fb54b13d52c8760a140ef81ca7ab/template/template/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/template/template/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uiwjs/react-native-template/cf63e26fd864fb54b13d52c8760a140ef81ca7ab/template/template/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/template/template/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uiwjs/react-native-template/cf63e26fd864fb54b13d52c8760a140ef81ca7ab/template/template/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/template/template/android/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | HelloWorld
3 |
4 |
--------------------------------------------------------------------------------
/template/template/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/template/template/android/app/src/release/java/com/helloworld/ReactNativeFlipper.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) Meta Platforms, Inc. and affiliates.
3 | *
4 | * This source code is licensed under the MIT license found in the LICENSE file in the root
5 | * directory of this source tree.
6 | */
7 | package com.helloworld;
8 | import android.content.Context;
9 | import com.facebook.react.ReactInstanceManager;
10 | /**
11 | * Class responsible of loading Flipper inside your React Native application. This is the release
12 | * flavor of it so it's empty as we don't want to load Flipper.
13 | */
14 | public class ReactNativeFlipper {
15 | public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) {
16 | // Do nothing as we don't want to initialize Flipper on Release.
17 | }
18 | }
--------------------------------------------------------------------------------
/template/template/android/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | ext {
5 | buildToolsVersion = "33.0.0"
6 | minSdkVersion = 21
7 | compileSdkVersion = 33
8 | targetSdkVersion = 33
9 |
10 | // We use NDK 23 which has both M1 support and is the side-by-side NDK version from AGP.
11 | ndkVersion = "23.1.7779620"
12 | }
13 | repositories {
14 | google()
15 | mavenCentral()
16 | }
17 | dependencies {
18 | classpath("com.android.tools.build:gradle:7.3.1")
19 | classpath("com.facebook.react:react-native-gradle-plugin")
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/template/template/android/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx512m -XX:MaxMetaspaceSize=256m
13 | org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
19 |
20 | # AndroidX package structure to make it clearer which packages are bundled with the
21 | # Android operating system, and which are packaged with your app's APK
22 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
23 | android.useAndroidX=true
24 | # Automatically convert third-party libraries to use AndroidX
25 | android.enableJetifier=true
26 |
27 | # Version of flipper SDK to use with React Native
28 | FLIPPER_VERSION=0.125.0
29 |
30 | # Use this property to specify which architecture you want to build.
31 | # You can also override it from the CLI using
32 | # ./gradlew -PreactNativeArchitectures=x86_64
33 | reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64
34 |
35 | # Use this property to enable support to the new architecture.
36 | # This will allow you to use TurboModules and the Fabric render in
37 | # your application. You should enable this flag either if you want
38 | # to write custom TurboModules/Fabric components OR use libraries that
39 | # are providing them.
40 | newArchEnabled=false
41 |
42 |
43 | # Use this property to enable or disable the Hermes JS engine.
44 | # If set to false, you will be using JSC instead.
45 | hermesEnabled=true
46 |
47 |
--------------------------------------------------------------------------------
/template/template/android/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uiwjs/react-native-template/cf63e26fd864fb54b13d52c8760a140ef81ca7ab/template/template/android/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/template/template/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-all.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/template/template/android/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/template/template/android/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'HelloWorld'
2 | apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings)
3 | include ':app'
4 | includeBuild('../node_modules/react-native-gradle-plugin')
5 |
6 |
--------------------------------------------------------------------------------
/template/template/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "HelloWorld",
3 | "displayName": "HelloWorld"
4 | }
--------------------------------------------------------------------------------
/template/template/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: ['module:metro-react-native-babel-preset'],
3 | plugins: [
4 | 'react-native-reanimated/plugin'
5 | ]
6 | };
7 |
--------------------------------------------------------------------------------
/template/template/index.js:
--------------------------------------------------------------------------------
1 | import {AppRegistry} from 'react-native';
2 | import App from './src/App';
3 | import {name as appName} from './app.json';
4 |
5 | AppRegistry.registerComponent(appName, () => App);
6 |
--------------------------------------------------------------------------------
/template/template/ios/.xcode.env:
--------------------------------------------------------------------------------
1 | export NODE_BINARY=$(command -v node)
2 |
--------------------------------------------------------------------------------
/template/template/ios/HelloWorld.xcodeproj/xcshareddata/xcschemes/HelloWorld.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
33 |
39 |
40 |
41 |
42 |
43 |
53 |
55 |
61 |
62 |
63 |
64 |
70 |
72 |
78 |
79 |
80 |
81 |
83 |
84 |
87 |
88 |
89 |
--------------------------------------------------------------------------------
/template/template/ios/HelloWorld.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/template/template/ios/HelloWorld.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/template/template/ios/HelloWorld/AppDelegate.h:
--------------------------------------------------------------------------------
1 | #import
2 | #import
3 | @interface AppDelegate : RCTAppDelegate
4 | @end
5 |
--------------------------------------------------------------------------------
/template/template/ios/HelloWorld/AppDelegate.mm:
--------------------------------------------------------------------------------
1 | #import "AppDelegate.h"
2 |
3 | #import
4 |
5 |
6 |
7 |
8 | @implementation AppDelegate
9 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
10 | {
11 | self.moduleName = @"HelloWorld";
12 | // You can add your custom initial props in the dictionary below.
13 | // They will be passed down to the ViewController used by React Native.
14 | self.initialProps = @{};
15 | return [super application:application didFinishLaunchingWithOptions:launchOptions];
16 | }
17 |
18 | - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
19 | {
20 | #if DEBUG
21 | return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"];
22 | #else
23 | return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
24 | #endif
25 | }
26 | /// This method controls whether the `concurrentRoot`feature of React18 is turned on or off.
27 | ///
28 | /// @see: https://reactjs.org/blog/2022/03/29/react-v18.html
29 | /// @note: This requires to be rendering on Fabric (i.e. on the New Architecture).
30 | /// @return: `true` if the `concurrentRoot` feature is enabled. Otherwise, it returns `false`.
31 | - (BOOL)concurrentRootEnabled
32 | {
33 | return true;
34 | }
35 | @end
36 |
--------------------------------------------------------------------------------
/template/template/ios/HelloWorld/Images.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "scale" : "2x",
6 | "size" : "20x20"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "scale" : "3x",
11 | "size" : "20x20"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "scale" : "2x",
16 | "size" : "29x29"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "scale" : "3x",
21 | "size" : "29x29"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "scale" : "2x",
26 | "size" : "40x40"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "scale" : "3x",
31 | "size" : "40x40"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "scale" : "2x",
36 | "size" : "60x60"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "scale" : "3x",
41 | "size" : "60x60"
42 | },
43 | {
44 | "idiom" : "ios-marketing",
45 | "scale" : "1x",
46 | "size" : "1024x1024"
47 | }
48 | ],
49 | "info" : {
50 | "author" : "xcode",
51 | "version" : 1
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/template/template/ios/HelloWorld/Images.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/template/template/ios/HelloWorld/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleDisplayName
8 | HelloWorld
9 | CFBundleExecutable
10 | $(EXECUTABLE_NAME)
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | $(MARKETING_VERSION)
21 | CFBundleSignature
22 | ????
23 | CFBundleVersion
24 | $(CURRENT_PROJECT_VERSION)
25 | LSRequiresIPhoneOS
26 |
27 | NSAppTransportSecurity
28 |
29 | NSExceptionDomains
30 |
31 | localhost
32 |
33 | NSExceptionAllowsInsecureHTTPLoads
34 |
35 |
36 |
37 |
38 | NSLocationWhenInUseUsageDescription
39 |
40 | UILaunchStoryboardName
41 | LaunchScreen
42 | UIRequiredDeviceCapabilities
43 |
44 | armv7
45 |
46 | UISupportedInterfaceOrientations
47 |
48 | UIInterfaceOrientationPortrait
49 | UIInterfaceOrientationLandscapeLeft
50 | UIInterfaceOrientationLandscapeRight
51 |
52 | UIViewControllerBasedStatusBarAppearance
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/template/template/ios/HelloWorld/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
24 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/template/template/ios/HelloWorld/main.m:
--------------------------------------------------------------------------------
1 | #import
2 |
3 | #import "AppDelegate.h"
4 |
5 | int main(int argc, char *argv[])
6 | {
7 | @autoreleasepool {
8 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
9 | }
10 | }
--------------------------------------------------------------------------------
/template/template/ios/HelloWorldTests/HelloWorldTests.m:
--------------------------------------------------------------------------------
1 | #import
2 | #import
3 |
4 | #import
5 | #import
6 |
7 | #define TIMEOUT_SECONDS 600
8 | #define TEXT_TO_LOOK_FOR @"Welcome to React"
9 |
10 | @interface HelloWorldTests : XCTestCase
11 |
12 | @end
13 |
14 | @implementation HelloWorldTests
15 |
16 | - (BOOL)findSubviewInView:(UIView *)view matching:(BOOL (^)(UIView *view))test
17 | {
18 | if (test(view)) {
19 | return YES;
20 | }
21 | for (UIView *subview in [view subviews]) {
22 | if ([self findSubviewInView:subview matching:test]) {
23 | return YES;
24 | }
25 | }
26 | return NO;
27 | }
28 |
29 | - (void)testRendersWelcomeScreen
30 | {
31 | UIViewController *vc = [[[RCTSharedApplication() delegate] window] rootViewController];
32 | NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS];
33 | BOOL foundElement = NO;
34 |
35 | __block NSString *redboxError = nil;
36 | #ifdef DEBUG
37 | RCTSetLogFunction(
38 | ^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) {
39 | if (level >= RCTLogLevelError) {
40 | redboxError = message;
41 | }
42 | });
43 | #endif
44 |
45 | while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) {
46 | [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
47 | [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
48 |
49 | foundElement = [self findSubviewInView:vc.view
50 | matching:^BOOL(UIView *view) {
51 | if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) {
52 | return YES;
53 | }
54 | return NO;
55 | }];
56 | }
57 |
58 | #ifdef DEBUG
59 | RCTSetLogFunction(RCTDefaultLogFunction);
60 | #endif
61 |
62 | XCTAssertNil(redboxError, @"RedBox error: %@", redboxError);
63 | XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS);
64 | }
65 |
66 | @end
67 |
--------------------------------------------------------------------------------
/template/template/ios/HelloWorldTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/template/template/ios/Podfile:
--------------------------------------------------------------------------------
1 | require_relative '../node_modules/react-native/scripts/react_native_pods'
2 | require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'
3 |
4 | platform :ios, min_ios_version_supported
5 | prepare_react_native_project!
6 | # If you are using a `react-native-flipper` your iOS build will fail when `NO_FLIPPER=1` is set.
7 | # because `react-native-flipper` depends on (FlipperKit,...) that will be excluded
8 | #
9 | # To fix this you can also exclude `react-native-flipper` using a `react-native.config.js`
10 | # ```js
11 | # module.exports = {
12 | # dependencies: {
13 | # ...(process.env.NO_FLIPPER ? { 'react-native-flipper': { platforms: { ios: null } } } : {}),
14 | # ```
15 | flipper_config = ENV['NO_FLIPPER'] == "1" ? FlipperConfiguration.disabled : FlipperConfiguration.enabled
16 | linkage = ENV['USE_FRAMEWORKS']
17 | if linkage != nil
18 | Pod::UI.puts "Configuring Pod with #{linkage}ally linked Frameworks".green
19 | use_frameworks! :linkage => linkage.to_sym
20 | end
21 | target 'HelloWorld' do
22 | config = use_native_modules!
23 |
24 | # Flags change depending on the env values.
25 | flags = get_default_flags()
26 |
27 | use_react_native!(
28 | :path => config[:reactNativePath],
29 | # Hermes is now enabled by default. Disable by setting this flag to false.
30 | # Upcoming versions of React Native may rely on get_default_flags(), but
31 | # we make it explicit here to aid in the React Native upgrade process.
32 | :hermes_enabled => false,
33 | :fabric_enabled => flags[:fabric_enabled],
34 | # Enables Flipper.
35 | #
36 | # Note that if you have use_frameworks! enabled, Flipper will not work and
37 | # you should disable the next line.
38 | :flipper_configuration => flipper_config,
39 | # An absolute path to your application root.
40 | :app_path => "#{Pod::Config.instance.installation_root}/.."
41 | )
42 |
43 | target 'HelloWorldTests' do
44 | inherit! :complete
45 | # Pods for testing
46 | end
47 |
48 | post_install do |installer|
49 | react_native_post_install(
50 | installer,
51 | # Set `mac_catalyst_enabled` to `true` in order to apply patches
52 | # necessary for Mac Catalyst builds
53 | :mac_catalyst_enabled => false
54 | )
55 | __apply_Xcode_12_5_M1_post_install_workaround(installer)
56 | end
57 | end
58 |
--------------------------------------------------------------------------------
/template/template/ios/_xcode.env:
--------------------------------------------------------------------------------
1 | # This `.xcode.env` file is versioned and is used to source the environment
2 | # used when running script phases inside Xcode.
3 | # To customize your local environment, you can create an `.xcode.env.local`
4 | # file that is not versioned.
5 |
6 | # NODE_BINARY variable contains the PATH to the node executable.
7 | #
8 | # Customize the NODE_BINARY variable here.
9 | # For example, to use nvm with brew, add the following line
10 | # . "$(brew --prefix nvm)/nvm.sh" --no-use
11 | export NODE_BINARY=$(command -v node)
12 |
--------------------------------------------------------------------------------
/template/template/jsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": ".",
4 | "paths": {
5 | "@": ["src/*"],
6 | "@components/*": ["src/components/*"],
7 | "@utils/*": ["src/utils/*"]
8 | }
9 | }
10 | }
--------------------------------------------------------------------------------
/template/template/metro.config.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Metro configuration for React Native
3 | * https://github.com/facebook/react-native
4 | *
5 | * @format
6 | */
7 |
8 | module.exports = {
9 | transformer: {
10 | getTransformOptions: async () => ({
11 | transform: {
12 | experimentalImportSupport: false,
13 | inlineRequires: true,
14 | },
15 | }),
16 | },
17 | };
18 |
--------------------------------------------------------------------------------
/template/template/mocker/index.js:
--------------------------------------------------------------------------------
1 | const delay = require('mocker-api/lib/delay');
2 | const user = require('./user.mock');
3 |
4 | // 是否禁用代理
5 | const noProxy = process.env.NO_PROXY === 'true';
6 |
7 | const proxy = {
8 | ...user,
9 | };
10 |
11 | module.exports = noProxy ? {...proxy} : delay(proxy, 1000);
12 | // module.exports = proxy;
13 |
--------------------------------------------------------------------------------
/template/template/mocker/user.mock.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | 'POST /api/login': (req, res) => {
3 | let {username, password} = req.body;
4 | if (username === 'admin' && password === 'admin!') {
5 | return res.status(201).json({
6 | message: 'Login successful!',
7 | token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9',
8 | data: {
9 | nikename: 'Hello App',
10 | },
11 | });
12 | }
13 | res.status(401).json({
14 | message: 'username or password is error.',
15 | });
16 | },
17 | 'POST /api/logout': {
18 | message: 'Logout successful!',
19 | },
20 | 'GET /api/auth': {
21 | token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9',
22 | // token: '',
23 | },
24 | };
25 |
--------------------------------------------------------------------------------
/template/template/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "HelloWorld",
3 | "version": "0.0.1",
4 | "private": true,
5 | "scripts": {
6 | "android": "react-native run-android",
7 | "ios": "react-native run-ios --simulator 'iPhone 14'",
8 | "start": "react-native start --reset-cache",
9 | "test": "jest",
10 | "api": "mocker ./mocker",
11 | "api2": "NO_PROXY=true mocker ./mocker",
12 | "lint": "eslint . --ext .js,.jsx",
13 | "prettier": "prettier --write '**/*.{js,jsx,md,json}'",
14 | "precommit": "npm run lint",
15 | "lint-staged": "lint-staged",
16 | "prepare": "husky install",
17 | "doc": "kktd @uiw/react-native-doc/doc/build"
18 | },
19 | "dependencies": {
20 | "@react-native-async-storage/async-storage": "~1.17.11",
21 | "@react-native-community/masked-view": "~0.1.11",
22 | "@react-navigation/bottom-tabs": "~6.3.2",
23 | "@react-navigation/native": "~6.0.11",
24 | "@react-navigation/stack": "~6.2.2",
25 | "react-native-safe-area-context": "~4.3.1",
26 | "react-native-reanimated": "3.1.0",
27 | "@rematch/core": "2.2.0",
28 | "@rematch/loading": "2.1.2",
29 | "@uiw/formatter": "~1.3.3",
30 | "@uiw/react-native": "^4.0.2",
31 | "react-native-gesture-handler": "2.8.0",
32 | "react-native-root-siblings":"4.1.1",
33 | "react-native-svg": "13.9.0",
34 | "react": "18.2.0",
35 | "react-native": "0.71.7",
36 | "react-native-device-info": "~10.0.2",
37 | "react-native-screens": "~3.15.0",
38 | "react-redux": "8.0.5",
39 | "redux": "4.1.2",
40 | "react-query": "~3.39.2",
41 | "@kkt/doc": "^1.0.0",
42 | "@uiw/react-native-doc": "^4.0.5"
43 | },
44 | "devDependencies": {
45 | "@babel/core": "~7.20.0",
46 | "@babel/preset-env": "^7.20.0",
47 | "@babel/runtime": "~7.20.0",
48 | "@react-native-community/eslint-config": "3.2.0",
49 | "@tsconfig/react-native": "^2.0.2",
50 | "@types/jest": "^29.2.1",
51 | "@types/react": "^18.0.24",
52 | "@types/react-test-renderer": "^18.0.0",
53 | "babel-jest": "~29.2.1",
54 | "babel-plugin-module-resolver": "^4.1.0",
55 | "eslint": "~8.21.0",
56 | "eslint-plugin-prettier": "~4.2.1",
57 | "mocker-api": "~2.9.5",
58 | "prettier": "^2.8.0",
59 | "jest": "29.2.1",
60 | "metro-react-native-babel-preset": "^0.73.9",
61 | "lint-staged": "~12.5.0",
62 | "husky": "^8.0.0",
63 | "react-test-renderer": "18.2.0",
64 | "typescript": "4.8.4"
65 | },
66 | "lint-staged": {
67 | "*.{js,jsx}": [
68 | "eslint --fix",
69 | "git add"
70 | ],
71 | "*.{js,jsx,less,md,json}": [
72 | "prettier --write"
73 | ]
74 | },
75 | "jest": {
76 | "preset": "react-native"
77 | }
78 | }
--------------------------------------------------------------------------------
/template/template/src/App.js:
--------------------------------------------------------------------------------
1 | import "react-native-gesture-handler";
2 | import React from "react";
3 | import { StatusBar, useColorScheme } from "react-native";
4 | import {
5 | NavigationContainer,
6 | useNavigationContainerRef,
7 | DefaultTheme,
8 | DarkTheme,
9 | } from "@react-navigation/native";
10 | import { createStackNavigator } from "@react-navigation/stack";
11 | import { Provider } from "react-redux";
12 | import { store } from "./models";
13 | import AuthLoadingScreen from "./pages/AuthLoading";
14 | import { stackPageData } from "./routes";
15 | import { QueryClient, QueryClientProvider } from "react-query";
16 | import { ThemeProvider, theme } from "@uiw/react-native";
17 |
18 | const Stack = createStackNavigator();
19 | const queryClient = new QueryClient();
20 |
21 | export default () => {
22 | const navigationRef = useNavigationContainerRef();
23 | const colorScheme = useColorScheme();
24 | return (
25 |
26 |
27 |
28 |
35 |
39 |
40 | {(token) => (
41 |
42 | {stackPageData.map((props, index) => {
43 | return (
44 | null
50 | // }}
51 | // component={Home}
52 | />
53 | );
54 | })}
55 |
56 | )}
57 |
58 |
59 |
60 |
61 |
62 | );
63 | };
64 |
--------------------------------------------------------------------------------
/template/template/src/components/Footer/index.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 | import {Text, StyleSheet} from 'react-native';
3 | import {Flex, Icon} from '@uiw/react-native';
4 |
5 | export default class Footer extends Component {
6 | render() {
7 | const {style} = this.props;
8 | return (
9 |
10 | Shanghai xxx xxx xxx Co., Ltd.
11 | Copyright © 2020-2025
12 |
13 | );
14 | }
15 | }
16 |
17 | const styles = StyleSheet.create({
18 | footer: {
19 | fontSize: 12,
20 | paddingVertical: 10,
21 | },
22 | copyright: {
23 | color: '#C2C2C2',
24 | fontSize: 12,
25 | },
26 | company: {
27 | paddingTop: 10,
28 | paddingBottom: 3,
29 | color: '#C2C2C2',
30 | fontSize: 12,
31 | },
32 | });
33 |
--------------------------------------------------------------------------------
/template/template/src/components/icons/signin.js:
--------------------------------------------------------------------------------
1 | export const logo = `
2 |
5 | `;
6 | export const logoLight = `
7 |
10 | `;
11 |
--------------------------------------------------------------------------------
/template/template/src/config.js:
--------------------------------------------------------------------------------
1 | import {getUniqueId, getVersion} from 'react-native-device-info';
2 |
3 | export default {
4 | /**
5 | * AndroidX Support
6 | * This module defaults to AndroidX you should configure your library versions similar to
7 | * this in your `android/build.gradle` file's "ext" block
8 | * https://www.npmjs.com/package/react-native-device-info#androidx-support
9 | */
10 | uid: getUniqueId(),
11 | /**
12 | * Gets the application version.
13 | */
14 | version: getVersion(),
15 | /**
16 | * The production value is `true` and there is no host option interface.
17 | */
18 | production: false,
19 | /**
20 | * Default first.
21 | */
22 | hosts: [
23 | {
24 | label: 'Native Mock API',
25 | type: 'Test',
26 | url: 'http://localhost:3721',
27 | },
28 | {
29 | label: 'Production Environment',
30 | type: 'production',
31 | url: 'http://103.20.249.82:18901',
32 | },
33 | ],
34 | };
35 |
--------------------------------------------------------------------------------
/template/template/src/global.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Store some global objects for easy calling
3 | *
4 | * - `navigation` Route go to page object
5 | */
6 |
7 | export default {};
8 |
--------------------------------------------------------------------------------
/template/template/src/hooks/users.js:
--------------------------------------------------------------------------------
1 | import { Alert } from 'react-native';
2 | import AsyncStorage from '@react-native-async-storage/async-storage';
3 | import { userLogin, userAuth } from '../services/users';
4 | import { useQuery, useMutation } from 'react-query';
5 | import Global from '../global';
6 | import conf from '../config';
7 | import { useSelector, useDispatch } from 'react-redux'
8 | // 登录
9 | export const login = ({ mutationKey }) => {
10 | const dispatch = useDispatch()
11 | const mutation = useMutation({
12 | mutationKey,
13 | mutationFn: userLogin,
14 | onSuccess: async data => {
15 | if (data?.token && data?.data) {
16 | await AsyncStorage.setItem('token', data.token);
17 | await AsyncStorage.setItem('userData', JSON.stringify(data.data));
18 | dispatch({
19 | type: "global/update",
20 | payload: {
21 | token: data.token,
22 | userData: JSON.stringify(data.data)
23 | }
24 | })
25 | if (Global.navigation) {
26 | Global.navigation.replace('Tab');
27 | }
28 | } else if (data && data.message) {
29 | Alert.alert(`Login failed - ${data.error}`, data.message);
30 | }
31 | },
32 | });
33 | return mutation;
34 | };
35 |
36 | // 验证token
37 | export const useAuthToken = () => {
38 | const { token } = useSelector(state => state.global)
39 | const dispatch = useDispatch()
40 | const mutation = useMutation({
41 | mutationFn: userAuth,
42 | onMutate: async () => {
43 | let host = await AsyncStorage.getItem('apihost');
44 | if (!host && conf.hosts[0]) {
45 | await AsyncStorage.setItem('apihost', JSON.stringify(conf.hosts[0]));
46 | dispatch({
47 | type: "global/update",
48 | payload: {
49 | apihost: conf.hosts[0]
50 | }
51 | })
52 | }
53 | if (!token) {
54 | await AsyncStorage.removeItem('userData');
55 | await AsyncStorage.removeItem('token');
56 | }
57 | },
58 | onSuccess: async data => {
59 | if (data?.token) {
60 | dispatch({
61 | type: "global/update",
62 | payload: {
63 | token: data.token,
64 | authState: true
65 | }
66 | })
67 | } else {
68 | dispatch({
69 | type: "global/update",
70 | payload: {
71 | authState: true,
72 | token: null
73 | }
74 | })
75 | }
76 | },
77 | });
78 | return mutation;
79 | };
80 |
81 | // 退出
82 | export const logout = () => {
83 | const dispatch = useDispatch()
84 | AsyncStorage.removeItem('token');
85 | AsyncStorage.removeItem('userData');
86 | dispatch({
87 | type: "global/update",
88 | payload: {
89 | token: null,
90 | authState: null
91 | }
92 | })
93 | if (Global.navigation) {
94 | Global.navigation.navigate?.('SignIn');
95 | }
96 | };
97 |
--------------------------------------------------------------------------------
/template/template/src/models/global.js:
--------------------------------------------------------------------------------
1 | import AsyncStorage from '@react-native-async-storage/async-storage';
2 | import { userAuth } from '../services/users';
3 | import conf from '../config';
4 |
5 | export default {
6 | state: {
7 | /**
8 | * 验证是否登录
9 | */
10 | authState: false,
11 | token: null,
12 | apihost: null,
13 | userData: null,
14 | },
15 | reducers: {
16 | update: (state, payload) => ({ ...state, ...payload }),
17 | },
18 | effects: dispatch => ({}),
19 | };
20 |
--------------------------------------------------------------------------------
/template/template/src/models/index.js:
--------------------------------------------------------------------------------
1 | import {init} from '@rematch/core';
2 | import createLoadingPlugin from '@rematch/loading';
3 | import * as global from './global';
4 |
5 | const loadingPlugin = createLoadingPlugin({});
6 |
7 | export const store = init({
8 | models: {
9 | global: global.default,
10 | },
11 | plugins: [
12 | loadingPlugin,
13 | // {
14 | // middleware: () => next => async (action) => {
15 | // // if (typeof window !== 'undefined') {
16 | // // const token = cookie.get('token');
17 | // // if (token) {
18 | // // await cookie.set('token', token, 1);
19 | // // }
20 | // // }
21 | // // do something here
22 | // return next(action);
23 | // },
24 | // },
25 | ],
26 | });
27 |
--------------------------------------------------------------------------------
/template/template/src/pages/AuthLoading/index.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from 'react';
2 | import { Text, StatusBar, StyleSheet, SafeAreaView } from 'react-native';
3 | import { useSelector } from 'react-redux';
4 | import { Flex, Loader, H3, Icon } from '@uiw/react-native';
5 | import Global from '../../global';
6 | import { logoLight } from '../../components/icons/signin';
7 | import Footer from '../../components/Footer';
8 | import { useAuthToken } from '../../hooks/users'
9 |
10 |
11 | const AuthLoadingScreen = ({
12 | navigation,
13 | children
14 | }) => {
15 | const { token, authState } = useSelector(state=>state.global)
16 | const { mutate, isLoading } = useAuthToken()
17 |
18 | useEffect(() => {
19 | if (navigation && Global) {
20 | Global.navigation = navigation;
21 | }
22 | mutate();
23 | }, [])
24 |
25 | if (children && typeof children === 'function' && authState) {
26 | return children(token);
27 | }
28 | return (
29 |
30 |
31 |
32 |
33 |
34 | My APP
35 |
36 |
37 | Verify login...} />
38 |
39 |
40 |
41 |
42 | );
43 | }
44 |
45 | export default AuthLoadingScreen
46 |
47 | const styles = StyleSheet.create({
48 | container: {
49 | flex: 1,
50 | backgroundColor: '#2F2F2F',
51 | },
52 | header: {
53 | marginTop: 110,
54 | },
55 | title: {
56 | marginTop: 30,
57 | fontWeight: '500',
58 | color: '#FFFFFF',
59 | },
60 | });
61 |
--------------------------------------------------------------------------------
/template/template/src/pages/DevOptions/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { connect } from 'react-redux';
3 | import AsyncStorage from '@react-native-async-storage/async-storage';
4 | import { TextInput, SafeAreaView, View, Text, StatusBar, StyleSheet, ScrollView, Platform, KeyboardAvoidingView } from 'react-native';
5 | import { Button, WingBlank, Icon, Flex, Spacing, H4, List } from '@uiw/react-native';
6 | import conf from '../../config';
7 |
8 | class DevOptions extends React.Component {
9 | constructor(props) {
10 | super(props);
11 | this.state = {
12 | dataList: [...conf.hosts],
13 | selectUrl: {},
14 | height: 0,
15 | };
16 | }
17 | async componentDidMount() {
18 | // 选择的 API URL
19 | let apihost = await AsyncStorage.getItem('apihost');
20 | const cacheData = await AsyncStorage.getItem('cacheURLData');
21 | const state = {};
22 | if (cacheData) {
23 | state.dataList = JSON.parse(cacheData);
24 | } else {
25 | state.dataList = this.state.dataList;
26 | }
27 | if (apihost) {
28 | apihost = JSON.parse(apihost);
29 | const selectUrl = state.dataList.find(item => item.url === apihost.url);
30 | state.selectUrl = selectUrl || {};
31 | }
32 | // eslint-disable-next-line react/no-did-mount-set-state
33 | this.setState({ ...state });
34 | }
35 | async handleSelect(data) {
36 | await this.setState({ selectUrl: data });
37 | await AsyncStorage.setItem('apihost', JSON.stringify(data));
38 | this.props.update({ apihost: data });
39 | }
40 | async handleEndEditing(e) {
41 | const { dataList } = this.state;
42 | const text = e.nativeEvent.text;
43 | const isInclude = dataList.find(item => item.url === text);
44 | if (!isInclude && text) {
45 | const customUrl = { url: text, label: 'Custom URL', type: 'custom' };
46 | dataList.unshift(customUrl);
47 | await AsyncStorage.setItem('cacheURLData', JSON.stringify(dataList));
48 | this.setState({ dataList, selectUrl: customUrl, customUrl: '' });
49 | }
50 | }
51 | deleteCustomUrl = async () => {
52 | const { dataList, selectUrl } = this.state;
53 | const data = dataList.filter(item => item.url !== selectUrl.url);
54 | this.setState({ dataList: data, selectUrl: {} });
55 | await AsyncStorage.setItem('cacheURLData', JSON.stringify(data));
56 | };
57 | handleCustomUrl = async customUrl => {
58 | await this.setState({ customUrl });
59 | };
60 | measureContainer = event => {
61 | const { height } = event.nativeEvent.layout;
62 | this.setState({ height });
63 | };
64 | render() {
65 | const { navigation } = this.props;
66 | const DataSourceView = (
67 |
68 |
69 |
81 |
82 |
83 | {this.state.dataList.map((item, idx) => (
84 |
90 | {item.url === this.state.selectUrl.url && }
91 | {item.label}
92 |
93 | ))}
94 |
95 |
96 | );
97 | return (
98 |
99 |
100 |
101 |
102 |
105 |
106 |
107 |
108 | Select Host
109 |
110 |
111 | {Platform.OS === 'ios' ? (
112 |
113 | {DataSourceView}
114 |
115 | ) : (
116 | DataSourceView
117 | )}
118 | {this.state.selectUrl.type === 'custom' && (
119 |
120 |
123 |
124 | )}
125 |
126 |
127 |
128 | );
129 | }
130 | }
131 |
132 | export default connect(
133 | ({ }) => ({}),
134 | ({ global }) => ({
135 | update: global.update,
136 | }),
137 | )(DevOptions);
138 |
139 | const styles = StyleSheet.create({
140 | block: {
141 | flex: 1,
142 | backgroundColor: '#2F2F2F',
143 | },
144 | title: {
145 | color: '#fff',
146 | },
147 | urlListIcon: {
148 | marginRight: 5,
149 | },
150 | input: {
151 | backgroundColor: '#636363',
152 | paddingHorizontal: 10,
153 | paddingVertical: 10,
154 | borderRadius: 5,
155 | color: '#fff',
156 | fontWeight: '200',
157 | fontSize: 16,
158 | },
159 | header: {
160 | paddingTop: 53,
161 | paddingBottom: 30,
162 | },
163 | content: {
164 | backgroundColor: '#efefef',
165 | borderRadius: 8,
166 | },
167 | btn: {
168 | width: '100%',
169 | paddingHorizontal: 5,
170 | paddingVertical: 16,
171 | textAlign: 'center',
172 | fontSize: 20,
173 | },
174 | footer: {
175 | borderWidth: 1,
176 | },
177 | });
178 |
--------------------------------------------------------------------------------
/template/template/src/pages/MyHome/Setting/index.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { View, SafeAreaView } from "react-native";
3 | export default class MyScreen extends Component {
4 | render() {
5 | return ;
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/template/template/src/pages/MyHome/index.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { View, SafeAreaView } from "react-native";
3 | import { Button, List, Icon, Text } from "@uiw/react-native";
4 |
5 | export default class MyScreen extends Component {
6 | render() {
7 | const { navigation } = this.props;
8 | return (
9 |
10 |
11 | navigation.navigate("MyHomeSetting"),
19 | },
20 | {
21 | title: "退出登录",
22 | onPress: () => navigation.replace("SignIn"),
23 | },
24 | ]}
25 | renderItem={({ item, index }) => {
26 | return (
27 | }
30 | size="large"
31 | paddingLeft={15}
32 | style={{ borderBottomWidth: 0 }}
33 | onPress={item.onPress || null}
34 | >
35 |
36 | {item.title}
37 |
38 |
39 | );
40 | }}
41 | />
42 |
43 |
44 | );
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/template/template/src/pages/OrderHome/index.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { View, SafeAreaView } from "react-native";
3 |
4 | export default class MyScreen extends Component {
5 | render() {
6 | return ;
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/template/template/src/pages/SignIn/index.js:
--------------------------------------------------------------------------------
1 | import React, { Component, useState, useEffect } from 'react';
2 | import { connect } from 'react-redux';
3 | import AsyncStorage from '@react-native-async-storage/async-storage';
4 | import { TextInput, SafeAreaView, StyleSheet, StatusBar, Text } from 'react-native';
5 | import { Button, H4, Flex, Spacing, P, Icon, CheckBox, Badge } from '@uiw/react-native';
6 | import Global from '../../global';
7 | import Footer from '../../components/Footer';
8 | import { logoLight } from '../../components/icons/signin';
9 | import conf from '../../config';
10 | import { login } from '../../hooks/users'
11 |
12 | const SigninScreen = ({
13 | navigation,
14 | }) => {
15 | const [store, setStore] = useState({
16 | hostType: '',
17 | formData: {
18 | username: 'admin',
19 | password: 'admin!',
20 | },
21 | })
22 | const { hostType, formData } = store
23 |
24 | const { mutate, isLoading } = login({ mutationKey: ['userLogin', formData] })
25 |
26 | useEffect(() => {
27 | if (navigation && Global) {
28 | Global.navigation = navigation;
29 | }
30 | _getHostType();
31 | }, [])
32 |
33 | const _getHostType = async () => {
34 | if (conf.production) {
35 | const productionOptions = conf.hosts.find(itm => itm.type === 'production');
36 | await AsyncStorage.setItem('apihost', JSON.stringify(productionOptions));
37 | } else {
38 | const host = await AsyncStorage.getItem('apihost');
39 | setStore({ ...store, hostType: JSON.parse(host).type })
40 | }
41 | };
42 |
43 | const loginIn = () => mutate?.(formData)
44 |
45 | return (
46 |
47 |
48 | {!conf.production && (
49 |
50 |
53 |
54 | )}
55 |
56 |
57 |
58 |
59 | Sign In
60 | {!conf.production && {hostType}}
61 | Enter username and password.
62 |
63 |
64 |
65 | setStore({ ...store, formData: { ...formData, username: text } })}
72 | />
73 |
74 | setStore({ ...store, formData: { ...formData, password: text } })}
81 | />
82 |
83 |
93 |
94 |
95 |
96 |
97 |
98 | );
99 | }
100 |
101 | export default SigninScreen
102 |
103 | const styles = StyleSheet.create({
104 | block: {
105 | flex: 1,
106 | backgroundColor: '#2F2F2F',
107 | },
108 | setting: {
109 | marginRight: 16,
110 | },
111 | header: {
112 | paddingTop: 43,
113 | paddingBottom: 20,
114 | },
115 | titie: {
116 | color: '#fff',
117 | marginTop: 26,
118 | marginBottom: 0,
119 | },
120 | description: {
121 | color: '#fff',
122 | fontSize: 12,
123 | marginBottom: 0,
124 | fontWeight: '200',
125 | },
126 | input: {
127 | width: 243,
128 | backgroundColor: '#636363',
129 | paddingHorizontal: 10,
130 | paddingVertical: 10,
131 | borderRadius: 6,
132 | color: '#fff',
133 | fontWeight: '200',
134 | fontSize: 16,
135 | },
136 | button: {
137 | // marginTop: 10,
138 | paddingHorizontal: 35,
139 | paddingVertical: 4,
140 | },
141 | hostNotice: {
142 | right: -60,
143 | top: -30,
144 | width: 40,
145 | height: 20,
146 | borderRadius: 3,
147 | overflow: 'hidden',
148 | color: '#fff',
149 | fontSize: 14,
150 | textAlign: 'center',
151 | backgroundColor: '#FFCB00',
152 | },
153 | });
154 |
--------------------------------------------------------------------------------
/template/template/src/pages/TransportHome/index.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { SafeAreaView } from 'react-native';
3 |
4 | export default function MyScreen() {
5 | return (
6 |
7 | );
8 | }
9 |
--------------------------------------------------------------------------------
/template/template/src/routes/index.js:
--------------------------------------------------------------------------------
1 | import SignIn from "../pages/SignIn";
2 | import DevOptions from "../pages/DevOptions";
3 | import MyHomeSetting from "../pages/MyHome/Setting";
4 | import TabsScreen from "./tabs";
5 |
6 | export const stackPageData = [
7 | {
8 | name: "Tab",
9 | component: TabsScreen,
10 | options: {
11 | headerShown: false,
12 | title: "首页",
13 | },
14 | },
15 | {
16 | name: "SignIn",
17 | component: SignIn,
18 | options: {
19 | headerShown: false,
20 | header: () => null,
21 | },
22 | },
23 | {
24 | name: "DevOptions",
25 | component: DevOptions,
26 | options: {
27 | headerShown: false,
28 | header: () => null,
29 | },
30 | },
31 | {
32 | name: "MyHomeSetting",
33 | component: MyHomeSetting,
34 | options: {
35 | title: "设置",
36 | },
37 | },
38 | ];
39 |
--------------------------------------------------------------------------------
/template/template/src/routes/tabs.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {StatusBar} from 'react-native';
3 | import {useTheme, Text, Icon} from '@uiw/react-native';
4 | import {createBottomTabNavigator} from '@react-navigation/bottom-tabs';
5 | import MyHome from '../pages/MyHome';
6 | import OrderHome from '../pages/OrderHome';
7 | import TransportHome from '../pages/TransportHome';
8 |
9 | const BottomTabs = createBottomTabNavigator();
10 | const tabs = [
11 | {
12 | name: 'TransportHome',
13 | component: TransportHome,
14 | label: '发货',
15 | icon: 'inbox',
16 | },
17 | {
18 | name: 'OrderHome',
19 | component: OrderHome,
20 | label: '订单',
21 | icon: 'file-text',
22 | },
23 | {
24 | name: 'MyHome',
25 | component: MyHome,
26 | label: '我的',
27 | icon: 'user',
28 | },
29 | ];
30 | const TabsScreen = props => {
31 | const theme = useTheme();
32 | return (
33 |
34 |
35 |
40 | {tabs.map((item, idx) => {
41 | return (
42 | (
52 |
57 | {item?.label}
58 |
59 | ),
60 | // eslint-disable-next-line react/no-unstable-nested-components
61 | tabBarIcon: ({focused}) => ,
62 | }}
63 | />
64 | );
65 | })}
66 |
67 |
68 | );
69 | };
70 |
71 | export default TabsScreen;
72 |
--------------------------------------------------------------------------------
/template/template/src/services/users.js:
--------------------------------------------------------------------------------
1 | import {fetch} from '../utils';
2 |
3 | /**
4 | * Auth token
5 | */
6 | export async function userAuth(params) {
7 | return fetch('/api/auth', {
8 | method: 'GET',
9 | body: params,
10 | });
11 | }
12 |
13 | /**
14 | * login
15 | */
16 | export async function userLogin(params) {
17 | return fetch('/api/login', {
18 | body: params,
19 | });
20 | }
21 |
22 | /**
23 | * logout
24 | */
25 | export async function userLogout(params) {
26 | return fetch('/api/logout', {
27 | body: params,
28 | });
29 | }
30 |
--------------------------------------------------------------------------------
/template/template/src/utils/fetch.js:
--------------------------------------------------------------------------------
1 | import AsyncStorage from '@react-native-async-storage/async-storage';
2 | import {Alert} from 'react-native';
3 | import Global from '../global';
4 |
5 | export default async function request(url, options) {
6 | let {method = 'POST', body = '', serverId = 'projectId', formdataBody, headers, ...params} = options || {};
7 | if (typeof body !== 'string') {
8 | body = JSON.stringify(body);
9 | }
10 | const header = {
11 | Accept: 'application/json',
12 | 'content-type': 'application/json',
13 | ...headers,
14 | };
15 | const token = await AsyncStorage.getItem('token');
16 |
17 | let host = await AsyncStorage.getItem('apihost');
18 | if (host) {
19 | host = JSON.parse(host);
20 | host = host.url;
21 | }
22 | if (token) {
23 | header.Authorization = token;
24 | }
25 | if (formdataBody) {
26 | // header['content-type'] = 'application/x-www-form-urlencoded';
27 | header['content-type'] = 'multipart/form-data';
28 | params.processData = false;
29 | params.contentType = false;
30 | let formdata = new FormData();
31 | Object.keys(formdataBody).forEach(keyName => {
32 | formdata.append(keyName, String(formdataBody[keyName]));
33 | });
34 | body = formdata;
35 | }
36 | const fetchURL = `${host}/${url.replace(/^\//, '')}`;
37 | // console.log('=> body:', method, fetchURL, body);
38 | // console.log('=> header:', header);
39 | // console.log('=> header:', header['x-auth']);
40 | return fetch(fetchURL, {
41 | method,
42 | body: body,
43 | headers: {...header},
44 | ...params,
45 | })
46 | .then(async response => {
47 | const data = await response.json();
48 | if (/(200|201)/.test(response.status)) {
49 | return data;
50 | }
51 | if (/(401)/.test(response.status)) {
52 | Global.navigation.navigate('SignIn');
53 | return;
54 | }
55 | Alert.alert(`Request Error ${response.status}`, `E2111: ${data.message} - ${fetchURL} - ${JSON.stringify(data)}`);
56 | })
57 | .catch(error => {
58 | Alert.alert('Service abnormal please check server', `E2112:${fetchURL} \n\n ${error.toString()} ${JSON.stringify(body)}`);
59 | });
60 | }
61 |
--------------------------------------------------------------------------------
/template/template/src/utils/index.js:
--------------------------------------------------------------------------------
1 | import fetch from './fetch';
2 |
3 | export {fetch};
4 |
5 | /**
6 | * Sleep second
7 | * @param {Number} ms second
8 | * @example
9 | * ```js
10 | * async function sleepyWork() {
11 | * console.log("I'm going to sleep for 1 second.");
12 | * await sleep(1000);
13 | * console.log('I woke up after 1 second.');
14 | * }
15 | * ```
16 | */
17 | export const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
18 |
--------------------------------------------------------------------------------