├── .all-contributorsrc
├── .github
├── CODEOWNERS
├── CODE_OF_CONDUCT.md
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
└── workflows
│ └── ci.yml
├── .gitignore
├── .husky
├── .gitignore
└── pre-commit
├── .npmignore
├── CapacitorCommunityHttp.podspec
├── LICENSE
├── README.md
├── android
├── .idea
│ ├── compiler.xml
│ ├── misc.xml
│ └── runConfigurations.xml
├── android.iml
├── build.gradle
├── capacitor-community-http.iml
├── capacitor-http.iml
├── gradle.properties
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── proguard-rules.pro
├── settings.gradle
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── getcapacitor
│ │ └── android
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── getcapacitor
│ │ │ └── plugin
│ │ │ └── http
│ │ │ ├── CapacitorCookieManager.java
│ │ │ ├── CapacitorHttpUrlConnection.java
│ │ │ ├── FilesystemUtils.java
│ │ │ ├── FormUploader.java
│ │ │ ├── Http.java
│ │ │ ├── HttpRequestHandler.java
│ │ │ ├── ICapacitorHttpUrlConnection.java
│ │ │ ├── JSValue.java
│ │ │ └── MimeType.java
│ └── res
│ │ ├── layout
│ │ └── bridge_layout_main.xml
│ │ └── values
│ │ ├── colors.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── com
│ └── getcapacitor
│ ├── ExampleUnitTest.java
│ └── plugin
│ └── http
│ └── HttpRequestHandlerTest.java
├── example
├── .editorconfig
├── .gitignore
├── .prettierrc.json
├── android
│ ├── .gitignore
│ ├── app
│ │ ├── .npmignore
│ │ ├── build.gradle
│ │ ├── capacitor.build.gradle
│ │ ├── proguard-rules.pro
│ │ └── src
│ │ │ ├── androidTest
│ │ │ └── java
│ │ │ │ └── com
│ │ │ │ └── getcapacitor
│ │ │ │ └── myapp
│ │ │ │ └── ExampleInstrumentedTest.java
│ │ │ ├── main
│ │ │ ├── AndroidManifest.xml
│ │ │ ├── assets
│ │ │ │ ├── capacitor.config.json
│ │ │ │ └── capacitor.plugins.json
│ │ │ ├── java
│ │ │ │ └── com
│ │ │ │ │ └── example
│ │ │ │ │ └── app
│ │ │ │ │ └── MainActivity.java
│ │ │ └── res
│ │ │ │ ├── drawable-land-hdpi
│ │ │ │ └── splash.png
│ │ │ │ ├── drawable-land-mdpi
│ │ │ │ └── splash.png
│ │ │ │ ├── drawable-land-xhdpi
│ │ │ │ └── splash.png
│ │ │ │ ├── drawable-land-xxhdpi
│ │ │ │ └── splash.png
│ │ │ │ ├── drawable-land-xxxhdpi
│ │ │ │ └── splash.png
│ │ │ │ ├── drawable-port-hdpi
│ │ │ │ └── splash.png
│ │ │ │ ├── drawable-port-mdpi
│ │ │ │ └── splash.png
│ │ │ │ ├── drawable-port-xhdpi
│ │ │ │ └── splash.png
│ │ │ │ ├── drawable-port-xxhdpi
│ │ │ │ └── splash.png
│ │ │ │ ├── drawable-port-xxxhdpi
│ │ │ │ └── splash.png
│ │ │ │ ├── drawable-v24
│ │ │ │ └── ic_launcher_foreground.xml
│ │ │ │ ├── drawable
│ │ │ │ ├── ic_launcher_background.xml
│ │ │ │ └── splash.png
│ │ │ │ ├── layout
│ │ │ │ └── activity_main.xml
│ │ │ │ ├── mipmap-anydpi-v26
│ │ │ │ ├── ic_launcher.xml
│ │ │ │ └── ic_launcher_round.xml
│ │ │ │ ├── mipmap-hdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ ├── ic_launcher_foreground.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ │ ├── mipmap-mdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ ├── ic_launcher_foreground.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ │ ├── mipmap-xhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ ├── ic_launcher_foreground.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ │ ├── mipmap-xxhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ ├── ic_launcher_foreground.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ │ ├── mipmap-xxxhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ ├── ic_launcher_foreground.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ │ ├── values
│ │ │ │ ├── ic_launcher_background.xml
│ │ │ │ ├── strings.xml
│ │ │ │ └── styles.xml
│ │ │ │ └── xml
│ │ │ │ ├── config.xml
│ │ │ │ └── file_paths.xml
│ │ │ └── test
│ │ │ └── java
│ │ │ └── com
│ │ │ └── getcapacitor
│ │ │ └── myapp
│ │ │ └── ExampleUnitTest.java
│ ├── build.gradle
│ ├── capacitor.settings.gradle
│ ├── gradle.properties
│ ├── gradle
│ │ └── wrapper
│ │ │ ├── gradle-wrapper.jar
│ │ │ └── gradle-wrapper.properties
│ ├── gradlew
│ ├── gradlew.bat
│ ├── settings.gradle
│ └── variables.gradle
├── ios
│ └── App
│ │ ├── App.xcodeproj
│ │ ├── project.pbxproj
│ │ └── project.xcworkspace
│ │ │ └── contents.xcworkspacedata
│ │ ├── App.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ └── IDEWorkspaceChecks.plist
│ │ ├── App
│ │ ├── AppDelegate.swift
│ │ ├── Assets.xcassets
│ │ │ ├── AppIcon.appiconset
│ │ │ │ ├── AppIcon-20x20@1x.png
│ │ │ │ ├── AppIcon-20x20@2x-1.png
│ │ │ │ ├── AppIcon-20x20@2x.png
│ │ │ │ ├── AppIcon-20x20@3x.png
│ │ │ │ ├── AppIcon-29x29@1x.png
│ │ │ │ ├── AppIcon-29x29@2x-1.png
│ │ │ │ ├── AppIcon-29x29@2x.png
│ │ │ │ ├── AppIcon-29x29@3x.png
│ │ │ │ ├── AppIcon-40x40@1x.png
│ │ │ │ ├── AppIcon-40x40@2x-1.png
│ │ │ │ ├── AppIcon-40x40@2x.png
│ │ │ │ ├── AppIcon-40x40@3x.png
│ │ │ │ ├── AppIcon-512@2x.png
│ │ │ │ ├── AppIcon-60x60@2x.png
│ │ │ │ ├── AppIcon-60x60@3x.png
│ │ │ │ ├── AppIcon-76x76@1x.png
│ │ │ │ ├── AppIcon-76x76@2x.png
│ │ │ │ ├── AppIcon-83.5x83.5@2x.png
│ │ │ │ └── Contents.json
│ │ │ ├── Contents.json
│ │ │ └── Splash.imageset
│ │ │ │ ├── Contents.json
│ │ │ │ ├── splash-2732x2732-1.png
│ │ │ │ ├── splash-2732x2732-2.png
│ │ │ │ └── splash-2732x2732.png
│ │ ├── Base.lproj
│ │ │ ├── LaunchScreen.storyboard
│ │ │ └── Main.storyboard
│ │ ├── Info.plist
│ │ ├── capacitor.config.json
│ │ └── config.xml
│ │ └── Podfile
├── package-lock.json
├── package.json
├── public
│ ├── favicon.ico
│ └── index.html
├── readme.md
├── server
│ ├── README.md
│ ├── files
│ │ └── static
│ │ │ ├── test.jpg
│ │ │ ├── test.jpg.zip
│ │ │ ├── test.mp4
│ │ │ └── test.pdf
│ ├── insomnia.json
│ ├── package-lock.json
│ ├── package.json
│ ├── src
│ │ ├── routes
│ │ │ ├── basic
│ │ │ │ ├── bool.ts
│ │ │ │ ├── empty.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── json.ts
│ │ │ │ ├── number.ts
│ │ │ │ └── string.ts
│ │ │ ├── content-type
│ │ │ │ ├── image.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── json.ts
│ │ │ │ ├── multipart-form.ts
│ │ │ │ ├── octet-stream.ts
│ │ │ │ ├── pdf.ts
│ │ │ │ ├── plaintext.ts
│ │ │ │ ├── video.ts
│ │ │ │ ├── x-www-form-urlencoded.ts
│ │ │ │ ├── xml.ts
│ │ │ │ └── zip.ts
│ │ │ └── io
│ │ │ │ ├── download.ts
│ │ │ │ ├── index.ts
│ │ │ │ └── upload.ts
│ │ └── server.ts
│ ├── tests
│ │ ├── basic.routes.js
│ │ └── content-type.routes.js
│ └── tsconfig.json
├── src
│ ├── App.tsx
│ ├── index.tsx
│ └── react-app-env.d.ts
└── tsconfig.json
├── ios
├── Plugin.xcodeproj
│ ├── project.pbxproj
│ └── xcuserdata
│ │ └── max.xcuserdatad
│ │ └── xcschemes
│ │ └── xcschememanagement.plist
├── Plugin.xcworkspace
│ ├── contents.xcworkspacedata
│ ├── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
│ └── xcuserdata
│ │ └── max.xcuserdatad
│ │ └── UserInterfaceState.xcuserstate
├── Plugin
│ ├── CapacitorCookieManager.swift
│ ├── CapacitorUrlRequest.swift
│ ├── FilesystemUtils.swift
│ ├── HttpRequestHandler.swift
│ ├── Info.plist
│ ├── Plugin.h
│ ├── Plugin.m
│ └── Plugin.swift
├── PluginTests
│ ├── Info.plist
│ └── PluginTests.swift
├── Podfile
└── Podfile.lock
├── package-lock.json
├── package.json
├── rollup.config.js
├── src
├── cookie.ts
├── definitions.ts
├── index.ts
├── request.ts
├── utils.ts
└── web.ts
└── tsconfig.json
/.all-contributorsrc:
--------------------------------------------------------------------------------
1 | {
2 | "files": [
3 | "README.md"
4 | ],
5 | "imageSize": 100,
6 | "commit": false,
7 | "contributors": [
8 | {
9 | "login": "danielsogl",
10 | "name": "Daniel Sogl",
11 | "avatar_url": "https://avatars2.githubusercontent.com/u/15234844?v=4",
12 | "profile": "https://github.com/danielsogl",
13 | "contributions": [
14 | "doc"
15 | ]
16 | },
17 | {
18 | "login": "priyankpat",
19 | "name": "Priyank Patel",
20 | "avatar_url": "https://avatars3.githubusercontent.com/u/5585797?v=4",
21 | "profile": "http://priyankpatel.io",
22 | "contributions": [
23 | "code"
24 | ]
25 | },
26 | {
27 | "login": "mlynch",
28 | "name": "Max Lynch",
29 | "avatar_url": "https://avatars3.githubusercontent.com/u/11214?v=4",
30 | "profile": "http://ionicframework.com/",
31 | "contributions": [
32 | "code"
33 | ]
34 | },
35 | {
36 | "login": "pixelbucket-dev",
37 | "name": "Falk Schieber",
38 | "avatar_url": "https://avatars3.githubusercontent.com/u/12937991?v=4",
39 | "profile": "https://github.com/pixelbucket-dev",
40 | "contributions": [
41 | "review"
42 | ]
43 | },
44 | {
45 | "login": "andysousa",
46 | "name": "Andy Sousa",
47 | "avatar_url": "https://avatars0.githubusercontent.com/u/42151009?v=4",
48 | "profile": "https://github.com/andysousa",
49 | "contributions": [
50 | "code"
51 | ]
52 | },
53 | {
54 | "login": "thomasvidas",
55 | "name": "Thomas Vidas",
56 | "avatar_url": "https://avatars.githubusercontent.com/u/8182078?v=4",
57 | "profile": "https://github.com/thomasvidas",
58 | "contributions": [
59 | "code",
60 | "maintenance"
61 | ]
62 | },
63 | {
64 | "login": "emily-curry",
65 | "name": "Emily Curry",
66 | "avatar_url": "https://avatars.githubusercontent.com/u/20479454?v=4",
67 | "profile": "https://github.com/emily-curry",
68 | "contributions": [
69 | "code"
70 | ]
71 | },
72 | {
73 | "login": "graefenhain",
74 | "name": "graefenhain",
75 | "avatar_url": "https://avatars.githubusercontent.com/u/88032701?v=4",
76 | "profile": "https://github.com/graefenhain",
77 | "contributions": [
78 | "code"
79 | ]
80 | },
81 | {
82 | "login": "asztal",
83 | "name": "Lee Houghton",
84 | "avatar_url": "https://avatars.githubusercontent.com/u/68302?v=4",
85 | "profile": "https://github.com/asztal",
86 | "contributions": [
87 | "bug"
88 | ]
89 | },
90 | {
91 | "login": "FelixSchwarzmeier",
92 | "name": "Felix Schwarzmeier",
93 | "avatar_url": "https://avatars.githubusercontent.com/u/23665008?v=4",
94 | "profile": "https://github.com/FelixSchwarzmeier",
95 | "contributions": [
96 | "code"
97 | ]
98 | },
99 | {
100 | "login": "jkbz64",
101 | "name": "Kamil Jakubus",
102 | "avatar_url": "https://avatars.githubusercontent.com/u/13223538?v=4",
103 | "profile": "https://github.com/jkbz64",
104 | "contributions": [
105 | "code"
106 | ]
107 | },
108 | {
109 | "login": "joeflateau",
110 | "name": "Joe Flateau",
111 | "avatar_url": "https://avatars.githubusercontent.com/u/643331?v=4",
112 | "profile": "http://joeflateau.net/",
113 | "contributions": [
114 | "bug"
115 | ]
116 | },
117 | {
118 | "login": "Frank608",
119 | "name": "Frank608",
120 | "avatar_url": "https://avatars.githubusercontent.com/u/56638143?v=4",
121 | "profile": "https://github.com/Frank608",
122 | "contributions": [
123 | "bug"
124 | ]
125 | },
126 | {
127 | "login": "JoelNietoTec",
128 | "name": "Joel Nieto",
129 | "avatar_url": "https://avatars.githubusercontent.com/u/6298693?v=4",
130 | "profile": "https://github.com/JoelNietoTec",
131 | "contributions": [
132 | "bug"
133 | ]
134 | },
135 | {
136 | "login": "ultimate-tester",
137 | "name": "ultimate-tester",
138 | "avatar_url": "https://avatars.githubusercontent.com/u/580758?v=4",
139 | "profile": "https://github.com/ultimate-tester",
140 | "contributions": [
141 | "code"
142 | ]
143 | },
144 | {
145 | "login": "sgzadrian",
146 | "name": "Adrian Sanchez",
147 | "avatar_url": "https://avatars.githubusercontent.com/u/12704905?v=4",
148 | "profile": "https://github.com/sgzadrian",
149 | "contributions": [
150 | "bug"
151 | ]
152 | },
153 | {
154 | "login": "milanc",
155 | "name": "milanc",
156 | "avatar_url": "https://avatars.githubusercontent.com/u/8333458?v=4",
157 | "profile": "https://github.com/milanc",
158 | "contributions": [
159 | "code"
160 | ]
161 | },
162 | {
163 | "login": "herecoulbeyourname",
164 | "name": "herecoulbeyourname",
165 | "avatar_url": "https://avatars.githubusercontent.com/u/57253976?v=4",
166 | "profile": "https://github.com/herecoulbeyourname",
167 | "contributions": [
168 | "code"
169 | ]
170 | },
171 | {
172 | "login": "Landschaft",
173 | "name": "Landschaft",
174 | "avatar_url": "https://avatars.githubusercontent.com/u/10559398?v=4",
175 | "profile": "https://github.com/Landschaft",
176 | "contributions": [
177 | "code"
178 | ]
179 | },
180 | {
181 | "login": "stonewoodman",
182 | "name": "stonewoodman",
183 | "avatar_url": "https://avatars.githubusercontent.com/u/2945329?v=4",
184 | "profile": "https://github.com/stonewoodman",
185 | "contributions": [
186 | "bug"
187 | ]
188 | },
189 | {
190 | "login": "mghcs87",
191 | "name": "Héctor Cruz",
192 | "avatar_url": "https://avatars.githubusercontent.com/u/17180632?v=4",
193 | "profile": "https://github.com/mghcs87",
194 | "contributions": [
195 | "bug"
196 | ]
197 | },
198 | {
199 | "login": "patrickbussmann",
200 | "name": "Patrick Bußmann",
201 | "avatar_url": "https://avatars.githubusercontent.com/u/15617021?v=4",
202 | "profile": "https://github.com/patrickbussmann",
203 | "contributions": [
204 | "code"
205 | ]
206 | },
207 | {
208 | "login": "jesperbjerke",
209 | "name": "Jesper Bjerke",
210 | "avatar_url": "https://avatars.githubusercontent.com/u/5323483?v=4",
211 | "profile": "https://github.com/jesperbjerke",
212 | "contributions": [
213 | "bug"
214 | ]
215 | }
216 | ],
217 | "badgeTemplate": "
-orange?style=flat-square\" />",
218 | "contributorsPerLine": 7,
219 | "projectName": "http",
220 | "projectOwner": "capacitor-community",
221 | "repoType": "github",
222 | "repoHost": "https://github.com",
223 | "skipCi": true,
224 | "commitConvention": "none"
225 | }
226 |
--------------------------------------------------------------------------------
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | * mlynch
2 |
--------------------------------------------------------------------------------
/.github/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | Contributor Code of Conduct
2 |
3 | As contributors and maintainers of this Capacitor Community project, we pledge to respect everyone who contributes by posting issues, updating documentation, submitting pull requests, providing feedback in comments, and any other activities.
4 |
5 | Communication through this repository must be constructive and never resort to personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
6 |
7 | We promise to extend courtesy and respect to everyone involved in this project regardless of gender, gender identity, sexual orientation, disability, age, race, ethnicity, religion, or level of experience. We expect anyone contributing to this Capacitor Community project to do the same.
8 |
9 | If any member of the community violates this code of conduct, the maintainers of this Capacitor Community and/or the Ionic project may take action, including but not limited to removing issues, comments, and PRs or blocking accounts as deemed appropriate.
10 |
11 | If you are subject to or witness unacceptable behavior, or have any other concerns, please contact the maintainer of this repository or email hi@ionicframework.com.
12 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **To Reproduce**
14 | Steps to reproduce the behavior:
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 |
20 | **Expected behavior**
21 | A clear and concise description of what you expected to happen.
22 |
23 | **Screenshots**
24 | If applicable, add screenshots to help explain your problem.
25 |
26 | **Desktop (please complete the following information):**
27 | - OS: [e.g. iOS]
28 | - Browser [e.g. chrome, safari]
29 | - Version [e.g. 22]
30 |
31 | **Smartphone (please complete the following information):**
32 | - Device: [e.g. iPhone6]
33 | - OS: [e.g. iOS8.1]
34 | - Browser [e.g. stock browser, safari]
35 | - Version [e.g. 22]
36 |
37 | **Additional context**
38 | Add any other context about the problem here.
39 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
19 | **Additional context**
20 | Add any other context or screenshots about the feature request here.
21 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: Test and Build Plugin
2 |
3 | on:
4 | push:
5 | branches: [master, develop]
6 | pull_request:
7 | branches: [master]
8 |
9 | jobs:
10 | build:
11 | runs-on: ubuntu-latest
12 |
13 | steps:
14 | - uses: actions/checkout@v2
15 |
16 | - name: Install yarn
17 | uses: actions/setup-node@v1
18 | with:
19 | node-version: '14'
20 |
21 | - name: Install deps
22 | run: yarn install
23 |
24 | # - name: Run tests
25 | # run: yarn test
26 |
27 | - name: Run build
28 | run: yarn build
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # ==============
2 | # Android ignore
3 | # ==============
4 |
5 | # Built application files
6 | *.apk
7 | *.aar
8 | *.ap_
9 | *.aab
10 |
11 | # Files for the ART/Dalvik VM
12 | *.dex
13 |
14 | # Java class files
15 | *.class
16 |
17 | # Generated files
18 | bin/
19 | gen/
20 | out/
21 | # Uncomment the following line in case you need and you don't have the release build type files in your app
22 | # release/
23 |
24 | # Gradle files
25 | .gradle/
26 | build/
27 |
28 | # Local configuration file (sdk path, etc)
29 | local.properties
30 |
31 | # Proguard folder generated by Eclipse
32 | proguard/
33 |
34 | # Log Files
35 | *.log
36 |
37 | # Android Studio Navigation editor temp files
38 | .navigation/
39 |
40 | # Android Studio captures folder
41 | captures/
42 |
43 | # IntelliJ
44 | *.iml
45 | android/.idea/workspace.xml
46 | android/.idea/tasks.xml
47 | android/.idea/gradle.xml
48 | android/.idea/assetWizardSettings.xml
49 | android/.idea/dictionaries
50 | android/.idea/libraries
51 | android/.idea/jarRepositories.xml
52 | # Android Studio 3 in .gitignore file.
53 | android/.idea/caches
54 | android/.idea/modules.xml
55 | # Comment next line if keeping position of elements in Navigation Editor is relevant for you
56 | android/.idea/navEditor.xml
57 |
58 | # Keystore files
59 | # Uncomment the following lines if you do not want to check your keystore files in.
60 | #*.jks
61 | #*.keystore
62 |
63 | # External native build folder generated in Android Studio 2.2 and later
64 | .externalNativeBuild
65 | .cxx/
66 |
67 | # Google Services (e.g. APIs or Firebase)
68 | # google-services.json
69 |
70 | # Freeline
71 | freeline.py
72 | freeline/
73 | freeline_project_description.json
74 |
75 | # fastlane
76 | fastlane/report.xml
77 | fastlane/Preview.html
78 | fastlane/screenshots
79 | fastlane/test_output
80 | fastlane/readme.md
81 |
82 | # Version control
83 | vcs.xml
84 |
85 | # lint
86 | lint/intermediates/
87 | lint/generated/
88 | lint/outputs/
89 | lint/tmp/
90 | # lint/reports/
91 |
92 | # Android Profiling
93 | *.hprof
94 |
95 | # ==========
96 | # iOS ignore
97 | # ==========
98 | # Xcode
99 | #
100 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
101 |
102 | ## User settings
103 | xcuserdata/
104 |
105 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9)
106 | *.xcscmblueprint
107 | *.xccheckout
108 |
109 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4)
110 | build/
111 | DerivedData/
112 | *.moved-aside
113 | *.pbxuser
114 | !default.pbxuser
115 | *.mode1v3
116 | !default.mode1v3
117 | *.mode2v3
118 | !default.mode2v3
119 | *.perspectivev3
120 | !default.perspectivev3
121 |
122 | ## Obj-C/Swift specific
123 | *.hmap
124 |
125 | ## App packaging
126 | *.ipa
127 | *.dSYM.zip
128 | *.dSYM
129 |
130 | ## Playgrounds
131 | timeline.xctimeline
132 | playground.xcworkspace
133 |
134 | # Swift Package Manager
135 | #
136 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
137 | # Packages/
138 | # Package.pins
139 | # Package.resolved
140 | # *.xcodeproj
141 | #
142 | # Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata
143 | # hence it is not needed unless you have added a package configuration file to your project
144 | # .swiftpm
145 |
146 | .build/
147 |
148 | # CocoaPods
149 | #
150 | # We recommend against adding the Pods directory to your .gitignore. However
151 | # you should judge for yourself, the pros and cons are mentioned at:
152 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
153 | #
154 | Pods/
155 | #
156 | # Add this line if you want to avoid checking in source code from the Xcode workspace
157 | # *.xcworkspace
158 |
159 | # Carthage
160 | #
161 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
162 | # Carthage/Checkouts
163 |
164 | Carthage/Build/
165 |
166 | # Accio dependency management
167 | Dependencies/
168 | .accio/
169 |
170 | # fastlane
171 | #
172 | # It is recommended to not store the screenshots in the git repo.
173 | # Instead, use fastlane to re-generate the screenshots whenever they are needed.
174 | # For more information about the recommended setup visit:
175 | # https://docs.fastlane.tools/best-practices/source-control/#source-control
176 |
177 | fastlane/report.xml
178 | fastlane/Preview.html
179 | fastlane/screenshots/**/*.png
180 | fastlane/test_output
181 |
182 | # Code Injection
183 | #
184 | # After new code Injection tools there's a generated folder /iOSInjectionProject
185 | # https://github.com/johnno1962/injectionforxcode
186 |
187 | iOSInjectionProject/
188 |
189 | # ==========
190 | # Web ignore
191 | # ==========
192 | node_modules
193 | dist
194 |
195 | # ==============
196 | # Example ignore
197 | # ==============
198 | example/ios/App/App/public
199 | example/ios/capacitor-cordova-ios-plugins
200 |
--------------------------------------------------------------------------------
/.husky/.gitignore:
--------------------------------------------------------------------------------
1 | _
2 |
--------------------------------------------------------------------------------
/.husky/pre-commit:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | . "$(dirname "$0")/_/husky.sh"
3 |
4 | npx pretty-quick --staged
5 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | # node files
2 | dist/
3 | node_modules/
4 |
5 | # iOS files
6 | Pods
7 | Build
8 | xcuserdata
9 |
10 | # macOS files
11 | .DS_Store
12 |
13 | # Based on Android gitignore template: https://github.com/github/gitignore/blob/master/Android.gitignore
14 |
15 | # Built application files
16 | *.apk
17 | *.ap_
18 |
19 | # Files for the ART/Dalvik VM
20 | *.dex
21 |
22 | # Java class files
23 | *.class
24 |
25 | # Generated files
26 | bin/
27 | gen/
28 | out/
29 |
30 | # Gradle files
31 | .gradle/
32 | build/
33 |
34 | # Local configuration file (sdk path, etc)
35 | local.properties
36 |
37 | # Proguard folder generated by Eclipse
38 | proguard/
39 |
40 | # Log Files
41 | *.log
42 |
43 | # Android Studio Navigation editor temp files
44 | .navigation/
45 |
46 | # Android Studio captures folder
47 | captures/
48 |
49 | # IntelliJ
50 | *.iml
51 | .idea
52 |
53 | # Keystore files
54 | # Uncomment the following line if you do not want to check your keystore files in.
55 | #*.jks
56 |
57 | # External native build folder generated in Android Studio 2.2 and later
58 | .externalNativeBuild
59 |
--------------------------------------------------------------------------------
/CapacitorCommunityHttp.podspec:
--------------------------------------------------------------------------------
1 | require 'json'
2 |
3 | package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
4 |
5 | Pod::Spec.new do |s|
6 | s.name = 'CapacitorCommunityHttp'
7 | s.version = package['version']
8 | s.summary = package['description']
9 | s.license = package['license']
10 | s.homepage = package['repository']['url']
11 | s.author = package['author']
12 | s.source = { git: package['repository']['url'], tag: s.version.to_s }
13 | s.source_files = 'ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}'
14 | s.ios.deployment_target = '12.0'
15 | s.dependency 'Capacitor'
16 | s.swift_version = '5.1'
17 | end
18 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Drifty Co.
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 |
--------------------------------------------------------------------------------
/android/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/android/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/android/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
10 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | ext {
2 | junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.12'
3 | androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.1.1'
4 | androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.2.0'
5 | }
6 |
7 | buildscript {
8 | repositories {
9 | google()
10 | jcenter()
11 | }
12 | dependencies {
13 | classpath 'com.android.tools.build:gradle:3.6.1'
14 | }
15 | }
16 |
17 | apply plugin: 'com.android.library'
18 |
19 | android {
20 | compileSdkVersion project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 29
21 | defaultConfig {
22 | minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 21
23 | targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 29
24 | versionCode 1
25 | versionName "1.0"
26 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
27 | }
28 | buildTypes {
29 | release {
30 | minifyEnabled false
31 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
32 | }
33 | }
34 | lintOptions {
35 | abortOnError false
36 | }
37 | }
38 |
39 | repositories {
40 | google()
41 | jcenter()
42 | mavenCentral()
43 | }
44 |
45 |
46 | dependencies {
47 | implementation fileTree(dir: 'libs', include: ['*.jar'])
48 | implementation project(':capacitor-android')
49 | testImplementation "junit:junit:$junitVersion"
50 | androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion"
51 | androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion"
52 | }
53 |
--------------------------------------------------------------------------------
/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 | org.gradle.jvmargs=-Xmx1536m
13 |
14 | # When configured, Gradle will run in incubating parallel mode.
15 | # This option should only be used with decoupled projects. More details, visit
16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
17 | # org.gradle.parallel=true
18 |
19 | # Supports AndroidX
20 | android.useAndroidX=true
21 | android.enableJetifier=true
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/capacitor-community/http/27dc4c858f1eb742622bc71c590f8aa351ef8221/android/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Dec 01 12:41:00 CST 2017
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip
7 |
--------------------------------------------------------------------------------
/android/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/android/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/android/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/android/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':capacitor-android'
2 | project(':capacitor-android').projectDir = new File('../node_modules/@capacitor/android/capacitor')
--------------------------------------------------------------------------------
/android/src/androidTest/java/com/getcapacitor/android/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.getcapacitor.android;
2 |
3 | import static org.junit.Assert.*;
4 |
5 | import android.content.Context;
6 | import androidx.test.ext.junit.runners.AndroidJUnit4;
7 | import androidx.test.platform.app.InstrumentationRegistry;
8 | import org.junit.Test;
9 | import org.junit.runner.RunWith;
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * @see Testing documentation
15 | */
16 | @RunWith(AndroidJUnit4.class)
17 | public class ExampleInstrumentedTest {
18 |
19 | @Test
20 | public void useAppContext() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
23 |
24 | assertEquals("com.getcapacitor.android", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/android/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
--------------------------------------------------------------------------------
/android/src/main/java/com/getcapacitor/plugin/http/FilesystemUtils.java:
--------------------------------------------------------------------------------
1 | package com.getcapacitor.plugin.http;
2 |
3 | import android.content.Context;
4 | import android.net.Uri;
5 | import android.os.Environment;
6 | import java.io.File;
7 |
8 | public class FilesystemUtils {
9 |
10 | public static final String DIRECTORY_DOCUMENTS = "DOCUMENTS";
11 | public static final String DIRECTORY_APPLICATION = "APPLICATION";
12 | public static final String DIRECTORY_DOWNLOADS = "DOWNLOADS";
13 | public static final String DIRECTORY_DATA = "DATA";
14 | public static final String DIRECTORY_CACHE = "CACHE";
15 | public static final String DIRECTORY_EXTERNAL = "EXTERNAL";
16 | public static final String DIRECTORY_EXTERNAL_STORAGE = "EXTERNAL_STORAGE";
17 |
18 | public static File getFileObject(Context c, String path, String directory) {
19 | if (directory == null || path.startsWith("file://")) {
20 | Uri u = Uri.parse(path);
21 | if (u.getScheme() == null || u.getScheme().equals("file")) {
22 | return new File(u.getPath());
23 | }
24 | }
25 |
26 | File androidDirectory = FilesystemUtils.getDirectory(c, directory);
27 |
28 | if (androidDirectory == null) {
29 | return null;
30 | } else {
31 | if (!androidDirectory.exists()) {
32 | androidDirectory.mkdir();
33 | }
34 | }
35 |
36 | return new File(androidDirectory, path);
37 | }
38 |
39 | public static File getDirectory(Context c, String directory) {
40 | switch (directory) {
41 | case DIRECTORY_APPLICATION:
42 | case DIRECTORY_DATA:
43 | return c.getFilesDir();
44 | case DIRECTORY_DOCUMENTS:
45 | return Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS);
46 | case DIRECTORY_DOWNLOADS:
47 | return Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
48 | case DIRECTORY_CACHE:
49 | return c.getCacheDir();
50 | case DIRECTORY_EXTERNAL:
51 | return c.getExternalFilesDir(null);
52 | case DIRECTORY_EXTERNAL_STORAGE:
53 | return Environment.getExternalStorageDirectory();
54 | }
55 | return null;
56 | }
57 |
58 | /**
59 | * True if the given directory string is a public storage directory, which is accessible by the user or other apps.
60 | * @param directory the directory string.
61 | */
62 | public static boolean isPublicDirectory(String directory) {
63 | return (DIRECTORY_DOCUMENTS.equals(directory) || DIRECTORY_DOWNLOADS.equals(directory) || "EXTERNAL_STORAGE".equals(directory));
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/android/src/main/java/com/getcapacitor/plugin/http/FormUploader.java:
--------------------------------------------------------------------------------
1 | package com.getcapacitor.plugin.http;
2 |
3 | import com.getcapacitor.JSObject;
4 | import java.io.File;
5 | import java.io.FileInputStream;
6 | import java.io.IOException;
7 | import java.io.OutputStream;
8 | import java.io.OutputStreamWriter;
9 | import java.io.PrintWriter;
10 | import java.net.HttpURLConnection;
11 | import java.net.URLConnection;
12 | import java.util.Iterator;
13 | import java.util.UUID;
14 | import org.json.JSONException;
15 |
16 | public class FormUploader {
17 |
18 | private final String LINE_FEED = "\r\n";
19 | private final String boundary;
20 | private final String charset = "UTF-8";
21 | private final OutputStream outputStream;
22 | private final PrintWriter prWriter;
23 |
24 | /**
25 | * This constructor initializes a new HTTP POST request with content type
26 | * is set to multipart/form-data
27 | * @param connection The HttpUrlConnection to use to upload a Form
28 | * @throws IOException Thrown if unable to parse the OutputStream of the connection
29 | */
30 | public FormUploader(HttpURLConnection connection) throws IOException {
31 | UUID uuid = UUID.randomUUID();
32 | boundary = uuid.toString();
33 |
34 | connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
35 |
36 | outputStream = connection.getOutputStream();
37 | prWriter = new PrintWriter(new OutputStreamWriter(outputStream, charset), true);
38 | }
39 |
40 | /**
41 | * Adds a form field to the request
42 | *
43 | * @param name field name
44 | * @param value field value
45 | */
46 | public void addFormField(String name, String value) {
47 | prWriter
48 | .append(LINE_FEED)
49 | .append("--")
50 | .append(boundary)
51 | .append(LINE_FEED)
52 | .append("Content-Disposition: form-data; name=\"")
53 | .append(name)
54 | .append("\"")
55 | .append(LINE_FEED)
56 | .append("Content-Type: text/plain; charset=")
57 | .append(charset)
58 | .append(LINE_FEED)
59 | .append(LINE_FEED)
60 | .append(value)
61 | .append(LINE_FEED)
62 | .append("--")
63 | .append(boundary)
64 | .append("--")
65 | .append(LINE_FEED);
66 | prWriter.flush();
67 | }
68 |
69 | /**
70 | * Adds a form field to the prWriter
71 | *
72 | * @param name field name
73 | * @param value field value
74 | */
75 | private void appendFieldToWriter(String name, String value) {
76 | prWriter
77 | .append(LINE_FEED)
78 | .append("--")
79 | .append(boundary)
80 | .append(LINE_FEED)
81 | .append("Content-Disposition: form-data; name=\"")
82 | .append(name)
83 | .append("\"")
84 | .append(LINE_FEED)
85 | .append("Content-Type: text/plain; charset=")
86 | .append(charset)
87 | .append(LINE_FEED)
88 | .append(LINE_FEED)
89 | .append(value);
90 | }
91 |
92 | /**
93 | * Adds a upload file section to the request
94 | *
95 | * @param fieldName name attribute in
96 | * @param uploadFile a File to be uploaded
97 | * @throws IOException Thrown if unable to parse the OutputStream of the connection
98 | */
99 | public void addFilePart(String fieldName, File uploadFile, JSObject data) throws IOException {
100 | String fileName = uploadFile.getName();
101 | prWriter
102 | .append(LINE_FEED)
103 | .append("--")
104 | .append(boundary)
105 | .append(LINE_FEED)
106 | .append("Content-Disposition: form-data; name=\"")
107 | .append(fieldName)
108 | .append("\"; filename=\"")
109 | .append(fileName)
110 | .append("\"")
111 | .append(LINE_FEED)
112 | .append("Content-Type: ")
113 | .append(URLConnection.guessContentTypeFromName(fileName))
114 | .append(LINE_FEED)
115 | .append(LINE_FEED);
116 | prWriter.flush();
117 |
118 | FileInputStream inputStream = new FileInputStream(uploadFile);
119 | byte[] buffer = new byte[4096];
120 | int bytesRead;
121 | while ((bytesRead = inputStream.read(buffer)) != -1) {
122 | outputStream.write(buffer, 0, bytesRead);
123 | }
124 | outputStream.flush();
125 | inputStream.close();
126 |
127 | if (data != null) {
128 | Iterator keyIterator = data.keys();
129 | while (keyIterator.hasNext()) {
130 | String key = keyIterator.next();
131 | try {
132 | Object value = data.get(key);
133 |
134 | if (!(value instanceof String)) continue;
135 |
136 | appendFieldToWriter(key, value.toString());
137 | } catch (JSONException e) {
138 | e.printStackTrace();
139 | }
140 | }
141 | }
142 |
143 | prWriter.append(LINE_FEED).append("--").append(boundary).append("--").append(LINE_FEED);
144 | prWriter.flush();
145 | }
146 |
147 | /**
148 | * Adds a header field to the request.
149 | *
150 | * @param name - name of the header field
151 | * @param value - value of the header field
152 | */
153 | public void addHeaderField(String name, String value) {
154 | prWriter.append(name).append(": ").append(value).append(LINE_FEED);
155 | prWriter.flush();
156 | }
157 |
158 | /**
159 | * Completes the request and receives response from the server.
160 | * returns a list of Strings as response in case the server returned
161 | * status OK, otherwise an exception is thrown.
162 | */
163 | public void finish() {
164 | prWriter.append(LINE_FEED);
165 | prWriter.flush();
166 | prWriter.append("--").append(boundary).append("--").append(LINE_FEED);
167 | prWriter.close();
168 | }
169 | }
170 |
--------------------------------------------------------------------------------
/android/src/main/java/com/getcapacitor/plugin/http/ICapacitorHttpUrlConnection.java:
--------------------------------------------------------------------------------
1 | package com.getcapacitor.plugin.http;
2 |
3 | import java.io.IOException;
4 | import java.io.InputStream;
5 |
6 | /**
7 | * This interface was extracted from {@link CapacitorHttpUrlConnection} to enable mocking that class.
8 | */
9 | interface ICapacitorHttpUrlConnection {
10 | InputStream getErrorStream();
11 |
12 | String getHeaderField(String name);
13 |
14 | InputStream getInputStream() throws IOException;
15 | }
16 |
--------------------------------------------------------------------------------
/android/src/main/java/com/getcapacitor/plugin/http/JSValue.java:
--------------------------------------------------------------------------------
1 | package com.getcapacitor.plugin.http;
2 |
3 | import com.getcapacitor.JSArray;
4 | import com.getcapacitor.JSObject;
5 | import com.getcapacitor.PluginCall;
6 | import org.json.JSONException;
7 |
8 | /**
9 | * Represents a single user-data value of any type on the capacitor PluginCall object.
10 | */
11 | public class JSValue {
12 |
13 | private final Object value;
14 |
15 | /**
16 | * @param call The capacitor plugin call, used for accessing the value safely.
17 | * @param name The name of the property to access.
18 | */
19 | public JSValue(PluginCall call, String name) {
20 | this.value = this.toValue(call, name);
21 | }
22 |
23 | /**
24 | * Returns the coerced but uncasted underlying value.
25 | */
26 | public Object getValue() {
27 | return this.value;
28 | }
29 |
30 | @Override
31 | public String toString() {
32 | return this.getValue().toString();
33 | }
34 |
35 | /**
36 | * Returns the underlying value as a JSObject, or throwing if it cannot.
37 | *
38 | * @throws JSONException If the underlying value is not a JSObject.
39 | */
40 | public JSObject toJSObject() throws JSONException {
41 | if (this.value instanceof JSObject) return (JSObject) this.value;
42 | throw new JSONException("JSValue could not be coerced to JSObject.");
43 | }
44 |
45 | /**
46 | * Returns the underlying value as a JSArray, or throwing if it cannot.
47 | *
48 | * @throws JSONException If the underlying value is not a JSArray.
49 | */
50 | public JSArray toJSArray() throws JSONException {
51 | if (this.value instanceof JSArray) return (JSArray) this.value;
52 | throw new JSONException("JSValue could not be coerced to JSArray.");
53 | }
54 |
55 | /**
56 | * Returns the underlying value this object represents, coercing it into a capacitor-friendly object if supported.
57 | */
58 | private Object toValue(PluginCall call, String name) {
59 | Object value = null;
60 | value = call.getArray(name, null);
61 | if (value != null) return value;
62 | value = call.getObject(name, null);
63 | if (value != null) return value;
64 | value = call.getString(name, null);
65 | if (value != null) return value;
66 | return call.getData().opt(name);
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/android/src/main/java/com/getcapacitor/plugin/http/MimeType.java:
--------------------------------------------------------------------------------
1 | package com.getcapacitor.plugin.http;
2 |
3 | enum MimeType {
4 | APPLICATION_JSON("application/json"),
5 | APPLICATION_VND_API_JSON("application/vnd.api+json"), // https://jsonapi.org
6 | TEXT_HTML("text/html");
7 |
8 | private final String value;
9 |
10 | MimeType(String value) {
11 | this.value = value;
12 | }
13 |
14 | String getValue() {
15 | return value;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/android/src/main/res/layout/bridge_layout_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/android/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/android/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Just a simple string
3 |
4 |
--------------------------------------------------------------------------------
/android/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/android/src/test/java/com/getcapacitor/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.getcapacitor;
2 |
3 | import static org.junit.Assert.*;
4 |
5 | import org.junit.Test;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 |
14 | @Test
15 | public void addition_isCorrect() throws Exception {
16 | assertEquals(4, 2 + 2);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/android/src/test/java/com/getcapacitor/plugin/http/HttpRequestHandlerTest.java:
--------------------------------------------------------------------------------
1 | package com.getcapacitor.plugin.http;
2 |
3 | import static com.getcapacitor.plugin.http.HttpRequestHandler.ResponseType.JSON;
4 | import static java.nio.charset.StandardCharsets.UTF_8;
5 | import static org.junit.Assert.assertEquals;
6 |
7 | import android.util.MutableBoolean;
8 | import com.getcapacitor.JSObject;
9 | import java.io.ByteArrayInputStream;
10 | import java.io.IOException;
11 | import java.io.InputStream;
12 | import java.util.HashMap;
13 | import java.util.Map;
14 | import org.json.JSONException;
15 | import org.json.JSONObject;
16 | import org.junit.Test;
17 |
18 | public class HttpRequestHandlerTest {
19 |
20 | @Test
21 | public void readData_error_with_HTML_message() throws IOException, JSONException {
22 | MutableBoolean isError = new MutableBoolean(false);
23 | String result = (String) HttpRequestHandler.readData(errorWithHtmlMessage("html-error"), JSON);
24 |
25 | assertEquals("html-error", result);
26 | }
27 |
28 | @Test
29 | public void readData_error_with_JSON() throws IOException, JSONException {
30 | JSObject jsonObject = new JSObject("{ 'message' : 'Hello world!' }");
31 |
32 | JSObject result = (JSObject) HttpRequestHandler.readData(errorWithJson(jsonObject), JSON);
33 |
34 | assertEquals(jsonObject.toString(), result.toString());
35 | }
36 |
37 | @Test
38 | public void readData_success_with_JSON() throws IOException, JSONException {
39 | JSObject jsonObject = new JSObject("{ 'message' : 'Hello world!' }");
40 |
41 | JSObject result = (JSObject) HttpRequestHandler.readData(successWithJson(jsonObject), JSON);
42 |
43 | assertEquals(jsonObject.toString(), result.toString());
44 | }
45 |
46 | @SuppressWarnings("SameParameterValue")
47 | private static CapacitorHttpUrlResponseMock errorWithHtmlMessage(String htmlErrorMessage) {
48 | return new CapacitorHttpUrlResponseMock(
49 | null,
50 | new ByteArrayInputStream(htmlErrorMessage.getBytes(UTF_8)),
51 | MimeType.TEXT_HTML.getValue()
52 | );
53 | }
54 |
55 | private static CapacitorHttpUrlResponseMock errorWithJson(JSONObject jsonObject) {
56 | return new CapacitorHttpUrlResponseMock(
57 | null,
58 | new ByteArrayInputStream(jsonObject.toString().getBytes(UTF_8)),
59 | MimeType.APPLICATION_VND_API_JSON.getValue()
60 | );
61 | }
62 |
63 | private static CapacitorHttpUrlResponseMock successWithJson(JSONObject jsonObject) {
64 | return new CapacitorHttpUrlResponseMock(new ByteArrayInputStream(jsonObject.toString().getBytes(UTF_8)), null, null);
65 | }
66 |
67 | private static class CapacitorHttpUrlResponseMock implements ICapacitorHttpUrlConnection {
68 |
69 | private final InputStream inputStream;
70 | private final InputStream errorStream;
71 | private final Map headerFields = new HashMap<>();
72 |
73 | CapacitorHttpUrlResponseMock(InputStream inputStream, InputStream errorStream, String contentType) {
74 | this.inputStream = inputStream;
75 | this.errorStream = errorStream;
76 | if (contentType != null) {
77 | this.headerFields.put("Content-Type", contentType);
78 | }
79 | }
80 |
81 | @Override
82 | public InputStream getInputStream() {
83 | return inputStream;
84 | }
85 |
86 | @Override
87 | public InputStream getErrorStream() {
88 | return errorStream;
89 | }
90 |
91 | @Override
92 | public String getHeaderField(String name) {
93 | return headerFields.get(name);
94 | }
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/example/.editorconfig:
--------------------------------------------------------------------------------
1 | # http://editorconfig.org
2 |
3 | root = true
4 |
5 | [*]
6 | charset = utf-8
7 | indent_style = space
8 | indent_size = 2
9 | end_of_line = lf
10 | insert_final_newline = true
11 | trim_trailing_whitespace = true
12 |
13 | [*.md]
14 | insert_final_newline = false
15 | trim_trailing_whitespace = false
16 |
--------------------------------------------------------------------------------
/example/.gitignore:
--------------------------------------------------------------------------------
1 | dist/
2 | !www/favicon.ico
3 | www/
4 |
5 | *~
6 | *.sw[mnpcod]
7 | *.log
8 | *.lock
9 | *.tmp
10 | *.tmp.*
11 | log.txt
12 | *.sublime-project
13 | *.sublime-workspace
14 |
15 | .stencil/
16 | .idea/
17 | .vscode/
18 | .sass-cache/
19 | .versions/
20 | node_modules/
21 | $RECYCLE.BIN/
22 |
23 | .DS_Store
24 | Thumbs.db
25 | UserInterfaceState.xcuserstate
26 | .env
27 |
28 | # Server Uploads/Downloads TODO: fix example to not use fixed path
29 | server/document.pdf
30 | server/uploads/*
31 |
--------------------------------------------------------------------------------
/example/.prettierrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "arrowParens": "avoid",
3 | "bracketSpacing": true,
4 | "jsxBracketSameLine": false,
5 | "jsxSingleQuote": false,
6 | "quoteProps": "consistent",
7 | "printWidth": 180,
8 | "semi": true,
9 | "singleQuote": true,
10 | "tabWidth": 2,
11 | "trailingComma": "all",
12 | "useTabs": false
13 | }
14 |
--------------------------------------------------------------------------------
/example/android/.gitignore:
--------------------------------------------------------------------------------
1 | # NPM renames .gitignore to .npmignore
2 | # In order to prevent that, we remove the initial "."
3 | # And the CLI then renames it
4 |
5 | # Using Android gitignore template: https://github.com/github/gitignore/blob/master/Android.gitignore
6 |
7 | # Built application files
8 | *.apk
9 | *.ap_
10 | *.aab
11 |
12 | # Files for the ART/Dalvik VM
13 | *.dex
14 |
15 | # Java class files
16 | *.class
17 |
18 | # Generated files
19 | bin/
20 | gen/
21 | out/
22 | release/
23 |
24 | # Gradle files
25 | .gradle/
26 | build/
27 |
28 | # Local configuration file (sdk path, etc)
29 | local.properties
30 |
31 | # Proguard folder generated by Eclipse
32 | proguard/
33 |
34 | # Log Files
35 | *.log
36 |
37 | # Android Studio Navigation editor temp files
38 | .navigation/
39 |
40 | # Android Studio captures folder
41 | captures/
42 |
43 | # IntelliJ
44 | *.iml
45 | .idea/workspace.xml
46 | .idea/tasks.xml
47 | .idea/gradle.xml
48 | .idea/assetWizardSettings.xml
49 | .idea/dictionaries
50 | .idea/libraries
51 | # Android Studio 3 in .gitignore file.
52 | .idea/caches
53 | .idea/modules.xml
54 | # Comment next line if keeping position of elements in Navigation Editor is relevant for you
55 | .idea/navEditor.xml
56 |
57 | # Keystore files
58 | # Uncomment the following lines if you do not want to check your keystore files in.
59 | #*.jks
60 | #*.keystore
61 |
62 | # External native build folder generated in Android Studio 2.2 and later
63 | .externalNativeBuild
64 |
65 | # Freeline
66 | freeline.py
67 | freeline/
68 | freeline_project_description.json
69 |
70 | # fastlane
71 | fastlane/report.xml
72 | fastlane/Preview.html
73 | fastlane/screenshots
74 | fastlane/test_output
75 | fastlane/readme.md
76 |
77 | # Version control
78 | vcs.xml
79 |
80 | # lint
81 | lint/intermediates/
82 | lint/generated/
83 | lint/outputs/
84 | lint/tmp/
85 | # lint/reports/
86 |
87 | # Cordova plugins for Capacitor
88 | capacitor-cordova-android-plugins
89 |
90 | # Copied web assets
91 | app/src/main/assets/public
92 |
--------------------------------------------------------------------------------
/example/android/app/.npmignore:
--------------------------------------------------------------------------------
1 | /build/*
2 | !/build/.npmkeep
3 |
--------------------------------------------------------------------------------
/example/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion rootProject.ext.compileSdkVersion
5 | defaultConfig {
6 | applicationId "com.example.app"
7 | minSdkVersion rootProject.ext.minSdkVersion
8 | targetSdkVersion rootProject.ext.targetSdkVersion
9 | versionCode 1
10 | versionName "1.0"
11 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
12 | }
13 | buildTypes {
14 | release {
15 | minifyEnabled false
16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
17 | }
18 | }
19 | }
20 |
21 | repositories {
22 | flatDir{
23 | dirs '../capacitor-cordova-android-plugins/src/main/libs', 'libs'
24 | }
25 | }
26 |
27 | dependencies {
28 | implementation fileTree(include: ['*.jar'], dir: 'libs')
29 | implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"
30 | implementation project(':capacitor-android')
31 | testImplementation "junit:junit:$junitVersion"
32 | androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion"
33 | androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion"
34 | implementation project(':capacitor-cordova-android-plugins')
35 | }
36 |
37 | apply from: 'capacitor.build.gradle'
38 |
39 | try {
40 | def servicesJSON = file('google-services.json')
41 | if (servicesJSON.text) {
42 | apply plugin: 'com.google.gms.google-services'
43 | }
44 | } catch(Exception e) {
45 | logger.warn("google-services.json not found, google-services plugin not applied. Push Notifications won't work")
46 | }
--------------------------------------------------------------------------------
/example/android/app/capacitor.build.gradle:
--------------------------------------------------------------------------------
1 | // DO NOT EDIT THIS FILE! IT IS GENERATED EACH TIME "capacitor update" IS RUN
2 |
3 | android {
4 | compileOptions {
5 | sourceCompatibility JavaVersion.VERSION_1_8
6 | targetCompatibility JavaVersion.VERSION_1_8
7 | }
8 | }
9 |
10 | apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle"
11 | dependencies {
12 | implementation project(':capacitor-community-http')
13 |
14 | }
15 |
16 |
17 | if (hasProperty('postBuildExtras')) {
18 | postBuildExtras()
19 | }
20 |
--------------------------------------------------------------------------------
/example/android/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/example/android/app/src/androidTest/java/com/getcapacitor/myapp/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.getcapacitor.myapp;
2 |
3 | import static org.junit.Assert.*;
4 |
5 | import android.content.Context;
6 | import androidx.test.ext.junit.runners.AndroidJUnit4;
7 | import androidx.test.platform.app.InstrumentationRegistry;
8 | import org.junit.Test;
9 | import org.junit.runner.RunWith;
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * @see Testing documentation
15 | */
16 | @RunWith(AndroidJUnit4.class)
17 | public class ExampleInstrumentedTest {
18 |
19 | @Test
20 | public void useAppContext() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
23 |
24 | assertEquals("com.getcapacitor.app", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/example/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
13 |
14 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
40 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/example/android/app/src/main/assets/capacitor.config.json:
--------------------------------------------------------------------------------
1 | {}
2 |
--------------------------------------------------------------------------------
/example/android/app/src/main/assets/capacitor.plugins.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "pkg": "@capacitor-community/http",
4 | "classpath": "com.getcapacitor.plugin.http.Http"
5 | }
6 | ]
7 |
--------------------------------------------------------------------------------
/example/android/app/src/main/java/com/example/app/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.example.app;
2 |
3 | import android.os.Bundle;
4 | import com.getcapacitor.BridgeActivity;
5 | import com.getcapacitor.plugin.http.Http;
6 |
7 | public class MainActivity extends BridgeActivity {
8 |
9 | @Override
10 | public void onCreate(Bundle savedInstanceState) {
11 | super.onCreate(savedInstanceState);
12 | registerPlugin(Http.class);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/drawable-land-hdpi/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/capacitor-community/http/27dc4c858f1eb742622bc71c590f8aa351ef8221/example/android/app/src/main/res/drawable-land-hdpi/splash.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/drawable-land-mdpi/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/capacitor-community/http/27dc4c858f1eb742622bc71c590f8aa351ef8221/example/android/app/src/main/res/drawable-land-mdpi/splash.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/drawable-land-xhdpi/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/capacitor-community/http/27dc4c858f1eb742622bc71c590f8aa351ef8221/example/android/app/src/main/res/drawable-land-xhdpi/splash.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/drawable-land-xxhdpi/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/capacitor-community/http/27dc4c858f1eb742622bc71c590f8aa351ef8221/example/android/app/src/main/res/drawable-land-xxhdpi/splash.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/drawable-land-xxxhdpi/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/capacitor-community/http/27dc4c858f1eb742622bc71c590f8aa351ef8221/example/android/app/src/main/res/drawable-land-xxxhdpi/splash.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/drawable-port-hdpi/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/capacitor-community/http/27dc4c858f1eb742622bc71c590f8aa351ef8221/example/android/app/src/main/res/drawable-port-hdpi/splash.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/drawable-port-mdpi/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/capacitor-community/http/27dc4c858f1eb742622bc71c590f8aa351ef8221/example/android/app/src/main/res/drawable-port-mdpi/splash.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/drawable-port-xhdpi/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/capacitor-community/http/27dc4c858f1eb742622bc71c590f8aa351ef8221/example/android/app/src/main/res/drawable-port-xhdpi/splash.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/drawable-port-xxhdpi/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/capacitor-community/http/27dc4c858f1eb742622bc71c590f8aa351ef8221/example/android/app/src/main/res/drawable-port-xxhdpi/splash.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/drawable-port-xxxhdpi/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/capacitor-community/http/27dc4c858f1eb742622bc71c590f8aa351ef8221/example/android/app/src/main/res/drawable-port-xxxhdpi/splash.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
12 |
13 |
19 |
22 |
25 |
26 |
27 |
28 |
34 |
35 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/drawable/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/capacitor-community/http/27dc4c858f1eb742622bc71c590f8aa351ef8221/example/android/app/src/main/res/drawable/splash.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
12 |
13 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/capacitor-community/http/27dc4c858f1eb742622bc71c590f8aa351ef8221/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/capacitor-community/http/27dc4c858f1eb742622bc71c590f8aa351ef8221/example/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/capacitor-community/http/27dc4c858f1eb742622bc71c590f8aa351ef8221/example/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/capacitor-community/http/27dc4c858f1eb742622bc71c590f8aa351ef8221/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/capacitor-community/http/27dc4c858f1eb742622bc71c590f8aa351ef8221/example/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/capacitor-community/http/27dc4c858f1eb742622bc71c590f8aa351ef8221/example/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/capacitor-community/http/27dc4c858f1eb742622bc71c590f8aa351ef8221/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/capacitor-community/http/27dc4c858f1eb742622bc71c590f8aa351ef8221/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/capacitor-community/http/27dc4c858f1eb742622bc71c590f8aa351ef8221/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/capacitor-community/http/27dc4c858f1eb742622bc71c590f8aa351ef8221/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/capacitor-community/http/27dc4c858f1eb742622bc71c590f8aa351ef8221/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/capacitor-community/http/27dc4c858f1eb742622bc71c590f8aa351ef8221/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/capacitor-community/http/27dc4c858f1eb742622bc71c590f8aa351ef8221/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/capacitor-community/http/27dc4c858f1eb742622bc71c590f8aa351ef8221/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/capacitor-community/http/27dc4c858f1eb742622bc71c590f8aa351ef8221/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/values/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFFFFF
4 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | example
4 | example
5 | com.example.app
6 | com.example.app
7 |
8 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
11 |
12 |
17 |
18 |
19 |
22 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/xml/config.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/xml/file_paths.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/example/android/app/src/test/java/com/getcapacitor/myapp/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.getcapacitor.myapp;
2 |
3 | import static org.junit.Assert.*;
4 |
5 | import org.junit.Test;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 |
14 | @Test
15 | public void addition_isCorrect() throws Exception {
16 | assertEquals(4, 2 + 2);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/example/android/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 |
5 | repositories {
6 | google()
7 | jcenter()
8 | }
9 | dependencies {
10 | classpath 'com.android.tools.build:gradle:3.6.1'
11 | classpath 'com.google.gms:google-services:4.3.3'
12 |
13 | // NOTE: Do not place your application dependencies here; they belong
14 | // in the individual module build.gradle files
15 | }
16 | }
17 |
18 | apply from: "variables.gradle"
19 |
20 | allprojects {
21 | repositories {
22 | google()
23 | jcenter()
24 | }
25 | }
26 |
27 | task clean(type: Delete) {
28 | delete rootProject.buildDir
29 | }
30 |
--------------------------------------------------------------------------------
/example/android/capacitor.settings.gradle:
--------------------------------------------------------------------------------
1 | // DO NOT EDIT THIS FILE! IT IS GENERATED EACH TIME "capacitor update" IS RUN
2 | include ':capacitor-android'
3 | project(':capacitor-android').projectDir = new File('../node_modules/@capacitor/android/capacitor')
4 |
5 | include ':capacitor-community-http'
6 | project(':capacitor-community-http').projectDir = new File('../../android')
7 |
--------------------------------------------------------------------------------
/example/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 | org.gradle.jvmargs=-Xmx1536m
13 |
14 | # When configured, Gradle will run in incubating parallel mode.
15 | # This option should only be used with decoupled projects. More details, visit
16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
17 | # org.gradle.parallel=true
18 |
19 | # Supports AndroidX
20 | android.useAndroidX=true
21 | android.enableJetifier=true
--------------------------------------------------------------------------------
/example/android/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/capacitor-community/http/27dc4c858f1eb742622bc71c590f8aa351ef8221/example/android/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/example/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Tue Jan 30 13:14:22 CST 2018
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip
7 |
--------------------------------------------------------------------------------
/example/android/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/example/android/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/example/android/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 | include ':capacitor-cordova-android-plugins'
3 | project(':capacitor-cordova-android-plugins').projectDir = new File('./capacitor-cordova-android-plugins/')
4 |
5 | apply from: 'capacitor.settings.gradle'
--------------------------------------------------------------------------------
/example/android/variables.gradle:
--------------------------------------------------------------------------------
1 | ext {
2 | minSdkVersion = 22
3 | compileSdkVersion = 30
4 | targetSdkVersion = 30
5 | androidxAppCompatVersion = '1.1.0'
6 | androidxCoreVersion = '1.2.0'
7 | androidxMaterialVersion = '1.1.0-rc02'
8 | androidxBrowserVersion = '1.2.0'
9 | androidxLocalbroadcastmanagerVersion = '1.0.0'
10 | firebaseMessagingVersion = '20.1.2'
11 | playServicesLocationVersion = '17.0.0'
12 | junitVersion = '4.12'
13 | androidxJunitVersion = '1.1.1'
14 | androidxEspressoCoreVersion = '3.2.0'
15 | cordovaAndroidVersion = '7.0.0'
16 | }
17 |
--------------------------------------------------------------------------------
/example/ios/App/App.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/example/ios/App/App.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/example/ios/App/App.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/example/ios/App/App/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import Capacitor
3 |
4 | @UIApplicationMain
5 | class AppDelegate: UIResponder, UIApplicationDelegate {
6 |
7 | var window: UIWindow?
8 |
9 |
10 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
11 | // Override point for customization after application launch.
12 | return true
13 | }
14 |
15 | func applicationWillResignActive(_ application: UIApplication) {
16 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
17 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
18 | }
19 |
20 | func applicationDidEnterBackground(_ application: UIApplication) {
21 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
22 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
23 | }
24 |
25 | func applicationWillEnterForeground(_ application: UIApplication) {
26 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
27 | }
28 |
29 | func applicationDidBecomeActive(_ application: UIApplication) {
30 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
31 | }
32 |
33 | func applicationWillTerminate(_ application: UIApplication) {
34 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
35 | }
36 |
37 | func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
38 | // Called when the app was launched with a url. Feel free to add additional processing here,
39 | // but if you want the App API to support tracking app url opens, make sure to keep this call
40 | return CAPBridge.handleOpenUrl(url, options)
41 | }
42 |
43 | func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
44 | // Called when the app was launched with an activity, including Universal Links.
45 | // Feel free to add additional processing here, but if you want the App API to support
46 | // tracking app url opens, make sure to keep this call
47 | return CAPBridge.handleContinueActivity(userActivity, restorationHandler)
48 | }
49 |
50 | override func touchesBegan(_ touches: Set, with event: UIEvent?) {
51 | super.touchesBegan(touches, with: event)
52 |
53 | let statusBarRect = UIApplication.shared.statusBarFrame
54 | guard let touchPoint = event?.allTouches?.first?.location(in: self.window) else { return }
55 |
56 | if statusBarRect.contains(touchPoint) {
57 | NotificationCenter.default.post(CAPBridge.statusBarTappedNotification)
58 | }
59 | }
60 |
61 | #if USE_PUSH
62 |
63 | func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
64 | NotificationCenter.default.post(name: Notification.Name(CAPNotifications.DidRegisterForRemoteNotificationsWithDeviceToken.name()), object: deviceToken)
65 | }
66 |
67 | func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
68 | NotificationCenter.default.post(name: Notification.Name(CAPNotifications.DidFailToRegisterForRemoteNotificationsWithError.name()), object: error)
69 | }
70 |
71 | #endif
72 |
73 | }
74 |
75 |
--------------------------------------------------------------------------------
/example/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/capacitor-community/http/27dc4c858f1eb742622bc71c590f8aa351ef8221/example/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@1x.png
--------------------------------------------------------------------------------
/example/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@2x-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/capacitor-community/http/27dc4c858f1eb742622bc71c590f8aa351ef8221/example/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@2x-1.png
--------------------------------------------------------------------------------
/example/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/capacitor-community/http/27dc4c858f1eb742622bc71c590f8aa351ef8221/example/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@2x.png
--------------------------------------------------------------------------------
/example/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/capacitor-community/http/27dc4c858f1eb742622bc71c590f8aa351ef8221/example/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@3x.png
--------------------------------------------------------------------------------
/example/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/capacitor-community/http/27dc4c858f1eb742622bc71c590f8aa351ef8221/example/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@1x.png
--------------------------------------------------------------------------------
/example/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@2x-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/capacitor-community/http/27dc4c858f1eb742622bc71c590f8aa351ef8221/example/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@2x-1.png
--------------------------------------------------------------------------------
/example/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/capacitor-community/http/27dc4c858f1eb742622bc71c590f8aa351ef8221/example/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@2x.png
--------------------------------------------------------------------------------
/example/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/capacitor-community/http/27dc4c858f1eb742622bc71c590f8aa351ef8221/example/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@3x.png
--------------------------------------------------------------------------------
/example/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/capacitor-community/http/27dc4c858f1eb742622bc71c590f8aa351ef8221/example/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@1x.png
--------------------------------------------------------------------------------
/example/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@2x-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/capacitor-community/http/27dc4c858f1eb742622bc71c590f8aa351ef8221/example/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@2x-1.png
--------------------------------------------------------------------------------
/example/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/capacitor-community/http/27dc4c858f1eb742622bc71c590f8aa351ef8221/example/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@2x.png
--------------------------------------------------------------------------------
/example/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/capacitor-community/http/27dc4c858f1eb742622bc71c590f8aa351ef8221/example/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@3x.png
--------------------------------------------------------------------------------
/example/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-512@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/capacitor-community/http/27dc4c858f1eb742622bc71c590f8aa351ef8221/example/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-512@2x.png
--------------------------------------------------------------------------------
/example/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-60x60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/capacitor-community/http/27dc4c858f1eb742622bc71c590f8aa351ef8221/example/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-60x60@2x.png
--------------------------------------------------------------------------------
/example/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-60x60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/capacitor-community/http/27dc4c858f1eb742622bc71c590f8aa351ef8221/example/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-60x60@3x.png
--------------------------------------------------------------------------------
/example/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-76x76@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/capacitor-community/http/27dc4c858f1eb742622bc71c590f8aa351ef8221/example/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-76x76@1x.png
--------------------------------------------------------------------------------
/example/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-76x76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/capacitor-community/http/27dc4c858f1eb742622bc71c590f8aa351ef8221/example/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-76x76@2x.png
--------------------------------------------------------------------------------
/example/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-83.5x83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/capacitor-community/http/27dc4c858f1eb742622bc71c590f8aa351ef8221/example/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-83.5x83.5@2x.png
--------------------------------------------------------------------------------
/example/ios/App/App/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "20x20",
5 | "idiom" : "iphone",
6 | "filename" : "AppIcon-20x20@2x.png",
7 | "scale" : "2x"
8 | },
9 | {
10 | "size" : "20x20",
11 | "idiom" : "iphone",
12 | "filename" : "AppIcon-20x20@3x.png",
13 | "scale" : "3x"
14 | },
15 | {
16 | "size" : "29x29",
17 | "idiom" : "iphone",
18 | "filename" : "AppIcon-29x29@2x-1.png",
19 | "scale" : "2x"
20 | },
21 | {
22 | "size" : "29x29",
23 | "idiom" : "iphone",
24 | "filename" : "AppIcon-29x29@3x.png",
25 | "scale" : "3x"
26 | },
27 | {
28 | "size" : "40x40",
29 | "idiom" : "iphone",
30 | "filename" : "AppIcon-40x40@2x.png",
31 | "scale" : "2x"
32 | },
33 | {
34 | "size" : "40x40",
35 | "idiom" : "iphone",
36 | "filename" : "AppIcon-40x40@3x.png",
37 | "scale" : "3x"
38 | },
39 | {
40 | "size" : "60x60",
41 | "idiom" : "iphone",
42 | "filename" : "AppIcon-60x60@2x.png",
43 | "scale" : "2x"
44 | },
45 | {
46 | "size" : "60x60",
47 | "idiom" : "iphone",
48 | "filename" : "AppIcon-60x60@3x.png",
49 | "scale" : "3x"
50 | },
51 | {
52 | "size" : "20x20",
53 | "idiom" : "ipad",
54 | "filename" : "AppIcon-20x20@1x.png",
55 | "scale" : "1x"
56 | },
57 | {
58 | "size" : "20x20",
59 | "idiom" : "ipad",
60 | "filename" : "AppIcon-20x20@2x-1.png",
61 | "scale" : "2x"
62 | },
63 | {
64 | "size" : "29x29",
65 | "idiom" : "ipad",
66 | "filename" : "AppIcon-29x29@1x.png",
67 | "scale" : "1x"
68 | },
69 | {
70 | "size" : "29x29",
71 | "idiom" : "ipad",
72 | "filename" : "AppIcon-29x29@2x.png",
73 | "scale" : "2x"
74 | },
75 | {
76 | "size" : "40x40",
77 | "idiom" : "ipad",
78 | "filename" : "AppIcon-40x40@1x.png",
79 | "scale" : "1x"
80 | },
81 | {
82 | "size" : "40x40",
83 | "idiom" : "ipad",
84 | "filename" : "AppIcon-40x40@2x-1.png",
85 | "scale" : "2x"
86 | },
87 | {
88 | "size" : "76x76",
89 | "idiom" : "ipad",
90 | "filename" : "AppIcon-76x76@1x.png",
91 | "scale" : "1x"
92 | },
93 | {
94 | "size" : "76x76",
95 | "idiom" : "ipad",
96 | "filename" : "AppIcon-76x76@2x.png",
97 | "scale" : "2x"
98 | },
99 | {
100 | "size" : "83.5x83.5",
101 | "idiom" : "ipad",
102 | "filename" : "AppIcon-83.5x83.5@2x.png",
103 | "scale" : "2x"
104 | },
105 | {
106 | "size" : "1024x1024",
107 | "idiom" : "ios-marketing",
108 | "filename" : "AppIcon-512@2x.png",
109 | "scale" : "1x"
110 | }
111 | ],
112 | "info" : {
113 | "version" : 1,
114 | "author" : "xcode"
115 | }
116 | }
--------------------------------------------------------------------------------
/example/ios/App/App/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/example/ios/App/App/Assets.xcassets/Splash.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "splash-2732x2732-2.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "splash-2732x2732-1.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "splash-2732x2732.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/example/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/capacitor-community/http/27dc4c858f1eb742622bc71c590f8aa351ef8221/example/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732-1.png
--------------------------------------------------------------------------------
/example/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/capacitor-community/http/27dc4c858f1eb742622bc71c590f8aa351ef8221/example/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732-2.png
--------------------------------------------------------------------------------
/example/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/capacitor-community/http/27dc4c858f1eb742622bc71c590f8aa351ef8221/example/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732.png
--------------------------------------------------------------------------------
/example/ios/App/App/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/example/ios/App/App/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/example/ios/App/App/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleDisplayName
8 | example
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
21 | CFBundleURLTypes
22 |
23 |
24 | CFBundleURLName
25 | com.getcapacitor.capacitor
26 | CFBundleURLSchemes
27 |
28 | capacitor
29 |
30 |
31 |
32 | CFBundleVersion
33 | 1
34 | LSRequiresIPhoneOS
35 |
36 | NSAppTransportSecurity
37 |
38 | NSAllowsArbitraryLoads
39 |
40 |
41 | NSCameraUsageDescription
42 | To Take Photos and Video
43 | NSLocationAlwaysUsageDescription
44 | Always allow Geolocation?
45 | NSLocationWhenInUseUsageDescription
46 | Allow Geolocation?
47 | NSMicrophoneUsageDescription
48 | To Record Audio With Video
49 | NSPhotoLibraryAddUsageDescription
50 | Store camera photos to camera
51 | NSPhotoLibraryUsageDescription
52 | To Pick Photos from Library
53 | UILaunchStoryboardName
54 | LaunchScreen
55 | UIMainStoryboardFile
56 | Main
57 | UIRequiredDeviceCapabilities
58 |
59 | armv7
60 |
61 | UISupportedInterfaceOrientations
62 |
63 | UIInterfaceOrientationPortrait
64 | UIInterfaceOrientationLandscapeLeft
65 | UIInterfaceOrientationLandscapeRight
66 |
67 | UISupportedInterfaceOrientations~ipad
68 |
69 | UIInterfaceOrientationPortrait
70 | UIInterfaceOrientationPortraitUpsideDown
71 | UIInterfaceOrientationLandscapeLeft
72 | UIInterfaceOrientationLandscapeRight
73 |
74 | UIViewControllerBasedStatusBarAppearance
75 |
76 |
77 |
78 |
--------------------------------------------------------------------------------
/example/ios/App/App/capacitor.config.json:
--------------------------------------------------------------------------------
1 | {}
2 |
--------------------------------------------------------------------------------
/example/ios/App/App/config.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/example/ios/App/Podfile:
--------------------------------------------------------------------------------
1 | platform :ios, '12.0'
2 | use_frameworks!
3 |
4 | # workaround to avoid Xcode caching of Pods that requires
5 | # Product -> Clean Build Folder after new Cordova plugins installed
6 | # Requires CocoaPods 1.6 or newer
7 | install! 'cocoapods', :disable_input_output_paths => true
8 |
9 | def capacitor_pods
10 | pod 'Capacitor', :path => '../../node_modules/@capacitor/ios'
11 | pod 'CapacitorCordova', :path => '../../node_modules/@capacitor/ios'
12 | pod 'CapacitorCommunityHttp', :path => '../../..'
13 | end
14 |
15 | target 'App' do
16 | capacitor_pods
17 | # Add your Pods here
18 | end
19 |
--------------------------------------------------------------------------------
/example/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "http-example",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@capacitor/android": "^3.3.2",
7 | "@capacitor/core": "^3.3.2",
8 | "@capacitor/ios": "^3.3.2",
9 | "@capacitor-community/http": "file:../",
10 | "@ionic/react": "^6.0.0-rc.3",
11 | "react": "^17.0.2",
12 | "react-dom": "^17.0.2"
13 | },
14 | "devDependencies": {
15 | "@capacitor/cli": "^3.3.2",
16 | "@types/node": "^12.0.0",
17 | "@types/react": "^17.0.0",
18 | "@types/react-dom": "^17.0.0",
19 | "react-scripts": "4.0.3",
20 | "typescript": "^4.1.2"
21 | },
22 | "scripts": {
23 | "start": "export PORT=8000 && react-scripts start",
24 | "build": "export BUILD_PATH='./www' && react-scripts build",
25 | "test": "react-scripts test",
26 | "eject": "react-scripts eject"
27 | },
28 | "eslintConfig": {
29 | "extends": [
30 | "react-app",
31 | "react-app/jest"
32 | ]
33 | },
34 | "browserslist": {
35 | "production": [
36 | ">0.2%",
37 | "not dead",
38 | "not op_mini all"
39 | ],
40 | "development": [
41 | "last 1 chrome version",
42 | "last 1 firefox version",
43 | "last 1 safari version"
44 | ]
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/example/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/capacitor-community/http/27dc4c858f1eb742622bc71c590f8aa351ef8221/example/public/favicon.ico
--------------------------------------------------------------------------------
/example/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Http Plugin Sample
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/example/readme.md:
--------------------------------------------------------------------------------
1 | # Getting Started with Create React App
2 |
3 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
4 |
5 | ## Available Scripts
6 |
7 | In the project directory, you can run:
8 |
9 | ### `yarn start`
10 |
11 | Runs the app in the development mode.\
12 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
13 |
14 | The page will reload if you make edits.\
15 | You will also see any lint errors in the console.
16 |
17 | ### `yarn test`
18 |
19 | Launches the test runner in the interactive watch mode.\
20 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
21 |
22 | ### `yarn build`
23 |
24 | Builds the app for production to the `build` folder.\
25 | It correctly bundles React in production mode and optimizes the build for the best performance.
26 |
27 | The build is minified and the filenames include the hashes.\
28 | Your app is ready to be deployed!
29 |
30 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
31 |
32 | ### `yarn eject`
33 |
34 | **Note: this is a one-way operation. Once you `eject`, you can’t go back!**
35 |
36 | If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
37 |
38 | Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own.
39 |
40 | You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it.
41 |
42 | ## Learn More
43 |
44 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
45 |
46 | To learn React, check out the [React documentation](https://reactjs.org/).
47 |
--------------------------------------------------------------------------------
/example/server/README.md:
--------------------------------------------------------------------------------
1 | # Example Server
2 |
3 | This example server can be used when testing the example Android and iOS applications in the `/example` folder of the `@capacitor-community/http` repo
4 |
5 | ## Routes
6 |
7 | There are 7 Http methods included for each route
8 |
9 | - GET
10 | - POST
11 | - PUT
12 | - PATCH
13 | - DELETE
14 | - OPTIONS
15 | - LINK
16 |
17 | `LINK` is a common, but non-standard, Http method. It is used in the example server as a way of checking support for any custom Http verb. If it works with `LINK` it should work with any Http method.
18 |
19 | ### Route List
20 |
21 | - `http://localhost:3000/`
22 | - Returns a 204 no content with no content-type header
23 | - `http://localhost:3000/content-type/image`
24 | - Returns a 200 with a test image and a content-type of `image/jpeg`
25 | - `http://localhost:3000/content-type/json`
26 | - Returns a 200 with a json body and a content-type of `application/json`
27 | - `http://localhost:3000/content-type/multipart-form`
28 | - Returns a 200 with a mutlipart form body and a content-type of `multipart/form-data`
29 | - `http://localhost:3000/content-type/octet-stream`
30 | - Returns a 200 with a binary body of `Hello World` and a content-type of `application/octet-stream`
31 | - `http://localhost:3000/content-type/pdf`
32 | - Returns a 200 with a test .pdf file and a content-type of `application/pdf`
33 | - `http://localhost:3000/content-type/plaintext`
34 | - Returns a 200 with an unparsed, but valid json body and a content-type of `text/plain; charset=utf-8`
35 | - `http://localhost:3000/content-type/video`
36 | - Returns a 200 with 10MB video and a content-type of `video/mp4`
37 | - `http://localhost:3000/content-type/xml`
38 | - Returns a 200 with a test .xml file and a content-type of `application/xml`
39 | - `http://localhost:3000/content-type/zip`
40 | - Returns a 200 with a test .zip file and a content-type of `application/zip`
41 |
42 | ## Insomnia
43 |
44 | [Insomnia](https://insomnia.rest/) is a tool for testing requests to and from a server. The `insomnia.json` file contains all of the routes for the server. It can be loaded in Insomnia so you can test the server manually.
45 |
46 | ## Testing
47 |
48 | Testing only works locally for now. To test, run the webserver with `npm start` and then in another terminal/process run `npm test`
49 |
--------------------------------------------------------------------------------
/example/server/files/static/test.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/capacitor-community/http/27dc4c858f1eb742622bc71c590f8aa351ef8221/example/server/files/static/test.jpg
--------------------------------------------------------------------------------
/example/server/files/static/test.jpg.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/capacitor-community/http/27dc4c858f1eb742622bc71c590f8aa351ef8221/example/server/files/static/test.jpg.zip
--------------------------------------------------------------------------------
/example/server/files/static/test.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/capacitor-community/http/27dc4c858f1eb742622bc71c590f8aa351ef8221/example/server/files/static/test.mp4
--------------------------------------------------------------------------------
/example/server/files/static/test.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/capacitor-community/http/27dc4c858f1eb742622bc71c590f8aa351ef8221/example/server/files/static/test.pdf
--------------------------------------------------------------------------------
/example/server/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "example",
3 | "type": "module",
4 | "private": true,
5 | "version": "0.1.0",
6 | "description": "Example server for @capacitor-community/http with Hapi.js",
7 | "main": "server.mjs",
8 | "scripts": {
9 | "start": "node --experimental-specifier-resolution=node dist/server.js",
10 | "build": "tsc",
11 | "test": "uvu tests"
12 | },
13 | "author": "Thomas Vidas ",
14 | "license": "MIT",
15 | "dependencies": {
16 | "@hapi/hapi": "^20.2.1",
17 | "@hapi/inert": "^6.0.4",
18 | "form-data": "^4.0.0"
19 | },
20 | "devDependencies": {
21 | "@types/hapi__hapi": "^20.0.9",
22 | "@types/hapi__inert": "^5.2.3",
23 | "@types/node": "^16.11.7",
24 | "axios": "^0.24.0",
25 | "typescript": "^4.4.4",
26 | "uvu": "^0.5.2"
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/example/server/src/routes/basic/bool.ts:
--------------------------------------------------------------------------------
1 | import Hapi from '@hapi/hapi';
2 |
3 | // Hapi route collection returning a boolean for every standard route + 1 custom route (LINK)
4 | const output = true;
5 | const httpMethods = ['get', 'post', 'put', 'patch', 'delete', 'options', 'link'];
6 |
7 | const routes: Hapi.ServerRoute[] = httpMethods.map(method => {
8 | return {
9 | method,
10 | path: '/bool',
11 | handler: (request: Hapi.Request, toolkit: Hapi.ResponseToolkit, err: Error) => {
12 | return output;
13 | },
14 | } as Hapi.ServerRoute;
15 | });
16 |
17 | export default routes;
18 |
--------------------------------------------------------------------------------
/example/server/src/routes/basic/empty.ts:
--------------------------------------------------------------------------------
1 | import Hapi from '@hapi/hapi';
2 |
3 | // Hapi route collection returning an empty Http 204 for every standard route + 1 custom route (LINK)
4 | const output = null;
5 | const httpMethods = ['get', 'post', 'put', 'patch', 'delete', 'options', 'link'];
6 |
7 | const routes: Hapi.ServerRoute[] = httpMethods.map(method => {
8 | return {
9 | method,
10 | path: '/',
11 | options: {
12 | cors: true,
13 | },
14 | handler: (request: Hapi.Request, toolkit: Hapi.ResponseToolkit, err: Error) => {
15 | return output;
16 | },
17 | } as Hapi.ServerRoute;
18 | });
19 |
20 | export default routes;
21 |
--------------------------------------------------------------------------------
/example/server/src/routes/basic/index.ts:
--------------------------------------------------------------------------------
1 | import Hapi from '@hapi/hapi';
2 | import EmptyRoutes from './empty';
3 | import JsonRoutes from './json';
4 | import StringRoutes from './string';
5 | import NumberRoutes from './number';
6 | import BooleanRoutes from './bool';
7 |
8 | const output: Hapi.ServerRoute[] = [];
9 | output.push(...EmptyRoutes, ...JsonRoutes, ...StringRoutes, ...NumberRoutes, ...BooleanRoutes);
10 | export default output;
11 |
--------------------------------------------------------------------------------
/example/server/src/routes/basic/json.ts:
--------------------------------------------------------------------------------
1 | import Hapi from '@hapi/hapi';
2 |
3 | // Hapi route collection returning a JSON object for every standard route + 1 custom route (LINK)
4 |
5 | const output = {
6 | 'stringValue': 'string value',
7 | 'numberValue': 1000,
8 | 'booleanValue': true,
9 | 'nullValue': null,
10 | 'string-with-hyphen': 'string-hyphenated value',
11 | 'nestedValue': {
12 | 'stringValue': 'string value',
13 | 'numberValue': 1000,
14 | 'booleanValue': true,
15 | 'nullValue': null,
16 | 'string-with-hyphen': 'string-hyphenated value',
17 | 'nestedValue': {
18 | 'stringValue': 'string value',
19 | 'numberValue': 1000,
20 | 'booleanValue': true,
21 | 'nullValue': null,
22 | 'string-with-hyphen': 'string-hyphenated value',
23 | },
24 | },
25 | };
26 |
27 | const httpMethods = ['get', 'post', 'put', 'patch', 'delete', 'options', 'link'];
28 |
29 | const routes: Hapi.ServerRoute[] = httpMethods.map(method => {
30 | return {
31 | method,
32 | path: '/json',
33 | handler: (request: Hapi.Request, toolkit: Hapi.ResponseToolkit, err: Error) => {
34 | return output;
35 | },
36 | } as Hapi.ServerRoute;
37 | });
38 |
39 | export default routes;
40 |
--------------------------------------------------------------------------------
/example/server/src/routes/basic/number.ts:
--------------------------------------------------------------------------------
1 | import Hapi from '@hapi/hapi';
2 |
3 | // Hapi route collection returning a number for every standard route + 1 custom route (LINK)
4 | const output = 200;
5 | const httpMethods = ['get', 'post', 'put', 'patch', 'delete', 'options', 'link'];
6 |
7 | const routes: Hapi.ServerRoute[] = httpMethods.map(method => {
8 | return {
9 | method,
10 | path: '/number',
11 | handler: (request: Hapi.Request, toolkit: Hapi.ResponseToolkit, err: Error) => {
12 | return output;
13 | },
14 | } as Hapi.ServerRoute;
15 | });
16 |
17 | export default routes;
18 |
--------------------------------------------------------------------------------
/example/server/src/routes/basic/string.ts:
--------------------------------------------------------------------------------
1 | import Hapi from '@hapi/hapi';
2 |
3 | // Hapi route collection returning a string for every standard route + 1 custom route (LINK)
4 | const output = 'String Http Response. This should not break things!';
5 | const httpMethods = ['get', 'post', 'put', 'patch', 'delete', 'options', 'link'];
6 |
7 | const routes: Hapi.ServerRoute[] = httpMethods.map(method => {
8 | return {
9 | method,
10 | path: '/string',
11 | handler: (request: Hapi.Request, toolkit: Hapi.ResponseToolkit, err: Error) => {
12 | return output;
13 | },
14 | } as Hapi.ServerRoute;
15 | });
16 |
17 | export default routes;
18 |
--------------------------------------------------------------------------------
/example/server/src/routes/content-type/image.ts:
--------------------------------------------------------------------------------
1 | import Hapi from '@hapi/hapi';
2 |
3 | // Hapi route collection returning an image with an image/jpg header for every standard route + 1 custom route (LINK)
4 | const output = { 'content-type': 'image/jpg' };
5 | const httpMethods = ['get', 'post', 'put', 'patch', 'delete', 'options', 'link'];
6 |
7 | const routes: Hapi.ServerRoute[] = httpMethods.map(method => {
8 | return {
9 | method,
10 | path: '/content-type/image',
11 | handler: (request: Hapi.Request, toolkit: Hapi.ResponseToolkit, err: Error) => {
12 | const response = toolkit.file(`${process.cwd()}/files/static/test.jpg`);
13 | response.header('Content-Type', 'image/jpg');
14 | return response;
15 | },
16 | } as Hapi.ServerRoute;
17 | });
18 |
19 | export default routes;
20 |
--------------------------------------------------------------------------------
/example/server/src/routes/content-type/index.ts:
--------------------------------------------------------------------------------
1 | import Hapi from '@hapi/hapi';
2 | import JsonRoutes from './json';
3 | import PlaintextRoutes from './plaintext';
4 | import MultipartFormRoutes from './multipart-form';
5 | import ImageRoutes from './image';
6 | import OctetStreamRoutes from './octet-stream';
7 | import PdfRoutes from './pdf';
8 | import VideoRoutes from './video';
9 | import XmlRoutes from './xml';
10 | import ZipRoutes from './zip';
11 |
12 | const output: Hapi.ServerRoute[] = [];
13 | output.push(...JsonRoutes, ...PlaintextRoutes, ...ImageRoutes, ...OctetStreamRoutes, ...PdfRoutes, ...VideoRoutes, ...ZipRoutes, ...MultipartFormRoutes, ...XmlRoutes);
14 | export default output;
15 |
--------------------------------------------------------------------------------
/example/server/src/routes/content-type/json.ts:
--------------------------------------------------------------------------------
1 | import Hapi from '@hapi/hapi';
2 |
3 | // Hapi route collection returning a JSON object for every standard route + 1 custom route (LINK)
4 | const output = { 'content-type': 'application/json' };
5 | const httpMethods = ['get', 'post', 'put', 'patch', 'delete', 'options', 'link'];
6 |
7 | const routes: Hapi.ServerRoute[] = httpMethods.map(method => {
8 | return {
9 | method,
10 | path: '/content-type/json',
11 | handler: (request: Hapi.Request, toolkit: Hapi.ResponseToolkit, err: Error) => {
12 | const response = toolkit.response(output);
13 | response.header('Content-Type', 'application/json');
14 | return response;
15 | },
16 | } as Hapi.ServerRoute;
17 | });
18 |
19 | export default routes;
20 |
--------------------------------------------------------------------------------
/example/server/src/routes/content-type/multipart-form.ts:
--------------------------------------------------------------------------------
1 | import Hapi from '@hapi/hapi';
2 | import FormData from 'form-data';
3 |
4 | // Hapi route collection returning a multipart/form for every standard route + 1 custom route (LINK)
5 | const output = { 'content-type': 'multipart/form-data' };
6 | const httpMethods = ['get', 'post', 'put', 'patch', 'delete', 'options', 'link'];
7 |
8 | const routes: Hapi.ServerRoute[] = httpMethods.map(method => {
9 | return {
10 | method,
11 | path: '/content-type/multipart-form',
12 | handler: (request: Hapi.Request, toolkit: Hapi.ResponseToolkit, err: Error) => {
13 | const form = new FormData();
14 | form.append('string', 'Hello World');
15 | form.append('number', 500);
16 | form.append('buffer', Buffer.from('foobar'));
17 |
18 | const response = toolkit.response(form.getBuffer());
19 | response.header('Content-Type', `multipart/form-data; boundary=${form.getBoundary()}`);
20 | return response;
21 | },
22 | } as Hapi.ServerRoute;
23 | });
24 |
25 | export default routes;
26 |
--------------------------------------------------------------------------------
/example/server/src/routes/content-type/octet-stream.ts:
--------------------------------------------------------------------------------
1 | import Hapi from '@hapi/hapi';
2 |
3 | // Hapi route collection returning a Buffer octet-stream for every standard route + 1 custom route (LINK)
4 | const output = Buffer.from('Hello World');
5 | const httpMethods = ['get', 'post', 'put', 'patch', 'delete', 'options', 'link'];
6 |
7 | const routes: Hapi.ServerRoute[] = httpMethods.map(method => {
8 | return {
9 | method,
10 | path: '/content-type/octet',
11 | handler: (request: Hapi.Request, toolkit: Hapi.ResponseToolkit, err: Error) => {
12 | return output;
13 | },
14 | } as Hapi.ServerRoute;
15 | });
16 |
17 | export default routes;
18 |
--------------------------------------------------------------------------------
/example/server/src/routes/content-type/pdf.ts:
--------------------------------------------------------------------------------
1 | import Hapi from '@hapi/hapi';
2 |
3 | // Hapi route collection returning a PDF with an application/pdf header for every standard route + 1 custom route (LINK)
4 | const output = { 'content-type': 'text/pdf' };
5 | const httpMethods = ['get', 'post', 'put', 'patch', 'delete', 'options', 'link'];
6 |
7 | const routes: Hapi.ServerRoute[] = httpMethods.map(method => {
8 | return {
9 | method,
10 | path: '/content-type/pdf',
11 | handler: (request: Hapi.Request, toolkit: Hapi.ResponseToolkit, err: Error) => {
12 | const response = toolkit.file(`${process.cwd()}/files/static/test.pdf`);
13 | response.header('Content-Type', 'application/pdf');
14 | return response;
15 | },
16 | } as Hapi.ServerRoute;
17 | });
18 |
19 | export default routes;
20 |
--------------------------------------------------------------------------------
/example/server/src/routes/content-type/plaintext.ts:
--------------------------------------------------------------------------------
1 | import Hapi from '@hapi/hapi';
2 |
3 | // Hapi route collection returning a JSON object with a text/plain header for every standard route + 1 custom route (LINK)
4 | const output = { 'content-type': 'text/plain' };
5 | const httpMethods = ['get', 'post', 'put', 'patch', 'delete', 'options', 'link'];
6 |
7 | const routes: Hapi.ServerRoute[] = httpMethods.map(method => {
8 | return {
9 | method,
10 | path: '/content-type/plaintext',
11 | handler: (request: Hapi.Request, toolkit: Hapi.ResponseToolkit, err: Error) => {
12 | const response = toolkit.response(output);
13 | response.header('Content-Type', 'text/plain');
14 | return response;
15 | },
16 | } as Hapi.ServerRoute;
17 | });
18 |
19 | export default routes;
20 |
--------------------------------------------------------------------------------
/example/server/src/routes/content-type/video.ts:
--------------------------------------------------------------------------------
1 | import Hapi from '@hapi/hapi';
2 |
3 | // Hapi route collection returning a video with an video/mp4 header for every standard route + 1 custom route (LINK)
4 | const output = { 'content-type': 'video/mp4' };
5 | const httpMethods = ['get', 'post', 'put', 'patch', 'delete', 'options', 'link'];
6 |
7 | const routes: Hapi.ServerRoute[] = httpMethods.map(method => {
8 | return {
9 | method,
10 | path: '/content-type/video',
11 | handler: (request: Hapi.Request, toolkit: Hapi.ResponseToolkit, err: Error) => {
12 | const response = toolkit.file(`${process.cwd()}/files/static/test.mp4`);
13 | response.header('Content-Type', 'video/mp4');
14 | return response;
15 | },
16 | } as Hapi.ServerRoute;
17 | });
18 |
19 | export default routes;
20 |
--------------------------------------------------------------------------------
/example/server/src/routes/content-type/x-www-form-urlencoded.ts:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/capacitor-community/http/27dc4c858f1eb742622bc71c590f8aa351ef8221/example/server/src/routes/content-type/x-www-form-urlencoded.ts
--------------------------------------------------------------------------------
/example/server/src/routes/content-type/xml.ts:
--------------------------------------------------------------------------------
1 | import Hapi from '@hapi/hapi';
2 |
3 | // Hapi route collection returning an image with an application/zip header for every standard route + 1 custom route (LINK)
4 | const output = { 'content-type': 'application/xml' };
5 | const httpMethods = ['get', 'post', 'put', 'patch', 'delete', 'options', 'link'];
6 |
7 | const routes: Hapi.ServerRoute[] = httpMethods.map(method => {
8 | return {
9 | method,
10 | path: '/content-type/xml',
11 | handler: (request: Hapi.Request, toolkit: Hapi.ResponseToolkit, err: Error) => {
12 | const response = toolkit.response('Test XML');
13 | response.header('Content-Type', 'application/xml');
14 | return response;
15 | },
16 | } as Hapi.ServerRoute;
17 | });
18 |
19 | export default routes;
20 |
--------------------------------------------------------------------------------
/example/server/src/routes/content-type/zip.ts:
--------------------------------------------------------------------------------
1 | import Hapi from '@hapi/hapi';
2 |
3 | // Hapi route collection returning an image with an application/zip header for every standard route + 1 custom route (LINK)
4 | const output = { 'content-type': 'application/zip' };
5 | const httpMethods = ['get', 'post', 'put', 'patch', 'delete', 'options', 'link'];
6 |
7 | const routes: Hapi.ServerRoute[] = httpMethods.map(method => {
8 | return {
9 | method,
10 | path: '/content-type/zip',
11 | handler: (request: Hapi.Request, toolkit: Hapi.ResponseToolkit, err: Error) => {
12 | const response = toolkit.file(`${process.cwd()}/files/static/test.jpg.zip`);
13 | response.header('Content-Type', 'application/zip');
14 | return response;
15 | },
16 | } as Hapi.ServerRoute;
17 | });
18 |
19 | export default routes;
20 |
--------------------------------------------------------------------------------
/example/server/src/routes/io/download.ts:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/capacitor-community/http/27dc4c858f1eb742622bc71c590f8aa351ef8221/example/server/src/routes/io/download.ts
--------------------------------------------------------------------------------
/example/server/src/routes/io/index.ts:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/capacitor-community/http/27dc4c858f1eb742622bc71c590f8aa351ef8221/example/server/src/routes/io/index.ts
--------------------------------------------------------------------------------
/example/server/src/routes/io/upload.ts:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/capacitor-community/http/27dc4c858f1eb742622bc71c590f8aa351ef8221/example/server/src/routes/io/upload.ts
--------------------------------------------------------------------------------
/example/server/src/server.ts:
--------------------------------------------------------------------------------
1 | import Hapi from '@hapi/hapi';
2 | import Inert from '@hapi/inert';
3 | import BasicRoutes from './routes/basic';
4 | import ContentTypeRoutes from './routes/content-type';
5 |
6 | const init = async () => {
7 | const server = Hapi.server({
8 | port: 3000,
9 | host: 'localhost',
10 | routes: {
11 | cors: {
12 | origin: ['*'], // an array of origins or 'ignore'
13 | credentials: true, // boolean - 'Access-Control-Allow-Credentials'
14 | },
15 | },
16 | });
17 | await server.register(Inert);
18 |
19 | server.route(BasicRoutes);
20 | server.route(ContentTypeRoutes);
21 |
22 | await server.start();
23 | console.log('Server running on %s', server.info.uri);
24 | };
25 |
26 | process.on('unhandledRejection', (err: any) => {
27 | console.log(err);
28 | process.exit(1);
29 | });
30 |
31 | init();
32 |
33 | /*
34 | import express from 'express'
35 | import compression from 'compression'
36 | import bodyParser from 'body-parser'
37 | import cors from 'cors'
38 | import cookieParser from 'cookie-parser'
39 | import multer from 'multer'
40 | import path from 'path'
41 |
42 | // __dirname workaround for .mjs file
43 | import { fileURLToPath } from 'url';
44 | const __dirname = path.dirname(fileURLToPath(import.meta.url));
45 |
46 | const app = express();
47 | const upload = multer({ dest: 'uploads/' })
48 |
49 | const staticPath = path.join(__dirname, '/public');
50 |
51 | app.use(express.static(staticPath));
52 | app.use(cors({ origin: true }));
53 | app.use(bodyParser.json());
54 | app.use(bodyParser.urlencoded({ extended: true }));
55 | app.use(cookieParser());
56 |
57 | app.listen(3455, function () {
58 | console.log('listening on port 3455');
59 | });
60 |
61 | app.get('/get', (req, res) => {
62 | const headers = req.headers;
63 | const params = req.query;
64 | console.log('Got headers', headers);
65 | console.log('Got params', params);
66 | console.log(req.url);
67 | res.status(200);
68 | res.send();
69 | });
70 |
71 | app.get('/get-gzip', compression({ filter: (req, res) => true, threshold: 1,}), (req, res) => {
72 | const headers = req.headers;
73 | const params = req.query;
74 | console.log('Got headers', headers);
75 | console.log('Got params', params);
76 | console.log(req.url);
77 | res.status(200);
78 | res.json({
79 | data: 'compressed',
80 | });
81 | });
82 |
83 | app.get('/get-json', (req, res) => {
84 | res.status(200);
85 | res.json({
86 | name: 'Max',
87 | superpower: 'Being Awesome',
88 | });
89 | });
90 |
91 | app.get('/get-html', (req, res) => {
92 | res.status(200);
93 | res.header('Content-Type', 'text/html');
94 | res.send('Hi
');
95 | });
96 |
97 | app.get('/head', (req, res) => {
98 | const headers = req.headers;
99 | console.log('HEAD');
100 | console.log('Got headers', headers);
101 | res.status(200);
102 | res.send();
103 | });
104 |
105 | app.delete('/delete', (req, res) => {
106 | const headers = req.headers;
107 | console.log('DELETE');
108 | console.log('Got headers', headers);
109 | res.status(200);
110 | res.send();
111 | });
112 |
113 | app.patch('/patch', (req, res) => {
114 | const headers = req.headers;
115 | console.log('PATCH');
116 | console.log('Got headers', headers);
117 | res.status(200);
118 | res.send();
119 | });
120 |
121 | app.post('/post', (req, res) => {
122 | const headers = req.headers;
123 | console.log('POST');
124 | console.log('Got headers', headers);
125 | res.status(200);
126 | res.send();
127 | });
128 |
129 | app.put('/put', (req, res) => {
130 | const headers = req.headers;
131 | console.log('PUT');
132 | console.log('Got headers', headers);
133 | res.status(200);
134 | res.send();
135 | });
136 |
137 | app.get('/cookie', (req, res) => {
138 | console.log('COOKIE', req.cookies);
139 | res.status(200);
140 | res.send();
141 | });
142 |
143 | app.get('/download-pdf', (req, res) => {
144 | console.log('Sending PDF to request', +new Date());
145 | res.download('document.pdf');
146 | });
147 |
148 | app.get('/set-cookies', (req, res) => {
149 | res.cookie('style', 'very cool');
150 | res.send();
151 | });
152 |
153 | app.post('/upload-pdf', upload.single('myFile'), (req, res) => {
154 | console.log('Handling upload');
155 | const file = req.file;
156 | console.log('Got file', file);
157 |
158 | res.status(200);
159 | res.send();
160 | });
161 |
162 | app.post('/form-data', (req, res) => {
163 | console.log('Got form data post', req.body);
164 |
165 | res.status(200);
166 | res.send();
167 | });
168 |
169 | app.post('/form-data-multi', upload.any(), (req, res) => {
170 | console.log('Got form data multipart post', req.body);
171 |
172 | console.log(req.files);
173 |
174 | res.status(200);
175 | res.send();
176 | });
177 | */
178 |
--------------------------------------------------------------------------------
/example/server/tests/basic.routes.js:
--------------------------------------------------------------------------------
1 | // tests/demo.js
2 | import { test } from 'uvu';
3 | import * as assert from 'uvu/assert';
4 | import axios from 'axios';
5 |
6 | const methods = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS', 'LINK'];
7 |
8 | test('Is server running?', async () => {
9 | try {
10 | await axios.get('http://localhost:3000');
11 | } catch (err) {
12 | assert.unreachable('Error! Is the example server running?');
13 | }
14 | });
15 |
16 | test('Basic Routes', async () => {
17 | for (const i in methods) {
18 | const method = methods[i];
19 | const res = await axios.request({ method, url: 'http://localhost:3000/' });
20 |
21 | // Empty requests should be fairly bare
22 | assert.is(res.status, 204); // Http 204 - No Content
23 | assert.not.ok(res.data); // Body should be empty
24 | }
25 | });
26 |
27 | test.run();
28 |
--------------------------------------------------------------------------------
/example/server/tests/content-type.routes.js:
--------------------------------------------------------------------------------
1 | // tests/demo.js
2 | import { test } from 'uvu';
3 | import * as assert from 'uvu/assert';
4 | import axios from 'axios';
5 |
6 | const methods = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS', 'LINK'];
7 |
8 | test('Is server running?', async () => {
9 | try {
10 | await axios.get('http://localhost:3000');
11 | } catch (err) {
12 | assert.unreachable('Error! Is the example server running?');
13 | }
14 | });
15 |
16 | test('Content-Type -> Images', async () => {
17 | for (const i in methods) {
18 | const method = methods[i];
19 | const res = await axios.request({ method, url: 'http://localhost:3000/content-type/image', responseType: 'blob' });
20 |
21 | // Image request should return 200 with an image and proper headers
22 | assert.is(res.status, 200); // Http 200 - OK
23 | assert.is(res.headers['content-type'], 'image/jpg'); // Content-Type specifies image
24 | assert.ok(res.data); // Just check if it is a non-empty body
25 | }
26 | });
27 |
28 | test('Content-Type -> JSON', async () => {
29 | for (const i in methods) {
30 | const method = methods[i];
31 | const res = await axios.request({ method, url: 'http://localhost:3000/content-type/json' });
32 |
33 | // JSON request should return 200 with parsed json and proper headers
34 | assert.is(res.status, 200); // Http 200 - OK
35 | assert.is(res.headers['content-type'], 'application/json; charset=utf-8'); // Content-Type specifies json
36 | assert.type(res.data, 'object'); // res.data['content-type'] should be parsed json
37 | assert.is(res.data['content-type'], 'application/json'); // res.data['content-type'] should be what we expect
38 | }
39 | });
40 |
41 | test('Content-Type -> Multipart Form', async () => {
42 | for (const i in methods) {
43 | const method = methods[i];
44 | const res = await axios.request({ method, url: 'http://localhost:3000/content-type/multipart-form' });
45 |
46 | // Form request should return 200 with multipart form data and proper headers
47 | assert.is(res.status, 200); // Http 200 - OK
48 | assert.match(res.headers['content-type'], /multipart\/form-data; boundary/g); // Content-Type specifies multipart-form
49 |
50 | assert.type(res.data, 'string'); // res.data['content-type'] should a string that we'll match a bit
51 | assert.match(res.data, /Content-Disposition: form-data; name="string"/g);
52 | assert.match(res.data, /Content-Disposition: form-data; name="number"/g);
53 | assert.match(res.data, /Content-Disposition: form-data; name="buffer"/g);
54 | assert.match(res.data, /Content-Type: application\/octet-stream/g);
55 | }
56 | });
57 |
58 | test('Content-Type -> Octet Stream', async () => {
59 | for (const i in methods) {
60 | const method = methods[i];
61 | const res = await axios.request({ method, url: 'http://localhost:3000/content-type/octet', responseType: 'arraybuffer' });
62 |
63 | // Octet request should return 200 with a blob of data and proper headers
64 | assert.is(res.status, 200); // Http 200 - OK
65 | assert.is(res.headers['content-type'], 'application/octet-stream'); // Content-Type specifies octet-stream
66 |
67 | // Response should be a buffer (based on response type so axios doesn't auto-parse it)
68 | assert.type(res.data, 'object');
69 |
70 | // Convert buffer to string to make sure its what we expect
71 | const bufferString = res.data.toString();
72 | assert.is(bufferString, 'Hello World');
73 | }
74 | });
75 |
76 | test('Content-Type -> PDF', async () => {
77 | for (const i in methods) {
78 | const method = methods[i];
79 | const res = await axios.request({ method, url: 'http://localhost:3000/content-type/pdf', responseType: 'blob' });
80 |
81 | // PDF request should return 200 with a pdf and proper headers
82 | assert.is(res.status, 200); // Http 200 - OK
83 | assert.is(res.headers['content-type'], 'application/pdf'); // Content-Type specifies PDF
84 | assert.ok(res.data); // Just check if it is a non-empty body
85 | }
86 | });
87 |
88 | test('Content-Type -> Plain Text', async () => {
89 | for (const i in methods) {
90 | const method = methods[i];
91 | const res = await axios.request({ method, url: 'http://localhost:3000/content-type/plaintext' });
92 |
93 | // re-stringify data because axios parses it automatically without some hacks
94 | res.data = JSON.stringify(res.data);
95 |
96 | // JSON request should return 200 with a blob of data and proper headers
97 | assert.is(res.status, 200); // Http 200 - OK
98 | assert.is(res.headers['content-type'], 'text/plain; charset=utf-8'); // Content-Type specifies plaintext
99 |
100 | // Response should be a raw string
101 | assert.type(res.data, 'string');
102 |
103 | // Convert string to JSON to make sure its what we expect
104 | const json = JSON.parse(res.data);
105 | assert.match(json['content-type'], 'text/plain');
106 | }
107 | });
108 |
109 | test('Content-Type -> Video', async () => {
110 | for (const i in methods) {
111 | const method = methods[i];
112 | const res = await axios.request({ method, url: 'http://localhost:3000/content-type/video', responseType: 'blob' });
113 |
114 | // Video request should return 200 with a video and proper headers
115 | assert.is(res.status, 200); // Http 200 - OK
116 | assert.is(res.headers['content-type'], 'video/mp4'); // Content-Type specifies video file
117 | assert.ok(res.data); // Just check if it is a non-empty body
118 | }
119 | });
120 |
121 | test('Content-Type -> XML', async () => {
122 | for (const i in methods) {
123 | const method = methods[i];
124 | const res = await axios.request({ method, url: 'http://localhost:3000/content-type/xml' });
125 |
126 | // XML request should return 200 with proper XML and proper headers
127 | assert.is(res.status, 200); // Http 200 - OK
128 | assert.is(res.headers['content-type'], 'application/xml'); // Content-Type specifies xml
129 | assert.type(res.data, 'string');
130 | assert.is(res.data, 'Test XML');
131 | }
132 | });
133 |
134 | test('Content-Type -> ZIP', async () => {
135 | for (const i in methods) {
136 | const method = methods[i];
137 | const res = await axios.request({ method, url: 'http://localhost:3000/content-type/zip', responseType: 'blob' });
138 |
139 | // Zip request should return 200 with a zip and proper headers
140 | assert.is(res.status, 200); // Http 200 - OK
141 | assert.is(res.headers['content-type'], 'application/zip'); // Content-Type specifies zip
142 | assert.ok(res.data); // Just check if it is a non-empty body
143 | }
144 | });
145 |
146 | test.run();
147 |
--------------------------------------------------------------------------------
/example/server/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ESNext",
4 | "module": "ESNext",
5 | "moduleResolution": "Node",
6 | "esModuleInterop": true,
7 | "forceConsistentCasingInFileNames": true,
8 | "strict": true,
9 | "skipLibCheck": true,
10 | "rootDir": "./src",
11 | "outDir": "./dist"
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/example/src/index.tsx:
--------------------------------------------------------------------------------
1 | import { IonApp } from '@ionic/react';
2 | import React from 'react';
3 | import ReactDOM from 'react-dom';
4 | import App from './App';
5 |
6 | /* Core CSS required for Ionic components to work properly */
7 | import '@ionic/react/css/core.css';
8 |
9 | /* Basic CSS for apps built with Ionic */
10 | import '@ionic/react/css/normalize.css';
11 | import '@ionic/react/css/structure.css';
12 | import '@ionic/react/css/typography.css';
13 |
14 | /* Optional CSS utils that can be commented out */
15 | import '@ionic/react/css/padding.css';
16 | import '@ionic/react/css/float-elements.css';
17 | import '@ionic/react/css/text-alignment.css';
18 | import '@ionic/react/css/text-transformation.css';
19 | import '@ionic/react/css/flex-utils.css';
20 | import '@ionic/react/css/display.css';
21 |
22 | ReactDOM.render(
23 |
24 |
25 |
26 |
27 | ,
28 | document.getElementById('root'),
29 | );
30 |
--------------------------------------------------------------------------------
/example/src/react-app-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/example/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "lib": ["dom", "dom.iterable", "esnext"],
5 | "allowJs": true,
6 | "skipLibCheck": true,
7 | "esModuleInterop": true,
8 | "allowSyntheticDefaultImports": true,
9 | "strict": true,
10 | "forceConsistentCasingInFileNames": true,
11 | "noFallthroughCasesInSwitch": true,
12 | "module": "esnext",
13 | "moduleResolution": "node",
14 | "resolveJsonModule": true,
15 | "isolatedModules": true,
16 | "noEmit": true,
17 | "jsx": "react-jsx"
18 | },
19 | "include": ["src"]
20 | }
21 |
--------------------------------------------------------------------------------
/ios/Plugin.xcodeproj/xcuserdata/max.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | Plugin.xcscheme_^#shared#^_
8 |
9 | orderHint
10 | 4
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/ios/Plugin.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/ios/Plugin.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Plugin.xcworkspace/xcuserdata/max.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/capacitor-community/http/27dc4c858f1eb742622bc71c590f8aa351ef8221/ios/Plugin.xcworkspace/xcuserdata/max.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/ios/Plugin/CapacitorCookieManager.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 | import Capacitor
3 |
4 | public class CapacitorCookieManager {
5 | public func encode(_ value: String) -> String {
6 | return value.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed)!
7 | }
8 |
9 | public func decode(_ value: String) -> String {
10 | return value.removingPercentEncoding!
11 | }
12 |
13 | public func setCookie(_ url: URL, _ key: String, _ value: String) {
14 | let jar = HTTPCookieStorage.shared
15 | let field = ["Set-Cookie": "\(key)=\(value)"]
16 | let cookies = HTTPCookie.cookies(withResponseHeaderFields: field, for: url)
17 | jar.setCookies(cookies, for: url, mainDocumentURL: url)
18 | }
19 |
20 | public func getCookie(_ url: URL, _ key: String) -> HTTPCookie {
21 | let cookies = getCookies(url)
22 | for cookie in cookies {
23 | if (cookie.name == key) {
24 | return cookie
25 | }
26 | }
27 | return HTTPCookie()
28 | }
29 |
30 | public func getCookies(_ url: URL) -> [HTTPCookie] {
31 | let jar = HTTPCookieStorage.shared
32 | guard let cookies = jar.cookies(for: url) else { return [] }
33 |
34 | return cookies
35 | }
36 |
37 | public func deleteCookie(_ url: URL, _ key: String) {
38 | let jar = HTTPCookieStorage.shared
39 | let cookie = jar.cookies(for: url)?.first(where: { (cookie) -> Bool in
40 | return cookie.name == key
41 | })
42 |
43 | if cookie != nil { jar.deleteCookie(cookie!) }
44 | }
45 |
46 | public func clearCookies(_ url: URL) {
47 | let jar = HTTPCookieStorage.shared
48 | jar.cookies(for: url)?.forEach({ (cookie) in jar.deleteCookie(cookie) })
49 | }
50 |
51 | public func clearAllCookies() {
52 | let jar = HTTPCookieStorage.shared
53 | jar.cookies?.forEach({ (cookie) in jar.deleteCookie(cookie) })
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/ios/Plugin/CapacitorUrlRequest.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 | import Capacitor
3 |
4 | public class CapacitorUrlRequest: NSObject, URLSessionTaskDelegate {
5 | private var request: URLRequest;
6 | private var headers: [String:String];
7 |
8 | enum CapacitorUrlRequestError: Error {
9 | case serializationError(String?)
10 | }
11 |
12 | init(_ url: URL, method: String) {
13 | request = URLRequest(url: url)
14 | request.httpMethod = method
15 | headers = [:]
16 | if let lang = Locale.autoupdatingCurrent.languageCode {
17 | if let country = Locale.autoupdatingCurrent.regionCode {
18 | headers["Accept-Language"] = "\(lang)-\(country),\(lang);q=0.5"
19 | } else {
20 | headers["Accept-Language"] = "\(lang);q=0.5"
21 | }
22 | request.addValue(headers["Accept-Language"]!, forHTTPHeaderField: "Accept-Language")
23 | }
24 | }
25 |
26 | private func getRequestDataAsJson(_ data: JSValue) throws -> Data? {
27 | // We need to check if the JSON is valid before attempting to serialize, as JSONSerialization.data will not throw an exception that can be caught, and will cause the application to crash if it fails.
28 | if JSONSerialization.isValidJSONObject(data) {
29 | return try JSONSerialization.data(withJSONObject: data)
30 | } else {
31 | throw CapacitorUrlRequest.CapacitorUrlRequestError.serializationError("[ data ] argument for request of content-type [ application/json ] must be serializable to JSON")
32 | }
33 | }
34 |
35 | private func getRequestDataAsFormUrlEncoded(_ data: JSValue) throws -> Data? {
36 | guard var components = URLComponents(url: request.url!, resolvingAgainstBaseURL: false) else { return nil }
37 | components.queryItems = []
38 |
39 | guard let obj = data as? JSObject else {
40 | // Throw, other data types explicitly not supported
41 | throw CapacitorUrlRequestError.serializationError("[ data ] argument for request with content-type [ multipart/form-data ] may only be a plain javascript object")
42 | }
43 |
44 | obj.keys.forEach { (key: String) in
45 | components.queryItems?.append(URLQueryItem(name: key, value: "\(obj[key] ?? "")"))
46 | }
47 |
48 |
49 | if components.query != nil {
50 | return Data(components.query!.utf8)
51 | }
52 |
53 | return nil
54 | }
55 |
56 | private func getRequestDataAsMultipartFormData(_ data: JSValue) throws -> Data {
57 | guard let obj = data as? JSObject else {
58 | // Throw, other data types explicitly not supported.
59 | throw CapacitorUrlRequestError.serializationError("[ data ] argument for request with content-type [ application/x-www-form-urlencoded ] may only be a plain javascript object")
60 | }
61 |
62 | let strings: [String: String] = obj.compactMapValues { any in
63 | any as? String
64 | }
65 |
66 | var data = Data()
67 | let boundary = UUID().uuidString
68 | let contentType = "multipart/form-data; boundary=\(boundary)"
69 | request.setValue(contentType, forHTTPHeaderField: "Content-Type")
70 | headers["Content-Type"] = contentType
71 |
72 | strings.forEach { key, value in
73 | data.append("\r\n--\(boundary)\r\n".data(using: .utf8)!)
74 | data.append("Content-Disposition: form-data; name=\"\(key)\"\r\n\r\n".data(using: .utf8)!)
75 | data.append(value.data(using: .utf8)!)
76 | }
77 | data.append("\r\n--\(boundary)--\r\n".data(using: .utf8)!)
78 |
79 | return data
80 | }
81 |
82 | private func getRequestDataAsString(_ data: JSValue) throws -> Data {
83 | guard let stringData = data as? String else {
84 | throw CapacitorUrlRequestError.serializationError("[ data ] argument could not be parsed as string")
85 | }
86 | return Data(stringData.utf8)
87 | }
88 |
89 | func getRequestHeader(_ index: String) -> Any? {
90 | var normalized = [:] as [String:Any]
91 | self.headers.keys.forEach { (key: String) in
92 | normalized[key.lowercased()] = self.headers[key]
93 | }
94 |
95 | return normalized[index.lowercased()]
96 | }
97 |
98 | func getRequestData(_ body: JSValue, _ contentType: String) throws -> Data? {
99 | // If data can be parsed directly as a string, return that without processing.
100 | if let strVal = try? getRequestDataAsString(body) {
101 | return strVal
102 | } else if contentType.contains("application/json") {
103 | return try getRequestDataAsJson(body)
104 | } else if contentType.contains("application/x-www-form-urlencoded") {
105 | return try getRequestDataAsFormUrlEncoded(body)
106 | } else if contentType.contains("multipart/form-data") {
107 | return try getRequestDataAsMultipartFormData(body)
108 | } else {
109 | throw CapacitorUrlRequestError.serializationError("[ data ] argument could not be parsed for content type [ \(contentType) ]")
110 | }
111 | }
112 |
113 | public func setRequestHeaders(_ headers: [String: String]) {
114 | headers.keys.forEach { (key: String) in
115 | let value = headers[key]
116 | request.addValue(value!, forHTTPHeaderField: key)
117 | self.headers[key] = value
118 | }
119 | }
120 |
121 | public func setRequestBody(_ body: JSValue) throws {
122 | let contentType = self.getRequestHeader("Content-Type") as? String
123 |
124 | if contentType != nil {
125 | request.httpBody = try getRequestData(body, contentType!)
126 | }
127 | }
128 |
129 | public func setContentType(_ data: String?) {
130 | request.setValue(data, forHTTPHeaderField: "Content-Type")
131 | }
132 |
133 | public func setTimeout(_ timeout: TimeInterval) {
134 | request.timeoutInterval = timeout;
135 | }
136 |
137 | public func getUrlRequest() -> URLRequest {
138 | return request;
139 | }
140 |
141 | public func urlSession(_ session: URLSession, task: URLSessionTask, willPerformHTTPRedirection response: HTTPURLResponse, newRequest request: URLRequest, completionHandler: @escaping (URLRequest?) -> Void) {
142 | completionHandler(nil)
143 | }
144 |
145 | public func getUrlSession(_ call: CAPPluginCall) -> URLSession {
146 | let disableRedirects = call.getBool("disableRedirects") ?? false
147 | if (!disableRedirects) {
148 | return URLSession.shared
149 | }
150 | return URLSession(configuration: URLSessionConfiguration.default, delegate: self, delegateQueue: nil)
151 | }
152 | }
153 |
--------------------------------------------------------------------------------
/ios/Plugin/FilesystemUtils.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 | import MobileCoreServices
3 |
4 | enum FilesystemError: Error {
5 | case fileNotFound(String)
6 | case invalidPath(String)
7 | case parentFolderNotExists(String)
8 | case saveError(String)
9 | }
10 |
11 | class FilesystemUtils {
12 | /**
13 | * Get the SearchPathDirectory corresponding to the JS string
14 | */
15 | static func getDirectory(directory: String) -> FileManager.SearchPathDirectory {
16 | switch directory {
17 | case "DOCUMENTS":
18 | return .documentDirectory
19 | case "APPLICATION":
20 | return .applicationDirectory
21 | case "CACHE":
22 | return .cachesDirectory
23 | case "DOWNLOADS":
24 | return .downloadsDirectory
25 | default:
26 | return .documentDirectory
27 | }
28 | }
29 |
30 | /**
31 | * Get the URL for this file, supporting file:// paths and
32 | * files with directory mappings.
33 | */
34 | static func getFileUrl(_ path: String, _ directoryOption: String) -> URL? {
35 | if path.starts(with: "file://") {
36 | return URL(string: path)
37 | }
38 |
39 | let directory = FilesystemUtils.getDirectory(directory: directoryOption)
40 |
41 | guard let dir = FileManager.default.urls(for: directory, in: .userDomainMask).first else {
42 | return nil
43 | }
44 |
45 | return dir.appendingPathComponent(path)
46 | }
47 |
48 | static func createDirectoryForFile(_ fileUrl: URL, _ recursive: Bool) throws {
49 | if !FileManager.default.fileExists(atPath: fileUrl.deletingLastPathComponent().absoluteString) {
50 | if recursive {
51 | try FileManager.default.createDirectory(at: fileUrl.deletingLastPathComponent(), withIntermediateDirectories: recursive, attributes: nil)
52 | } else {
53 | throw FilesystemError.parentFolderNotExists("Parent folder doesn't exist")
54 | }
55 | }
56 | }
57 |
58 | /**
59 | * Read a file as a string at the given directory and with the given encoding
60 | */
61 | static func readFileString(_ path: String, _ directory: String, _ encoding: String?) throws -> String {
62 | guard let fileUrl = FilesystemUtils.getFileUrl(path, directory) else {
63 | throw FilesystemError.fileNotFound("No such file exists")
64 | }
65 | if encoding != nil {
66 | let data = try String(contentsOf: fileUrl, encoding: .utf8)
67 | return data
68 | } else {
69 | let data = try Data(contentsOf: fileUrl)
70 | return data.base64EncodedString()
71 | }
72 | }
73 |
74 | static func writeFileString(_ path: String, _ directory: String, _ encoding: String?, _ data: String, _ recursive: Bool = false) throws -> URL {
75 |
76 | guard let fileUrl = FilesystemUtils.getFileUrl(path, directory) else {
77 | throw FilesystemError.invalidPath("Invlid path")
78 | }
79 |
80 | if !FileManager.default.fileExists(atPath: fileUrl.deletingLastPathComponent().absoluteString) {
81 | if recursive {
82 | try FileManager.default.createDirectory(at: fileUrl.deletingLastPathComponent(), withIntermediateDirectories: recursive, attributes: nil)
83 | } else {
84 | throw FilesystemError.parentFolderNotExists("Parent folder doesn't exist")
85 | }
86 | }
87 |
88 | if encoding != nil {
89 | try data.write(to: fileUrl, atomically: false, encoding: .utf8)
90 | } else {
91 | let cleanData = getCleanBase64Data(data)
92 | if let base64Data = Data(base64Encoded: cleanData) {
93 | try base64Data.write(to: fileUrl)
94 | } else {
95 | throw FilesystemError.saveError("Unable to save file")
96 | }
97 | }
98 |
99 | return fileUrl
100 | }
101 |
102 |
103 | static func getCleanBase64Data(_ data: String) -> String {
104 | let dataParts = data.split(separator: ",")
105 | var cleanData = data
106 | if dataParts.count > 0 {
107 | cleanData = String(dataParts.last!)
108 | }
109 | return cleanData
110 | }
111 |
112 | static func mimeTypeForPath(path: String) -> String {
113 | let url = NSURL(fileURLWithPath: path)
114 | let pathExtension = url.pathExtension
115 | if let uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, pathExtension! as NSString, nil)?.takeRetainedValue() {
116 | if let mimetype = UTTypeCopyPreferredTagWithClass(uti, kUTTagClassMIMEType)?.takeRetainedValue() {
117 | return mimetype as String
118 | }
119 | }
120 | return "application/octet-stream"
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/ios/Plugin/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | $(CURRENT_PROJECT_VERSION)
21 | NSPrincipalClass
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/ios/Plugin/Plugin.h:
--------------------------------------------------------------------------------
1 | #import
2 |
3 | //! Project version number for Plugin.
4 | FOUNDATION_EXPORT double PluginVersionNumber;
5 |
6 | //! Project version string for Plugin.
7 | FOUNDATION_EXPORT const unsigned char PluginVersionString[];
8 |
9 | // In this header, you should import all the public headers of your framework using statements like #import
10 |
--------------------------------------------------------------------------------
/ios/Plugin/Plugin.m:
--------------------------------------------------------------------------------
1 | #import
2 | #import
3 |
4 | CAP_PLUGIN(HttpPlugin, "Http",
5 | CAP_PLUGIN_METHOD(request, CAPPluginReturnPromise);
6 | CAP_PLUGIN_METHOD(get, CAPPluginReturnPromise);
7 | CAP_PLUGIN_METHOD(post, CAPPluginReturnPromise);
8 | CAP_PLUGIN_METHOD(put, CAPPluginReturnPromise);
9 | CAP_PLUGIN_METHOD(patch, CAPPluginReturnPromise);
10 | CAP_PLUGIN_METHOD(del, CAPPluginReturnPromise);
11 | CAP_PLUGIN_METHOD(setCookie, CAPPluginReturnPromise);
12 | CAP_PLUGIN_METHOD(getCookiesMap, CAPPluginReturnPromise);
13 | CAP_PLUGIN_METHOD(getCookies, CAPPluginReturnPromise);
14 | CAP_PLUGIN_METHOD(getCookie, CAPPluginReturnPromise);
15 | CAP_PLUGIN_METHOD(deleteCookie, CAPPluginReturnPromise);
16 | CAP_PLUGIN_METHOD(clearCookies, CAPPluginReturnPromise);
17 | CAP_PLUGIN_METHOD(clearAllCookies, CAPPluginReturnPromise);
18 | CAP_PLUGIN_METHOD(downloadFile, CAPPluginReturnPromise);
19 | CAP_PLUGIN_METHOD(uploadFile, CAPPluginReturnPromise);
20 | )
21 |
--------------------------------------------------------------------------------
/ios/Plugin/Plugin.swift:
--------------------------------------------------------------------------------
1 | import Capacitor
2 | import Foundation
3 |
4 | @objc(HttpPlugin) public class HttpPlugin: CAPPlugin {
5 | var cookieManager: CapacitorCookieManager? = nil
6 | var capConfig: InstanceConfiguration? = nil
7 |
8 | private func getServerUrl(_ call: CAPPluginCall) -> URL? {
9 | guard let urlString = call.getString("url") else {
10 | call.reject("Invalid URL. Check that \"url\" is passed in correctly")
11 | return nil
12 | }
13 |
14 | let url = URL(string: urlString)
15 | return url;
16 | }
17 |
18 | @objc override public func load() {
19 | cookieManager = CapacitorCookieManager()
20 | capConfig = bridge?.config
21 | }
22 |
23 | @objc func http(_ call: CAPPluginCall, _ httpMethod: String?) {
24 | // Protect against bad values from JS before calling request
25 | guard let u = call.getString("url") else { return call.reject("Must provide a URL"); }
26 | guard let _ = httpMethod ?? call.getString("method") else { return call.reject("Must provide an HTTP Method"); }
27 | guard var _ = URL(string: u) else { return call.reject("Invalid URL"); }
28 |
29 | do {
30 | try HttpRequestHandler.request(call, httpMethod)
31 | } catch let e {
32 | call.reject(e.localizedDescription)
33 | }
34 | }
35 |
36 | @objc func request(_ call: CAPPluginCall) {
37 | http(call, nil)
38 | }
39 |
40 | @objc func get(_ call: CAPPluginCall) {
41 | http(call, "GET")
42 | }
43 |
44 | @objc func post(_ call: CAPPluginCall) {
45 | http(call, "POST")
46 | }
47 |
48 | @objc func put(_ call: CAPPluginCall) {
49 | http(call, "PUT")
50 | }
51 |
52 | @objc func patch(_ call: CAPPluginCall) {
53 | http(call, "PATCH")
54 | }
55 |
56 | @objc func del(_ call: CAPPluginCall) {
57 | http(call, "DELETE")
58 | }
59 |
60 | @objc func downloadFile(_ call: CAPPluginCall) {
61 | // Protect against bad values from JS before calling request
62 | guard let u = call.getString("url") else { return call.reject("Must provide a URL") }
63 | guard let _ = call.getString("filePath") else { return call.reject("Must provide a file path to download the file to") }
64 | guard let _ = URL(string: u) else { return call.reject("Invalid URL") }
65 |
66 | let progressEmitter: HttpRequestHandler.ProgressEmitter = {bytes, contentLength in
67 | self.notifyListeners("progress", data: [
68 | "type": "DOWNLOAD",
69 | "url": u,
70 | "bytes": bytes,
71 | "contentLength": contentLength
72 | ])
73 | }
74 |
75 | do {
76 | try HttpRequestHandler.download(call, updateProgress: progressEmitter)
77 | } catch let e {
78 | call.reject(e.localizedDescription)
79 | }
80 | }
81 |
82 | @objc func uploadFile(_ call: CAPPluginCall) {
83 | // Protect against bad values from JS before calling request
84 | let fd = call.getString("fileDirectory") ?? "DOCUMENTS"
85 | guard let u = call.getString("url") else { return call.reject("Must provide a URL") }
86 | guard let fp = call.getString("filePath") else { return call.reject("Must provide a file path to download the file to") }
87 | guard let _ = URL(string: u) else { return call.reject("Invalid URL") }
88 | guard let _ = FilesystemUtils.getFileUrl(fp, fd) else { return call.reject("Unable to get file URL") }
89 |
90 | do {
91 | try HttpRequestHandler.upload(call)
92 | } catch let e {
93 | call.reject(e.localizedDescription)
94 | }
95 | }
96 |
97 | @objc func setCookie(_ call: CAPPluginCall) {
98 | guard let key = call.getString("key") else { return call.reject("Must provide key") }
99 | guard let value = call.getString("value") else { return call.reject("Must provide value") }
100 |
101 | let url = getServerUrl(call)
102 | if url != nil {
103 | cookieManager!.setCookie(url!, key, cookieManager!.encode(value))
104 | call.resolve()
105 | }
106 | }
107 |
108 | @objc func getCookiesMap(_ call: CAPPluginCall) {
109 | let url = getServerUrl(call)
110 | if url != nil {
111 | let cookies = cookieManager!.getCookies(url!)
112 | var cookiesMap: [String: String] = [:]
113 | for cookie in cookies {
114 | cookiesMap[cookie.name] = cookie.value
115 | }
116 | call.resolve(cookiesMap)
117 | }
118 | }
119 |
120 | @objc func getCookies(_ call: CAPPluginCall) {
121 | let url = getServerUrl(call)
122 | if url != nil {
123 | let cookies = cookieManager!.getCookies(url!)
124 | let output = cookies.map { (cookie: HTTPCookie) -> [String: String] in
125 | return [
126 | "key": cookie.name,
127 | "value": cookie.value,
128 | ]
129 | }
130 | call.resolve([
131 | "cookies": output
132 | ])
133 | }
134 | }
135 |
136 | @objc func getCookie(_ call: CAPPluginCall) {
137 | guard let key = call.getString("key") else { return call.reject("Must provide key") }
138 | let url = getServerUrl(call)
139 | if url != nil {
140 | let cookie = cookieManager!.getCookie(url!, key)
141 | call.resolve([
142 | "key": cookie.name,
143 | "value": cookieManager!.decode(cookie.value)
144 | ])
145 | }
146 | }
147 |
148 | @objc func deleteCookie(_ call: CAPPluginCall) {
149 | guard let key = call.getString("key") else { return call.reject("Must provide key") }
150 | let url = getServerUrl(call)
151 | if url != nil {
152 | let jar = HTTPCookieStorage.shared
153 |
154 | let cookie = jar.cookies(for: url!)?.first(where: { (cookie) -> Bool in
155 | return cookie.name == key
156 | })
157 |
158 | if cookie != nil {
159 | jar.deleteCookie(cookie!)
160 | }
161 |
162 | call.resolve()
163 | }
164 | }
165 |
166 | @objc func clearCookies(_ call: CAPPluginCall) {
167 | let url = getServerUrl(call)
168 | if url != nil {
169 | cookieManager!.clearCookies(url!)
170 | call.resolve()
171 | }
172 | }
173 |
174 | @objc func clearAllCookies(_ call: CAPPluginCall) {
175 | cookieManager!.clearAllCookies()
176 | call.resolve()
177 | }
178 | }
179 |
--------------------------------------------------------------------------------
/ios/PluginTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
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 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/ios/PluginTests/PluginTests.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | import Capacitor
3 | @testable import Plugin
4 |
5 | class PluginTests: XCTestCase {
6 |
7 | override func setUp() {
8 | super.setUp()
9 | // Put setup code here. This method is called before the invocation of each test method in the class.
10 | }
11 |
12 | override func tearDown() {
13 | // Put teardown code here. This method is called after the invocation of each test method in the class.
14 | super.tearDown()
15 | }
16 |
17 | func testEcho() {
18 | // This is an example of a functional test case for a plugin.
19 | // Use XCTAssert and related functions to verify your tests produce the correct results.
20 |
21 | let value = "Hello, World!"
22 | let plugin = MyPlugin()
23 |
24 | let call = CAPPluginCall(callbackId: "test", options: [
25 | "value": value
26 | ], success: { (result, call) in
27 | let resultValue = result!.data["value"] as? String
28 | XCTAssertEqual(value, resultValue)
29 | }, error: { (err) in
30 | XCTFail("Error shouldn't have been called")
31 | })
32 |
33 | plugin.echo(call!)
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/ios/Podfile:
--------------------------------------------------------------------------------
1 | platform :ios, '12.0'
2 |
3 | def capacitor_pods
4 | # Comment the next line if you're not using Swift and don't want to use dynamic frameworks
5 | use_frameworks!
6 | pod 'Capacitor', path: '../node_modules/@capacitor/ios'
7 | pod 'CapacitorCordova', path: '../node_modules/@capacitor/ios'
8 | end
9 |
10 | target 'Plugin' do
11 | capacitor_pods
12 | end
13 |
14 | target 'PluginTests' do
15 | capacitor_pods
16 | end
17 |
--------------------------------------------------------------------------------
/ios/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - Capacitor (3.0.0):
3 | - CapacitorCordova
4 | - CapacitorCordova (3.0.0)
5 |
6 | DEPENDENCIES:
7 | - "Capacitor (from `../node_modules/@capacitor/ios`)"
8 | - "CapacitorCordova (from `../node_modules/@capacitor/ios`)"
9 |
10 | EXTERNAL SOURCES:
11 | Capacitor:
12 | :path: "../node_modules/@capacitor/ios"
13 | CapacitorCordova:
14 | :path: "../node_modules/@capacitor/ios"
15 |
16 | SPEC CHECKSUMS:
17 | Capacitor: 06cd8cd01340f5b162e9528bf5569d87a6f29009
18 | CapacitorCordova: 183c8d1af3851da6d7a371f273462c8e64e15464
19 |
20 | PODFILE CHECKSUM: b7b76f9a39066f9f3276fd95a6e5ca9625f20b3f
21 |
22 | COCOAPODS: 1.11.0
23 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@capacitor-community/http",
3 | "version": "1.4.1",
4 | "description": "A native HTTP plugin for CORS-free requests and file transfers",
5 | "main": "dist/plugin.cjs.js",
6 | "module": "dist/esm/index.js",
7 | "types": "dist/esm/index.d.ts",
8 | "scripts": {
9 | "build": "npm run clean && tsc && rollup -c rollup.config.js",
10 | "ios:build": "cd ios && pod install && cd ..",
11 | "docs": "typedoc src/web.ts src/definitions.ts",
12 | "clean": "rimraf ./dist",
13 | "watch": "tsc --watch",
14 | "fmt": "npm run prettier -- --write",
15 | "prettier": "prettier \"**/*.{css,html,ts,js,java}\"",
16 | "prepublishOnly": "npm run build && npm run ios:build",
17 | "prepare": "husky install"
18 | },
19 | "author": "Max Lynch , Thomas Vidas ",
20 | "license": "MIT",
21 | "dependencies": {
22 | "@capacitor/android": "^3.0.0",
23 | "@capacitor/core": "^3.0.0",
24 | "@capacitor/filesystem": "^1.0.0",
25 | "@capacitor/ios": "^3.0.0"
26 | },
27 | "devDependencies": {
28 | "@ionic/prettier-config": "^1.0.1",
29 | "all-contributors-cli": "^6.20.0",
30 | "husky": "^6.0.0",
31 | "prettier": "^2.3.0",
32 | "prettier-plugin-java": "^1.1.1",
33 | "pretty-quick": "^3.1.0",
34 | "rimraf": "^3.0.2",
35 | "rollup": "^2.50.0",
36 | "typedoc": "^0.20.36",
37 | "typescript": "^4.2.4"
38 | },
39 | "husky": {
40 | "hooks": {
41 | "pre-commit": "pretty-quick --staged"
42 | }
43 | },
44 | "files": [
45 | "dist/",
46 | "ios/",
47 | "android/",
48 | "CapacitorCommunityHttp.podspec"
49 | ],
50 | "keywords": [
51 | "capacitor",
52 | "plugin",
53 | "native"
54 | ],
55 | "prettier": "@ionic/prettier-config",
56 | "capacitor": {
57 | "ios": {
58 | "src": "ios"
59 | },
60 | "android": {
61 | "src": "android"
62 | }
63 | },
64 | "repository": {
65 | "type": "git",
66 | "url": "https://github.com/capacitor-community/http"
67 | },
68 | "bugs": {
69 | "url": "https://github.com/capacitor-community/http/issues"
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/rollup.config.js:
--------------------------------------------------------------------------------
1 | export default {
2 | input: 'dist/esm/index.js',
3 | output: [
4 | {
5 | file: 'dist/plugin.js',
6 | format: 'iife',
7 | name: 'capacitorCommunityHttp',
8 | globals: {
9 | '@capacitor/core': 'capacitorExports',
10 | },
11 | sourcemap: true,
12 | inlineDynamicImports: true,
13 | },
14 | {
15 | file: 'dist/plugin.cjs.js',
16 | format: 'cjs',
17 | sourcemap: true,
18 | inlineDynamicImports: true,
19 | },
20 | ],
21 | external: ['@capacitor/core'],
22 | };
23 |
--------------------------------------------------------------------------------
/src/cookie.ts:
--------------------------------------------------------------------------------
1 | import { HttpCookie, HttpCookieOptions } from './definitions';
2 | import { encode, decode } from './utils';
3 |
4 | /**
5 | * Set a cookie
6 | * @param key The key to set
7 | * @param value The value to set
8 | * @param options Optional additional parameters
9 | */
10 | export const setCookie = (
11 | key: string,
12 | value: any,
13 | options: HttpCookieOptions = {},
14 | ): void => {
15 | // Safely Encoded Key/Value
16 | const encodedKey = encode(key);
17 | const encodedValue = encode(value);
18 |
19 | // Clean & sanitize options
20 | const expires = `; expires=${(options.expires || '').replace(
21 | 'expires=',
22 | '',
23 | )}`; // Default is "; expires="
24 | const path = (options.path || '/').replace('path=', ''); // Default is "path=/"
25 |
26 | document.cookie = `${encodedKey}=${
27 | encodedValue || ''
28 | }${expires}; path=${path}`;
29 | };
30 |
31 | /**
32 | * Gets all HttpCookies
33 | */
34 | export const getCookies = (): HttpCookie[] => {
35 | const output: HttpCookie[] = [];
36 | const map: any = {};
37 | if (!document.cookie) {
38 | return output;
39 | }
40 |
41 | const cookies = document.cookie.split(';') || [];
42 | for (const cookie of cookies) {
43 | // Replace first "=" with CAP_COOKIE to prevent splitting on additional "="
44 | let [k, v] = cookie.replace(/=/, 'CAP_COOKIE').split('CAP_COOKIE');
45 | k = decode(k).trim();
46 | v = decode(v).trim();
47 | map[k] = v;
48 | }
49 |
50 | const entries: [string, any][] = Object.entries(map);
51 | for (const [key, value] of entries) {
52 | output.push({
53 | key,
54 | value,
55 | });
56 | }
57 |
58 | return output;
59 | };
60 |
61 | /**
62 | * Gets a single HttpCookie given a key
63 | */
64 | export const getCookie = (key: string): HttpCookie => {
65 | const cookies = getCookies();
66 | for (const cookie of cookies) {
67 | if (cookie.key === key) {
68 | return cookie;
69 | }
70 | }
71 |
72 | return {
73 | key,
74 | value: '',
75 | };
76 | };
77 |
78 | /**
79 | * Deletes a cookie given a key
80 | * @param key The key of the cookie to delete
81 | */
82 | export const deleteCookie = (key: string): void => {
83 | document.cookie = `${key}=; Max-Age=0`;
84 | };
85 |
86 | /**
87 | * Clears out cookies by setting them to expire immediately
88 | */
89 | export const clearCookies = (): void => {
90 | const cookies = document.cookie.split(';') || [];
91 | for (const cookie of cookies) {
92 | document.cookie = cookie
93 | .replace(/^ +/, '')
94 | .replace(/=.*/, `=;expires=${new Date().toUTCString()};path=/`);
95 | }
96 | };
97 |
--------------------------------------------------------------------------------
/src/definitions.ts:
--------------------------------------------------------------------------------
1 | import type { PluginListenerHandle } from '@capacitor/core';
2 | import { Directory } from '@capacitor/filesystem';
3 |
4 | type HttpResponseType = 'arraybuffer' | 'blob' | 'json' | 'text' | 'document';
5 |
6 | export interface HttpPlugin {
7 | request(options: HttpOptions): Promise;
8 | get(options: HttpOptions): Promise;
9 | post(options: HttpOptions): Promise;
10 | put(options: HttpOptions): Promise;
11 | patch(options: HttpOptions): Promise;
12 | del(options: HttpOptions): Promise;
13 |
14 | setCookie(options: HttpSetCookieOptions): Promise;
15 | getCookie(options: HttpSingleCookieOptions): Promise;
16 | getCookies(options: HttpMultiCookiesOptions): Promise;
17 | getCookiesMap(options: HttpMultiCookiesOptions): Promise;
18 | clearCookies(options: HttpMultiCookiesOptions): Promise;
19 | clearAllCookies(): Promise;
20 | deleteCookie(options: HttpSingleCookieOptions): Promise;
21 |
22 | uploadFile(options: HttpUploadFileOptions): Promise;
23 | downloadFile(
24 | options: HttpDownloadFileOptions,
25 | ): Promise;
26 |
27 | addListener(
28 | eventName: 'progress',
29 | listenerFunc: HttpProgressListener,
30 | ): Promise & PluginListenerHandle;
31 |
32 | removeAllListeners(): Promise;
33 | }
34 |
35 | export interface HttpOptions {
36 | url: string;
37 | method?: string;
38 | params?: HttpParams;
39 | data?: any;
40 | headers?: HttpHeaders;
41 | /**
42 | * How long to wait to read additional data. Resets each time new
43 | * data is received
44 | */
45 | readTimeout?: number;
46 | /**
47 | * How long to wait for the initial connection.
48 | */
49 | connectTimeout?: number;
50 | /**
51 | * Sets whether automatic HTTP redirects should be disabled
52 | */
53 | disableRedirects?: boolean;
54 | /**
55 | * Extra arguments for fetch when running on the web
56 | */
57 | webFetchExtra?: RequestInit;
58 | /**
59 | * This is used to parse the response appropriately before returning it to
60 | * the requestee. If the response content-type is "json", this value is ignored.
61 | */
62 | responseType?: HttpResponseType;
63 | /**
64 | * Use this option if you need to keep the URL unencoded in certain cases
65 | * (already encoded, azure/firebase testing, etc.). The default is _true_.
66 | */
67 | shouldEncodeUrlParams?: boolean;
68 | }
69 |
70 | export interface HttpParams {
71 | [key: string]: string | string[];
72 | }
73 |
74 | export interface HttpHeaders {
75 | [key: string]: string;
76 | }
77 |
78 | export interface HttpResponse {
79 | data: any;
80 | status: number;
81 | headers: HttpHeaders;
82 | url: string;
83 | }
84 |
85 | export interface HttpDownloadFileOptions extends HttpOptions {
86 | /**
87 | * The path the downloaded file should be moved to
88 | */
89 | filePath: string;
90 | /**
91 | * Optionally, the directory to put the file in
92 | *
93 | * If this option is used, filePath can be a relative path rather than absolute
94 | */
95 | fileDirectory?: Directory;
96 | /**
97 | * Optionally, the switch that enables notifying listeners about downloaded progress
98 | *
99 | * If this option is used, progress event should be dispatched on every chunk received
100 | */
101 | progress?: Boolean;
102 | }
103 |
104 | export interface HttpUploadFileOptions extends HttpOptions {
105 | /**
106 | * The URL to upload the file to
107 | */
108 | url: string;
109 | /**
110 | * The field name to upload the file with
111 | */
112 | name: string;
113 | /**
114 | * For uploading a file on the web, a JavaScript Blob to upload
115 | */
116 | blob?: Blob;
117 | /**
118 | * For uploading a file natively, the path to the file on disk to upload
119 | */
120 | filePath?: string;
121 | /**
122 | * Optionally, the directory to look for the file in.
123 | *
124 | * If this option is used, filePath can be a relative path rather than absolute
125 | */
126 | fileDirectory?: Directory;
127 | }
128 |
129 | export interface HttpCookie {
130 | key: string;
131 | value: string;
132 | }
133 |
134 | export interface HttpCookieMap {
135 | [key: string]: any;
136 | }
137 |
138 | export interface HttpCookieOptions {
139 | url?: string;
140 | path?: string;
141 | expires?: string;
142 | }
143 |
144 | export interface HttpSingleCookieOptions {
145 | url: string;
146 | key: string;
147 | }
148 |
149 | export interface HttpSetCookieOptions {
150 | url: string;
151 | key: string;
152 | value: string;
153 | path?: string;
154 | expires?: string;
155 | }
156 |
157 | export interface HttpMultiCookiesOptions {
158 | url: string;
159 | }
160 |
161 | export interface HttpCookieExtraOptions {
162 | path?: string;
163 | expires?: string;
164 | }
165 |
166 | export interface HttpGetCookiesResult {
167 | cookies: HttpCookie[];
168 | }
169 |
170 | export interface HttpDownloadFileResult {
171 | path?: string;
172 | blob?: Blob;
173 | }
174 |
175 | export interface HttpUploadFileResult extends HttpResponse {}
176 |
177 | export type ProgressType = 'DOWNLOAD' | 'UPLOAD';
178 |
179 | export interface ProgressStatus {
180 | type: ProgressType;
181 | url: string;
182 | bytes: number;
183 | contentLength: number;
184 | }
185 |
186 | export type HttpProgressListener = (progress: ProgressStatus) => void;
187 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | import { registerPlugin } from '@capacitor/core';
2 | import type { HttpPlugin } from './definitions';
3 |
4 | const Http = registerPlugin('Http', {
5 | web: () => import('./web').then(m => new m.HttpWeb()),
6 | electron: () => import('./web').then(m => new m.HttpWeb()),
7 | });
8 |
9 | export * from './definitions';
10 | export { Http };
11 |
--------------------------------------------------------------------------------
/src/request.ts:
--------------------------------------------------------------------------------
1 | import type {
2 | HttpOptions,
3 | HttpResponse,
4 | HttpParams,
5 | HttpHeaders,
6 | } from './definitions';
7 | import { readBlobAsBase64 } from './utils';
8 |
9 | /**
10 | * Normalize an HttpHeaders map by lowercasing all of the values
11 | * @param headers The HttpHeaders object to normalize
12 | */
13 | const normalizeHttpHeaders = (headers: HttpHeaders = {}): HttpHeaders => {
14 | const originalKeys = Object.keys(headers);
15 | const loweredKeys = Object.keys(headers).map(k => k.toLocaleLowerCase());
16 | const normalized = loweredKeys.reduce((acc, key, index) => {
17 | acc[key] = headers[originalKeys[index]];
18 | return acc;
19 | }, {});
20 | return normalized;
21 | };
22 |
23 | /**
24 | * Builds a string of url parameters that
25 | * @param params A map of url parameters
26 | * @param shouldEncode true if you should encodeURIComponent() the values (true by default)
27 | */
28 | const buildUrlParams = (
29 | params?: HttpParams,
30 | shouldEncode: boolean = true,
31 | ): string | null => {
32 | if (!params) return null;
33 |
34 | const output = Object.entries(params).reduce((accumulator, entry) => {
35 | const [key, value] = entry;
36 |
37 | let encodedValue: string;
38 | let item: string;
39 | if (Array.isArray(value)) {
40 | item = '';
41 | value.forEach(str => {
42 | encodedValue = shouldEncode ? encodeURIComponent(str) : str;
43 | item += `${key}=${encodedValue}&`;
44 | });
45 | // last character will always be "&" so slice it off
46 | item.slice(0, -1);
47 | } else {
48 | encodedValue = shouldEncode ? encodeURIComponent(value) : value;
49 | item = `${key}=${encodedValue}`;
50 | }
51 |
52 | return `${accumulator}&${item}`;
53 | }, '');
54 |
55 | // Remove initial "&" from the reduce
56 | return output.substr(1);
57 | };
58 |
59 | /**
60 | * Build the RequestInit object based on the options passed into the initial request
61 | * @param options The Http plugin options
62 | * @param extra Any extra RequestInit values
63 | */
64 | export const buildRequestInit = (
65 | options: HttpOptions,
66 | extra: RequestInit = {},
67 | ): RequestInit => {
68 | const output: RequestInit = {
69 | method: options.method || 'GET',
70 | headers: options.headers,
71 | ...extra,
72 | };
73 |
74 | // Get the content-type
75 | const headers = normalizeHttpHeaders(options.headers);
76 | const type = headers['content-type'] || '';
77 |
78 | // If body is already a string, then pass it through as-is.
79 | if (typeof options.data === 'string') {
80 | output.body = options.data;
81 | }
82 | // Build request initializers based off of content-type
83 | else if (type.includes('application/x-www-form-urlencoded')) {
84 | const params = new URLSearchParams();
85 | for (const [key, value] of Object.entries(options.data || {})) {
86 | params.set(key, value as any);
87 | }
88 | output.body = params.toString();
89 | } else if (type.includes('multipart/form-data')) {
90 | const form = new FormData();
91 | if (options.data instanceof FormData) {
92 | options.data.forEach((value, key) => {
93 | form.append(key, value);
94 | });
95 | } else {
96 | for (let key of Object.keys(options.data)) {
97 | form.append(key, options.data[key]);
98 | }
99 | }
100 | output.body = form;
101 | const headers = new Headers(output.headers);
102 | headers.delete('content-type'); // content-type will be set by `window.fetch` to includy boundary
103 | output.headers = headers;
104 | } else if (
105 | type.includes('application/json') ||
106 | typeof options.data === 'object'
107 | ) {
108 | output.body = JSON.stringify(options.data);
109 | }
110 |
111 | return output;
112 | };
113 |
114 | /**
115 | * Perform an Http request given a set of options
116 | * @param options Options to build the HTTP request
117 | */
118 | export const request = async (options: HttpOptions): Promise => {
119 | const requestInit = buildRequestInit(options, options.webFetchExtra);
120 | const urlParams = buildUrlParams(
121 | options.params,
122 | options.shouldEncodeUrlParams,
123 | );
124 | const url = urlParams ? `${options.url}?${urlParams}` : options.url;
125 |
126 | const response = await fetch(url, requestInit);
127 | const contentType = response.headers.get('content-type') || '';
128 |
129 | // Default to 'text' responseType so no parsing happens
130 | let { responseType = 'text' } = response.ok ? options : {};
131 |
132 | // If the response content-type is json, force the response to be json
133 | if (contentType.includes('application/json')) {
134 | responseType = 'json';
135 | }
136 |
137 | let data: any;
138 | switch (responseType) {
139 | case 'arraybuffer':
140 | case 'blob':
141 | const blob = await response.blob();
142 | data = await readBlobAsBase64(blob);
143 | break;
144 | case 'json':
145 | data = await response.json();
146 | break;
147 | case 'document':
148 | case 'text':
149 | default:
150 | data = await response.text();
151 | }
152 |
153 | // Convert fetch headers to Capacitor HttpHeaders
154 | const headers = {} as HttpHeaders;
155 | response.headers.forEach((value: string, key: string) => {
156 | headers[key] = value;
157 | });
158 |
159 | return {
160 | data,
161 | headers,
162 | status: response.status,
163 | url: response.url,
164 | };
165 | };
166 |
167 | /**
168 | * Perform an Http GET request given a set of options
169 | * @param options Options to build the HTTP request
170 | */
171 | export const get = async (options: HttpOptions): Promise =>
172 | request({ ...options, method: 'GET' });
173 |
174 | /**
175 | * Perform an Http POST request given a set of options
176 | * @param options Options to build the HTTP request
177 | */
178 | export const post = async (options: HttpOptions): Promise =>
179 | request({ ...options, method: 'POST' });
180 |
181 | /**
182 | * Perform an Http PUT request given a set of options
183 | * @param options Options to build the HTTP request
184 | */
185 | export const put = async (options: HttpOptions): Promise =>
186 | request({ ...options, method: 'PUT' });
187 |
188 | /**
189 | * Perform an Http PATCH request given a set of options
190 | * @param options Options to build the HTTP request
191 | */
192 | export const patch = async (options: HttpOptions): Promise =>
193 | request({ ...options, method: 'PATCH' });
194 |
195 | /**
196 | * Perform an Http DELETE request given a set of options
197 | * @param options Options to build the HTTP request
198 | */
199 | export const del = async (options: HttpOptions): Promise =>
200 | request({ ...options, method: 'DELETE' });
201 |
--------------------------------------------------------------------------------
/src/utils.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Read in a Blob value and return it as a base64 string
3 | * @param blob The blob value to convert to a base64 string
4 | */
5 | export const readBlobAsBase64 = async (blob: Blob): Promise =>
6 | new Promise((resolve, reject) => {
7 | const reader = new FileReader();
8 | reader.onload = () => {
9 | const base64String = reader.result as string;
10 | const base64StringWithoutTags = base64String.substr(
11 | base64String.indexOf(',') + 1,
12 | ); // remove prefix "data:application/pdf;base64,"
13 | resolve(base64StringWithoutTags);
14 | };
15 | reader.onerror = (error: any) => reject(error);
16 | reader.readAsDataURL(blob);
17 | });
18 |
19 | /**
20 | * Safely web encode a string value (inspired by js-cookie)
21 | * @param str The string value to encode
22 | */
23 | export const encode = (str: string) =>
24 | encodeURIComponent(str)
25 | .replace(/%(2[346B]|5E|60|7C)/g, decodeURIComponent)
26 | .replace(/[()]/g, escape);
27 |
28 | /**
29 | * Safely web decode a string value (inspired by js-cookie)
30 | * @param str The string value to decode
31 | */
32 | export const decode = (str: string): string =>
33 | str.replace(/(%[\dA-F]{2})+/gi, decodeURIComponent);
34 |
--------------------------------------------------------------------------------
/src/web.ts:
--------------------------------------------------------------------------------
1 | import type {
2 | HttpPlugin,
3 | HttpOptions,
4 | HttpResponse,
5 | HttpDownloadFileOptions,
6 | HttpDownloadFileResult,
7 | HttpUploadFileOptions,
8 | HttpUploadFileResult,
9 | HttpCookie,
10 | HttpCookieMap,
11 | HttpGetCookiesResult,
12 | HttpSetCookieOptions,
13 | HttpMultiCookiesOptions,
14 | HttpSingleCookieOptions,
15 | ProgressStatus,
16 | } from './definitions';
17 | import { WebPlugin } from '@capacitor/core';
18 | import * as Cookie from './cookie';
19 | import * as Request from './request';
20 |
21 | export class HttpWeb extends WebPlugin implements HttpPlugin {
22 | constructor() {
23 | super();
24 | }
25 |
26 | /**
27 | * Perform an Http request given a set of options
28 | * @param options Options to build the HTTP request
29 | */
30 | public request = async (options: HttpOptions): Promise =>
31 | Request.request(options);
32 |
33 | /**
34 | * Perform an Http GET request given a set of options
35 | * @param options Options to build the HTTP request
36 | */
37 | public get = async (options: HttpOptions): Promise =>
38 | Request.get(options);
39 |
40 | /**
41 | * Perform an Http POST request given a set of options
42 | * @param options Options to build the HTTP request
43 | */
44 | public post = async (options: HttpOptions): Promise =>
45 | Request.post(options);
46 |
47 | /**
48 | * Perform an Http PUT request given a set of options
49 | * @param options Options to build the HTTP request
50 | */
51 | public put = async (options: HttpOptions): Promise =>
52 | Request.put(options);
53 |
54 | /**
55 | * Perform an Http PATCH request given a set of options
56 | * @param options Options to build the HTTP request
57 | */
58 | public patch = async (options: HttpOptions): Promise =>
59 | Request.patch(options);
60 |
61 | /**
62 | * Perform an Http DELETE request given a set of options
63 | * @param options Options to build the HTTP request
64 | */
65 | public del = async (options: HttpOptions): Promise =>
66 | Request.del(options);
67 |
68 | /**
69 | * Gets all HttpCookies as a Map
70 | */
71 | public getCookiesMap = async (
72 | // @ts-ignore
73 | options: HttpMultiCookiesOptions,
74 | ): Promise => {
75 | const cookies = Cookie.getCookies();
76 | const output: HttpCookieMap = {};
77 |
78 | for (const cookie of cookies) {
79 | output[cookie.key] = cookie.value;
80 | }
81 |
82 | return output;
83 | };
84 |
85 | /**
86 | * Get all HttpCookies as an object with the values as an HttpCookie[]
87 | */
88 | public getCookies = async (
89 | options: HttpMultiCookiesOptions,
90 | ): Promise => {
91 | // @ts-ignore
92 | const { url } = options;
93 |
94 | const cookies = Cookie.getCookies();
95 | return { cookies };
96 | };
97 |
98 | /**
99 | * Set a cookie
100 | * @param key The key to set
101 | * @param value The value to set
102 | * @param options Optional additional parameters
103 | */
104 | public setCookie = async (options: HttpSetCookieOptions): Promise => {
105 | const { key, value, expires = '', path = '' } = options;
106 | Cookie.setCookie(key, value, { expires, path });
107 | };
108 |
109 | /**
110 | * Gets all cookie values unless a key is specified, then return only that value
111 | * @param key The key of the cookie value to get
112 | */
113 | public getCookie = async (
114 | options: HttpSingleCookieOptions,
115 | ): Promise => Cookie.getCookie(options.key);
116 |
117 | /**
118 | * Deletes a cookie given a key
119 | * @param key The key of the cookie to delete
120 | */
121 | public deleteCookie = async (
122 | options: HttpSingleCookieOptions,
123 | ): Promise => Cookie.deleteCookie(options.key);
124 |
125 | /**
126 | * Clears out cookies by setting them to expire immediately
127 | */
128 | public clearCookies = async (
129 | // @ts-ignore
130 | options: HttpMultiCookiesOptions,
131 | ): Promise => Cookie.clearCookies();
132 |
133 | /**
134 | * Clears out cookies by setting them to expire immediately
135 | */
136 | public clearAllCookies = async (): Promise => Cookie.clearCookies();
137 |
138 | /**
139 | * Uploads a file through a POST request
140 | * @param options TODO
141 | */
142 | public uploadFile = async (
143 | options: HttpUploadFileOptions,
144 | ): Promise => {
145 | const formData = new FormData();
146 | formData.append(options.name, options.blob || 'undefined');
147 | const fetchOptions = {
148 | ...options,
149 | body: formData,
150 | method: 'POST',
151 | };
152 |
153 | return this.post(fetchOptions);
154 | };
155 |
156 | /**
157 | * Downloads a file
158 | * @param options TODO
159 | */
160 | public downloadFile = async (
161 | options: HttpDownloadFileOptions,
162 | ): Promise => {
163 | const requestInit = Request.buildRequestInit(
164 | options,
165 | options.webFetchExtra,
166 | );
167 | const response = await fetch(options.url, requestInit);
168 | let blob: Blob;
169 |
170 | if (!options?.progress) blob = await response.blob();
171 | else if (!response?.body) blob = new Blob();
172 | else {
173 | const reader = response.body.getReader();
174 |
175 | let bytes: number = 0;
176 | let chunks: Array = [];
177 |
178 | const contentType: string | null = response.headers.get('content-type');
179 | const contentLength: number = parseInt(
180 | response.headers.get('content-length') || '0',
181 | 10,
182 | );
183 |
184 | while (true) {
185 | const { done, value } = await reader.read();
186 |
187 | if (done) break;
188 |
189 | chunks.push(value);
190 | bytes += value?.length || 0;
191 |
192 | const status: ProgressStatus = {
193 | type: 'DOWNLOAD',
194 | url: options.url,
195 | bytes,
196 | contentLength,
197 | };
198 |
199 | this.notifyListeners('progress', status);
200 | }
201 |
202 | let allChunks = new Uint8Array(bytes);
203 | let position: number = 0;
204 | for (const chunk of chunks) {
205 | if (typeof chunk === 'undefined') continue;
206 |
207 | allChunks.set(chunk, position);
208 | position += chunk.length;
209 | }
210 |
211 | blob = new Blob([allChunks.buffer], { type: contentType || undefined });
212 | }
213 |
214 | return {
215 | blob,
216 | };
217 | };
218 | }
219 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "allowUnreachableCode": false,
4 | "declaration": true,
5 | "esModuleInterop": true,
6 | "lib": ["dom", "es2017"],
7 | "module": "esnext",
8 | "moduleResolution": "node",
9 | "noFallthroughCasesInSwitch": true,
10 | "noUnusedLocals": true,
11 | "noUnusedParameters": true,
12 | "outDir": "dist/esm",
13 | "pretty": true,
14 | "sourceMap": true,
15 | "strict": true,
16 | "target": "es2017"
17 | },
18 | "files": ["src/index.ts"]
19 | }
20 |
--------------------------------------------------------------------------------