diff --git a/.github/actions/filter-out-non-e2e-enabled/action.yml b/.github/actions/filter-out-non-e2e-enabled/action.yml new file mode 100644 index 000000000..7659d709f --- /dev/null +++ b/.github/actions/filter-out-non-e2e-enabled/action.yml @@ -0,0 +1,12 @@ +name: Filter Out Non-E2E Enabled Packages +description: Action for filtering out packages that dont have E2E Tests +inputs: + paths: + description: An array of package paths + required: true +outputs: + e2e-paths: + description: An array of relative paths to packages that have e2e +runs: + using: node16 + main: main.js \ No newline at end of file diff --git a/.github/actions/filter-out-non-e2e-enabled/main.js b/.github/actions/filter-out-non-e2e-enabled/main.js new file mode 100644 index 000000000..9a80b504e --- /dev/null +++ b/.github/actions/filter-out-non-e2e-enabled/main.js @@ -0,0 +1,17 @@ +require = require('esm')(module); + +const { relative, resolve, join } = require('path'); +const { existsSync } = require('fs'); +const core = require('@actions/core') + +const { root } = require('../../../scripts/lib/repo.mjs'); +const { execute } = require('../../../scripts/lib/cli.mjs'); + +execute(async () => { + const paths = JSON.parse(core.getInput('paths', '[]')).map(f => resolve(root, f)); + const filteredPaths = paths.filter(path => existsSync(join(path, 'e2e-tests'))); + const output = JSON.stringify(filteredPaths.map(path => relative(root, path))); + + core.info(`E2E enabled paths: ${output}`); + core.setOutput('e2e-paths', output); +}); \ No newline at end of file diff --git a/.github/bot.yml b/.github/bot.yml index d2b2b893e..7d2ace5b3 100644 --- a/.github/bot.yml +++ b/.github/bot.yml @@ -26,14 +26,6 @@ tasks: config: label: 'needs reply' exclude-labeler: true - - name: add-label - on: - issues: - types: [opened] - condition: |- - !(await getTeamMembers('capacitor')).includes(payload.sender.login) - config: - label: 'triage' - name: add-platform-labels on: issues: diff --git a/.github/ionic-issue-bot.yml b/.github/ionic-issue-bot.yml new file mode 100644 index 000000000..bcf8cdb41 --- /dev/null +++ b/.github/ionic-issue-bot.yml @@ -0,0 +1,12 @@ +triage: + label: triage + removeLabelWhenProjectAssigned: false + dryRun: false + +lockClosed: + days: 30 + maxIssuesPerRun: 100 + message: > + Thanks for the issue! This issue is being locked to prevent comments that are not relevant to the original issue. + If this is still an issue with the latest version of the plugin, please create a new issue and ensure the template is fully filled out. + dryRun: false \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 557525b14..1e7d084e7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -38,7 +38,7 @@ jobs: with: files: ${{ steps.files.outputs.all }} lint: - runs-on: macos-latest + runs-on: macos-12 timeout-minutes: 30 needs: - setup @@ -58,7 +58,7 @@ jobs: - run: npm install - run: npm run lint verify-ios: - runs-on: macos-latest + runs-on: macos-12 if: needs.setup.outputs.plugins != '[]' timeout-minutes: 30 needs: @@ -66,8 +66,11 @@ jobs: - lint strategy: matrix: + xcode: + - /Applications/Xcode_13.3.1.app plugin: ${{ fromJson(needs.setup.outputs.plugins) }} steps: + - run: sudo xcode-select --switch ${{ matrix.xcode }} - uses: actions/setup-node@v1 with: node-version: 14.x diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml new file mode 100644 index 000000000..30ff12c5d --- /dev/null +++ b/.github/workflows/e2e.yml @@ -0,0 +1,166 @@ +name: E2E Tests + +on: + pull_request: + branches: + - '**' + +jobs: + setup: + if: 'false' + runs-on: ubuntu-latest + timeout-minutes: 30 + outputs: + plugins: ${{ steps.e2e-packages.outputs.e2e-paths }} + steps: + - name: Cancel Previous Runs + uses: styfle/cancel-workflow-action@ce177499ccf9fd2aded3b0426c97e5434c2e8a73 + with: + access_token: ${{ secrets.GITHUB_TOKEN }} + - uses: actions/checkout@v2 + - name: Restore Dependency Cache + id: cache-modules + uses: actions/cache@v2 + with: + path: | + node_modules + */node_modules + key: dependency-cache-${{ hashFiles('package.json', '*/package.json') }} + - run: npm install + - id: files + uses: imhoffd/get-changed-files@v2 + with: + format: 'json' + - id: packages + uses: ./.github/actions/changed-packages + with: + files: ${{ steps.files.outputs.all }} + - id: e2e-packages + uses: ./.github/actions/filter-out-non-e2e-enabled + with: + paths: ${{ steps.packages.outputs.paths }} + + e2e-ios: + runs-on: macos-11 + timeout-minutes: 35 + if: needs.setup.outputs.plugins != '[]' + needs: + - setup + strategy: + matrix: + plugin: ${{ fromJson(needs.setup.outputs.plugins) }} + defaults: + run: + working-directory: ${{ matrix.plugin }}/e2e-tests + steps: + - uses: actions/checkout@v2 + + - name: Setup NodeJS & NPM + uses: actions/setup-node@v2 + with: + node-version: 14.x + + - name: Prepare Local Package + run: npm install && npm run build && npm run pack-local + working-directory: ${{ matrix.plugin }} + env: + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + + - name: Setup NPMRC + run: echo "//registry.npmjs.org/:_authToken=${{secrets.E2E_NPM_TOKEN}}" > .npmrc + + - name: Prepare Local Package + run: npm run e2e:prepare + env: + NPM_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }} + + - name: Install Packages + run: npm install + env: + NPM_TOKEN: ${{ secrets.E2E_NPM_TOKEN }} + + - name: Run E2E Test on iOS + run: npm run e2e:ios + env: + REACT_APP_GOOGLE_MAPS_API_KEY: ${{ secrets.REACT_APP_GOOGLE_MAPS_API_KEY }} + + e2e-android: + runs-on: macos-10.15 + timeout-minutes: 35 + if: needs.setup.outputs.plugins != '[]' + needs: + - setup + strategy: + matrix: + plugin: ${{ fromJson(needs.setup.outputs.plugins) }} + defaults: + run: + working-directory: ${{ matrix.plugin }}/e2e-tests + steps: + - uses: actions/checkout@v2 + + - name: Setup NodeJS & NPM + uses: actions/setup-node@v2 + with: + node-version: 14.x + + - name: Prepare Local Package + run: npm run e2e:prepare + env: + NPM_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }} + + - name: Prepare Local Package + run: npm install && npm run build && npm run pack-local + working-directory: ${{ matrix.plugin }} + env: + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + + - name: Setup NPMRC + run: echo "//registry.npmjs.org/:_authToken=${{secrets.E2E_NPM_TOKEN}}" > .npmrc + + - name: Setup local.properties + run: echo "REACT_APP_GOOGLE_MAPS_API_KEY=${{secrets.REACT_APP_GOOGLE_MAPS_API_KEY}}" > android/local.properties + + - name: Install Packages + run: npm install + env: + NPM_TOKEN: ${{ secrets.E2E_NPM_TOKEN }} + + - name: AVD cache + uses: actions/cache@v2 + id: avd-cache + with: + path: | + ~/.android/avd/* + ~/.android/adb* + key: avd-adb-p3a-30-cache-2 + + - name: Create AVD and generate snapshot for caching + if: steps.avd-cache.outputs.cache-hit != 'true' + uses: reactivecircus/android-emulator-runner@v2 + with: + avd-name: e2eDevice + api-level: 30 + target: google_apis + arch: x86 + profile: pixel_3a + emulator-build: 7759208 + force-avd-creation: true + emulator-options: -no-window -no-audio -no-boot-anim -accel on + script: echo "Generated AVD snapshot for caching." + + - name: Run E2E Test on Android + uses: reactivecircus/android-emulator-runner@v2 + with: + avd-name: e2eDevice + api-level: 30 + target: google_apis + arch: x86 + profile: pixel_3a + working-directory: ${{ matrix.plugin }}/e2e-tests + emulator-build: 7759208 + emulator-options: -no-window -no-audio -no-boot-anim -accel on -no-snapshot-save + disable-animations: false + script: npm run e2e:android + env: + REACT_APP_GOOGLE_MAPS_API_KEY: ${{ secrets.REACT_APP_GOOGLE_MAPS_API_KEY }} diff --git a/.github/workflows/publish-android.yml b/.github/workflows/publish-android.yml index 2a0cc010e..961348736 100644 --- a/.github/workflows/publish-android.yml +++ b/.github/workflows/publish-android.yml @@ -1,22 +1,55 @@ name: Publish Native Android Libraries on: + workflow_call: + secrets: + ANDROID_OSSRH_USERNAME: + required: true + ANDROID_OSSRH_PASSWORD: + required: true + ANDROID_SIGNING_KEY_ID: + required: true + ANDROID_SIGNING_PASSWORD: + required: true + ANDROID_SIGNING_KEY: + required: true + ANDROID_SONATYPE_STAGING_PROFILE_ID: + required: true + CAP_GH_RELEASE_TOKEN: + required: true + inputs: + plugins: + description: 'Specify an optional subset of plugins to publish (space delimited)' + type: string + required: false + default: '' + capacitor-version: + description: 'Optional. Specify the version of Capacitor the plugins should depend on. Must be in mathematical notation, eg: [4.0,5.0) for 4.x versions only, or [4.0,) for 4.x versions and higher' + type: string + required: false + default: '' workflow_dispatch: inputs: plugins: description: 'Specify an optional subset of plugins to publish (space delimited)' required: false default: '' + capacitor-version: + description: 'Optional. Specify the version of Capacitor the plugins should depend on. Must be in mathematical notation, eg: [4.0,5.0) for 4.x versions only, or [4.0,) for 4.x versions and higher' + required: false + default: '' jobs: build: runs-on: ubuntu-latest + timeout-minutes: 30 permissions: contents: read packages: write steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: - ref: native-publish + fetch-depth: 0 + token: ${{ secrets.CAP_GH_RELEASE_TOKEN }} - name: set up JDK 11 uses: actions/setup-java@v2 with: @@ -28,6 +61,7 @@ jobs: working-directory: ./scripts env: GITHUB_PLUGINS: ${{ github.event.inputs.plugins }} + GITHUB_CAPACITOR_VERSION: ${{ github.event.inputs.capacitor-version }} ANDROID_OSSRH_USERNAME: ${{ secrets.ANDROID_OSSRH_USERNAME }} ANDROID_OSSRH_PASSWORD: ${{ secrets.ANDROID_OSSRH_PASSWORD }} ANDROID_SIGNING_KEY_ID: ${{ secrets.ANDROID_SIGNING_KEY_ID }} diff --git a/.github/workflows/publish-ios.yml b/.github/workflows/publish-ios.yml index 99f3becc4..eadd97652 100644 --- a/.github/workflows/publish-ios.yml +++ b/.github/workflows/publish-ios.yml @@ -8,20 +8,18 @@ on: required: true jobs: publish-ios: - runs-on: macos-11 + runs-on: macos-12 if: github.event.inputs.plugins != '[]' timeout-minutes: 30 strategy: matrix: plugin: ${{ fromJson(github.event.inputs.plugins) }} steps: - - run: sudo xcode-select --switch /Applications/Xcode_12.5.app + - run: sudo xcode-select --switch /Applications/Xcode_13.3.1.app - uses: actions/setup-node@v1 with: node-version: 14.x - uses: actions/checkout@v2 - with: - ref: native-publish - name: Install Cocoapods run: | gem install cocoapods diff --git a/.github/workflows/publish-latest.yml b/.github/workflows/publish-latest.yml new file mode 100644 index 000000000..3906a3762 --- /dev/null +++ b/.github/workflows/publish-latest.yml @@ -0,0 +1,21 @@ +name: Publish Latest + +on: workflow_dispatch + +jobs: + publish-npm-latest: + uses: ./.github/workflows/publish-npm-latest.yml + secrets: + CAP_GH_RELEASE_TOKEN: ${{ secrets.CAP_GH_RELEASE_TOKEN }} + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + publish-android: + needs: publish-npm-latest + uses: ./.github/workflows/publish-android.yml + secrets: + ANDROID_OSSRH_USERNAME: ${{ secrets.ANDROID_OSSRH_USERNAME }} + ANDROID_OSSRH_PASSWORD: ${{ secrets.ANDROID_OSSRH_PASSWORD }} + ANDROID_SIGNING_KEY_ID: ${{ secrets.ANDROID_SIGNING_KEY_ID }} + ANDROID_SIGNING_PASSWORD: ${{ secrets.ANDROID_SIGNING_PASSWORD }} + ANDROID_SIGNING_KEY: ${{ secrets.ANDROID_SIGNING_KEY }} + ANDROID_SONATYPE_STAGING_PROFILE_ID: ${{ secrets.ANDROID_SONATYPE_STAGING_PROFILE_ID }} + CAP_GH_RELEASE_TOKEN: ${{ secrets.CAP_GH_RELEASE_TOKEN }} diff --git a/.github/workflows/publish-npm-alpha.yml b/.github/workflows/publish-npm-alpha.yml new file mode 100644 index 000000000..1bc3e663a --- /dev/null +++ b/.github/workflows/publish-npm-alpha.yml @@ -0,0 +1,33 @@ +name: Publish NPM Alpha + +on: workflow_dispatch + +jobs: + deploy-npm-alpha: + runs-on: macos-12 + timeout-minutes: 30 + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + token: ${{ secrets.CAP_GH_RELEASE_TOKEN }} + - uses: actions/setup-node@v1 + with: + node-version: 14.x + - name: Restore Dependency Cache + uses: actions/cache@v2 + with: + path: ~/.npm + key: ${{ runner.OS }}-dependency-cache-${{ hashFiles('**/package.json') }} + - run: | + echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}" >> ~/.npmrc + npm whoami + npm install + - name: Version & Publish + env: + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + GH_TOKEN: ${{ secrets.CAP_GH_RELEASE_TOKEN }} + run: | + git config user.name "Github Workflow (on behalf of ${{ github.actor }})" + git config user.email "users.noreply.github.com" + npm run ci:publish:alpha \ No newline at end of file diff --git a/.github/workflows/publish-npm-beta.yml b/.github/workflows/publish-npm-beta.yml new file mode 100644 index 000000000..b8c500d85 --- /dev/null +++ b/.github/workflows/publish-npm-beta.yml @@ -0,0 +1,33 @@ +name: Publish NPM Beta + +on: workflow_dispatch + +jobs: + deploy-npm-beta: + runs-on: macos-12 + timeout-minutes: 30 + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + token: ${{ secrets.CAP_GH_RELEASE_TOKEN }} + - uses: actions/setup-node@v1 + with: + node-version: 14.x + - name: Restore Dependency Cache + uses: actions/cache@v2 + with: + path: ~/.npm + key: ${{ runner.OS }}-dependency-cache-${{ hashFiles('**/package.json') }} + - run: | + echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}" >> ~/.npmrc + npm whoami + npm install + - name: Version & Publish + env: + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + GH_TOKEN: ${{ secrets.CAP_GH_RELEASE_TOKEN }} + run: | + git config user.name "Github Workflow (on behalf of ${{ github.actor }})" + git config user.email "users.noreply.github.com" + npm run ci:publish:beta \ No newline at end of file diff --git a/.github/workflows/publish-npm-dev.yml b/.github/workflows/publish-npm-dev.yml new file mode 100644 index 000000000..dfe62a826 --- /dev/null +++ b/.github/workflows/publish-npm-dev.yml @@ -0,0 +1,33 @@ +name: Publish NPM Dev + +on: workflow_dispatch + +jobs: + deploy-npm-dev: + runs-on: macos-12 + timeout-minutes: 30 + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + token: ${{ secrets.CAP_GH_RELEASE_TOKEN }} + - uses: actions/setup-node@v1 + with: + node-version: 14.x + - name: Restore Dependency Cache + uses: actions/cache@v2 + with: + path: ~/.npm + key: ${{ runner.OS }}-dependency-cache-${{ hashFiles('**/package.json') }} + - run: | + echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}" >> ~/.npmrc + npm whoami + npm install + - name: Version & Publish + env: + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + GH_TOKEN: ${{ secrets.CAP_GH_RELEASE_TOKEN }} + run: | + git config user.name "Github Workflow (on behalf of ${{ github.actor }})" + git config user.email "users.noreply.github.com" + npm run ci:publish:dev \ No newline at end of file diff --git a/.github/workflows/publish-npm-latest.yml b/.github/workflows/publish-npm-latest.yml new file mode 100644 index 000000000..576eb05a6 --- /dev/null +++ b/.github/workflows/publish-npm-latest.yml @@ -0,0 +1,41 @@ +name: Publish NPM Latest + +on: + workflow_call: + secrets: + CAP_GH_RELEASE_TOKEN: + required: true + NPM_TOKEN: + required: true + workflow_dispatch: + +jobs: + deploy-npm-latest: + if: github.ref == 'refs/heads/main' + runs-on: macos-12 + timeout-minutes: 30 + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + token: ${{ secrets.CAP_GH_RELEASE_TOKEN }} + - uses: actions/setup-node@v1 + with: + node-version: 14.x + - name: Restore Dependency Cache + uses: actions/cache@v2 + with: + path: ~/.npm + key: ${{ runner.OS }}-dependency-cache-${{ hashFiles('**/package.json') }} + - run: | + echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}" >> ~/.npmrc + npm whoami + npm install + - name: Version & Publish + env: + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + GH_TOKEN: ${{ secrets.CAP_GH_RELEASE_TOKEN }} + run: | + git config user.name "Github Workflow (on behalf of ${{ github.actor }})" + git config user.email "users.noreply.github.com" + npm run ci:publish:latest diff --git a/.github/workflows/publish-npm-nightly.yml b/.github/workflows/publish-npm-nightly.yml new file mode 100644 index 000000000..6f60682e1 --- /dev/null +++ b/.github/workflows/publish-npm-nightly.yml @@ -0,0 +1,36 @@ +name: Publish NPM Nightly + +on: + schedule: + - cron: '0 15 * * 1-5' + +jobs: + deploy-npm-nightly: + if: github.ref == 'refs/heads/main' + runs-on: macos-12 + timeout-minutes: 30 + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + token: ${{ secrets.CAP_GH_RELEASE_TOKEN }} + - uses: actions/setup-node@v1 + with: + node-version: 14.x + - name: Restore Dependency Cache + uses: actions/cache@v2 + with: + path: ~/.npm + key: ${{ runner.OS }}-dependency-cache-${{ hashFiles('**/package.json') }} + - run: | + echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}" >> ~/.npmrc + npm whoami + npm install + - name: Version & Publish + env: + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + GH_TOKEN: ${{ secrets.CAP_GH_RELEASE_TOKEN }} + run: | + git config user.name "Github Workflow (on behalf of ${{ github.actor }})" + git config user.email "users.noreply.github.com" + npm run ci:publish:nightly diff --git a/.github/workflows/publish-npm-rc.yml b/.github/workflows/publish-npm-rc.yml new file mode 100644 index 000000000..049112025 --- /dev/null +++ b/.github/workflows/publish-npm-rc.yml @@ -0,0 +1,33 @@ +name: Publish NPM RC + +on: workflow_dispatch + +jobs: + deploy-npm-rc: + runs-on: macos-12 + timeout-minutes: 30 + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + token: ${{ secrets.CAP_GH_RELEASE_TOKEN }} + - uses: actions/setup-node@v1 + with: + node-version: 14.x + - name: Restore Dependency Cache + uses: actions/cache@v2 + with: + path: ~/.npm + key: ${{ runner.OS }}-dependency-cache-${{ hashFiles('**/package.json') }} + - run: | + echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}" >> ~/.npmrc + npm whoami + npm install + - name: Version & Publish + env: + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + GH_TOKEN: ${{ secrets.CAP_GH_RELEASE_TOKEN }} + run: | + git config user.name "Github Workflow (on behalf of ${{ github.actor }})" + git config user.email "users.noreply.github.com" + npm run ci:publish:rc \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 000000000..c419dc433 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,250 @@ +# Change Log + +All notable changes to this project will be documented in this file. +See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [4.0.1](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0...4.0.1) (2022-07-28) + +**Note:** Version bump only for package capacitor-plugins + + + + + +# [4.0.0](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0-beta.2...4.0.0) (2022-07-27) + + +### Bug Fixes + +* **share:** Prevent crash on no shareable files ([#1088](https://github.com/ionic-team/capacitor-plugins/issues/1088)) ([dc67e7b](https://github.com/ionic-team/capacitor-plugins/commit/dc67e7b96daa99e2d020b76005e37d93b610bbf2)) +* **status-bar:** not working on older devices ([#1078](https://github.com/ionic-team/capacitor-plugins/issues/1078)) ([4e34977](https://github.com/ionic-team/capacitor-plugins/commit/4e349772d3d8f8e30ce52c1831a1dc9a9f9fd408)) + + +### Features + +* **keyboard:** add getResizeMode function ([#1082](https://github.com/ionic-team/capacitor-plugins/issues/1082)) ([594d854](https://github.com/ionic-team/capacitor-plugins/commit/594d8545fa1560c2d518d0eff30e2702f1b90a45)) +* **splash-screen:** Use Android 12 Splash Screen API ([#1011](https://github.com/ionic-team/capacitor-plugins/issues/1011)) ([79185ad](https://github.com/ionic-team/capacitor-plugins/commit/79185adf76bc4ff4bae1be5ec5b5881cfbe748b1)) + + + + + +# [4.0.0-beta.2](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0-beta.0...4.0.0-beta.2) (2022-07-08) + + +### Features + +* **browser:** Allow to configure popover size ([#1056](https://github.com/ionic-team/capacitor-plugins/issues/1056)) ([90eb1e5](https://github.com/ionic-team/capacitor-plugins/commit/90eb1e5356aab11103f9b1f56808102ee42f2f1b)) +* **google-maps:** provides variables for configuring dependencies ([#1063](https://github.com/ionic-team/capacitor-plugins/issues/1063)) ([5c077f1](https://github.com/ionic-team/capacitor-plugins/commit/5c077f199cbd16b459a77061509e0504029f78db)) +* **local-notifications:** Add delivered notification handling ([#1060](https://github.com/ionic-team/capacitor-plugins/issues/1060)) ([0a89dc9](https://github.com/ionic-team/capacitor-plugins/commit/0a89dc97407685a7f1ec97532af304115fea7a0f)) + + + + + +# 4.0.0-beta.0 (2022-06-27) + + +### Bug Fixes + +* **app:** Don't unset App Listeners on removeAllListeners ([#716](https://github.com/ionic-team/capacitor-plugins/issues/716)) ([17f2ee8](https://github.com/ionic-team/capacitor-plugins/commit/17f2ee8743e1366dd74771bdad9829cc5f3891e8)) +* **app:** get correct build value ([#858](https://github.com/ionic-team/capacitor-plugins/issues/858)) ([4d3b125](https://github.com/ionic-team/capacitor-plugins/commit/4d3b1253c5a9c699c146526fab64c4184f810469)) +* **app:** use alternative to deprecated versionCode ([#491](https://github.com/ionic-team/capacitor-plugins/issues/491)) ([6ebabf7](https://github.com/ionic-team/capacitor-plugins/commit/6ebabf77f1b9a954b25fdad8aaf9a89638d8366b)) +* **browser:** browserFinished does not fire when closing popovers ([#483](https://github.com/ionic-team/capacitor-plugins/issues/483)) ([fb8dbb8](https://github.com/ionic-team/capacitor-plugins/commit/fb8dbb8dc69d67e2aab72ea3cd5389dc91f9bace)) +* **camera:** Append exif to android images ([#480](https://github.com/ionic-team/capacitor-plugins/issues/480)) ([cad8a30](https://github.com/ionic-team/capacitor-plugins/commit/cad8a30c562202fb819a4d260d5307f1b6b8fa44)) +* **camera:** avoid error if image has no orientation ([#554](https://github.com/ionic-team/capacitor-plugins/issues/554)) ([dc8a55a](https://github.com/ionic-team/capacitor-plugins/commit/dc8a55a71cdaaf7ad86aee8470a0c7b8284653c4)) +* **camera:** cleanup camera images if not needed ([#563](https://github.com/ionic-team/capacitor-plugins/issues/563)) ([a2e4f43](https://github.com/ionic-team/capacitor-plugins/commit/a2e4f4339119698e8dd066a5f2f8f065ab2e4727)) +* **camera:** Don't save gallery images on iOS 14+ ([#696](https://github.com/ionic-team/capacitor-plugins/issues/696)) ([7b2cc88](https://github.com/ionic-team/capacitor-plugins/commit/7b2cc88f6e83265c991ae9f81cfc3f6bed346250)) +* **camera:** Make allowEdit work on all devices ([#552](https://github.com/ionic-team/capacitor-plugins/issues/552)) ([5224177](https://github.com/ionic-team/capacitor-plugins/commit/5224177f77bdce1c8f028e2cef41614fa687502f)) +* **camera:** Make web use source options ([#487](https://github.com/ionic-team/capacitor-plugins/issues/487)) ([7870e6b](https://github.com/ionic-team/capacitor-plugins/commit/7870e6b6ca196265640fc0ba3c1f52ddca075607)) +* **camera:** process picked image only once ([#782](https://github.com/ionic-team/capacitor-plugins/issues/782)) ([897dcaf](https://github.com/ionic-team/capacitor-plugins/commit/897dcaf839a6cb83256485c32df2ca0e7b439124)) +* **camera:** Properly reset orientation exif if corrected ([#545](https://github.com/ionic-team/capacitor-plugins/issues/545)) ([ad8c325](https://github.com/ionic-team/capacitor-plugins/commit/ad8c325af0a2459f5a7788be08a8da4118717671)) +* **camera:** Remove capture attribute from multiple photo picker ([#687](https://github.com/ionic-team/capacitor-plugins/issues/687)) ([e551ef7](https://github.com/ionic-team/capacitor-plugins/commit/e551ef77eebe331cc7bf13c9c0eab5a0bd2da0d1)) +* **camera:** Reset exif orientation if corrected ([#510](https://github.com/ionic-team/capacitor-plugins/issues/510)) ([a65c05e](https://github.com/ionic-team/capacitor-plugins/commit/a65c05e0de8f53e7371c194047a75797d53879b5)) +* **camera:** Resize not respecting aspect ratio on iOS ([#568](https://github.com/ionic-team/capacitor-plugins/issues/568)) ([ea2b801](https://github.com/ionic-team/capacitor-plugins/commit/ea2b8012aab7e5ea34cfa34735f7f55ba76a3882)) +* **camera:** return original image if editing is cancelled ([#566](https://github.com/ionic-team/capacitor-plugins/issues/566)) ([4786841](https://github.com/ionic-team/capacitor-plugins/commit/4786841099403a4d3d59aaf9103e8fa02aa8e4e2)) +* **camera:** Return proper exif when picking multiple images ([#712](https://github.com/ionic-team/capacitor-plugins/issues/712)) ([8451237](https://github.com/ionic-team/capacitor-plugins/commit/8451237e46f24c59e74e350eaa9b31e6d99a68a0)) +* **camera:** return single picture on pickImages ([#783](https://github.com/ionic-team/capacitor-plugins/issues/783)) ([9d65db1](https://github.com/ionic-team/capacitor-plugins/commit/9d65db1e74117fd1c1e7cd9bbba7efaeb4c13e0c)) +* **camera:** Return the full webPath ([#502](https://github.com/ionic-team/capacitor-plugins/issues/502)) ([e849732](https://github.com/ionic-team/capacitor-plugins/commit/e849732dbcf5e85d1df09835c53ff5738fbb4ded)) +* **camera:** Return the image on dismiss completion ([#849](https://github.com/ionic-team/capacitor-plugins/issues/849)) ([f083841](https://github.com/ionic-team/capacitor-plugins/commit/f0838416c6cf731aaae83fcb4986568357878b41)) +* **camera:** saveToGallery for edited images ([#602](https://github.com/ionic-team/capacitor-plugins/issues/602)) ([b5ac27d](https://github.com/ionic-team/capacitor-plugins/commit/b5ac27d59181ec3acc2909b2569d8ab45a829b1c)) +* **camera:** set camera direction for web ([#665](https://github.com/ionic-team/capacitor-plugins/issues/665)) ([4afedb9](https://github.com/ionic-team/capacitor-plugins/commit/4afedb96f3b745a86d9cacd33ca71c42ae3fb8d4)) +* **camera:** set settings again on callbacks ([#595](https://github.com/ionic-team/capacitor-plugins/issues/595)) ([908bd68](https://github.com/ionic-team/capacitor-plugins/commit/908bd688767e374cf8e96b3def08bd33dcdfd2aa)) +* **camera:** Use Locale.ROOT on toUpperCase ([#812](https://github.com/ionic-team/capacitor-plugins/issues/812)) ([6d689ac](https://github.com/ionic-team/capacitor-plugins/commit/6d689acc48e3746ddd35bd5e1e8d7f239cb7f8df)) +* **device:** handle case of no localStorage for getId ([#1059](https://github.com/ionic-team/capacitor-plugins/issues/1059)) ([5f77a7d](https://github.com/ionic-team/capacitor-plugins/commit/5f77a7da48fc7f0ce5250e7cba621731ac6b210a)) +* **device:** isVirtual is false on M1 simulators ([#726](https://github.com/ionic-team/capacitor-plugins/issues/726)) ([5377586](https://github.com/ionic-team/capacitor-plugins/commit/53775863df624531e8ffa4b18852b408e1bd2cbd)) +* **device:** return short language code in web ([#893](https://github.com/ionic-team/capacitor-plugins/issues/893)) ([07f0887](https://github.com/ionic-team/capacitor-plugins/commit/07f0887f4f0c9a883e55fb24b506a47dc61f13f7)) +* **filesystem:** allow copy if from is not parent of to ([#546](https://github.com/ionic-team/capacitor-plugins/issues/546)) ([a70414e](https://github.com/ionic-team/capacitor-plugins/commit/a70414e79189579ff1a0b5c2a90d12491f5c23cf)) +* **filesystem:** Prevent android crash on invalid base64 write ([#937](https://github.com/ionic-team/capacitor-plugins/issues/937)) ([1af0bfe](https://github.com/ionic-team/capacitor-plugins/commit/1af0bfe24d2a36bc2949fe52866131c3327b321e)) +* **filesystem:** Throw errors instead of strings ([#746](https://github.com/ionic-team/capacitor-plugins/issues/746)) ([af4b875](https://github.com/ionic-team/capacitor-plugins/commit/af4b8750be512b869af07bcf96c1602eedc6758e)) +* **filesystem:** web appendFile with base64 data ([#928](https://github.com/ionic-team/capacitor-plugins/issues/928)) ([80253cf](https://github.com/ionic-team/capacitor-plugins/commit/80253cf2652bf7fa9c07933989cbdffeadd52a27)) +* **geolocation:** reject checkPermissions / requestPermissions if location services are disabled ([#1053](https://github.com/ionic-team/capacitor-plugins/issues/1053)) ([774ec6e](https://github.com/ionic-team/capacitor-plugins/commit/774ec6e941193b1b06d07d31e6672340de532385)) +* **geolocation:** return cached location if newer than maximumAge ([#639](https://github.com/ionic-team/capacitor-plugins/issues/639)) ([7b08eea](https://github.com/ionic-team/capacitor-plugins/commit/7b08eea9729bbf2b2b6b881cc81389cf108b3a2c)) +* **geolocation:** stop location requests on pause ([#1018](https://github.com/ionic-team/capacitor-plugins/issues/1018)) ([eb24f25](https://github.com/ionic-team/capacitor-plugins/commit/eb24f2521d05dd25a2087a1de2b3e0644568cda0)) +* **google-maps:** correctly typed event listeners ([656f916](https://github.com/ionic-team/capacitor-plugins/commit/656f9169ccd8d7fa880143b13ca5f62bb546edb0)) +* **google-maps:** Fixing map touch events on Android ([7cb89fb](https://github.com/ionic-team/capacitor-plugins/commit/7cb89fb788e05aa9e90c39698e041ebe094132ea)) +* **ios:** Check if UIApplicationDelegate responds to window selector ([#1032](https://github.com/ionic-team/capacitor-plugins/issues/1032)) ([5be1466](https://github.com/ionic-team/capacitor-plugins/commit/5be14662181305e48bc097ade6504c579880bda8)) +* **keyboard:** Prevent null pointer if native listener not set ([#789](https://github.com/ionic-team/capacitor-plugins/issues/789)) ([8b6f119](https://github.com/ionic-team/capacitor-plugins/commit/8b6f119ad5143d380aa9ebd7c73b701ad5a1f10a)) +* **local-notifications:** Add FLAG_MUTABLE to pending intents for SDK 31 support ([#914](https://github.com/ionic-team/capacitor-plugins/issues/914)) ([9ad0ce6](https://github.com/ionic-team/capacitor-plugins/commit/9ad0ce6f1497f425db907908be1b125e6ed83dbc)) +* **local-notifications:** Handle case of not allowed exact notifications ([#954](https://github.com/ionic-team/capacitor-plugins/issues/954)) ([5016996](https://github.com/ionic-team/capacitor-plugins/commit/5016996b3a4e9824d8dd2bc4c71892fc5dbc7365)) +* **local-notifications:** requestPermissions and checkPermissions return if enabled ([#494](https://github.com/ionic-team/capacitor-plugins/issues/494)) ([555bb1f](https://github.com/ionic-team/capacitor-plugins/commit/555bb1f9bd02ccd999891a316e7ee0f8c1844e92)) +* **local-notifications:** Throw errors if missing mandatory channel fields ([#577](https://github.com/ionic-team/capacitor-plugins/issues/577)) ([6bf3a4f](https://github.com/ionic-team/capacitor-plugins/commit/6bf3a4f0de8880588200ae60e73427fa6959ea20)) +* **push-notifications:** Throw errors if missing mandatory channel fields ([#576](https://github.com/ionic-team/capacitor-plugins/issues/576)) ([50f4e70](https://github.com/ionic-team/capacitor-plugins/commit/50f4e7026e5cae5f0871d4863bfab36989208064)) +* **push-notifications:** use id and tag for canceling active notification ([#1041](https://github.com/ionic-team/capacitor-plugins/issues/1041)) ([fa710a6](https://github.com/ionic-team/capacitor-plugins/commit/fa710a63ea87f0ec0a7b0059baacfad7a45f8558)) +* **share:** avoid crash when targeting SDK 31 ([#913](https://github.com/ionic-team/capacitor-plugins/issues/913)) ([275da5f](https://github.com/ionic-team/capacitor-plugins/commit/275da5fc23cf0ef173276d9027f8c5ffdb8a5432)) +* Make removeAllListeners return a promise ([#895](https://github.com/ionic-team/capacitor-plugins/issues/895)) ([e5c49d6](https://github.com/ionic-team/capacitor-plugins/commit/e5c49d64445dca70286334e6a0441d8021197b13)) +* **local-notifications:** return schedule on as object ([#603](https://github.com/ionic-team/capacitor-plugins/issues/603)) ([ca34b01](https://github.com/ionic-team/capacitor-plugins/commit/ca34b01c73f14bb0ad14e8a501210e42a0e65b04)) +* **local-notifications:** use proper rollup config ([#528](https://github.com/ionic-team/capacitor-plugins/issues/528)) ([cd17daa](https://github.com/ionic-team/capacitor-plugins/commit/cd17daa02241f50299232212ad72722d8a35ee16)) +* **network:** Don't add window event listeners if there is no window ([#678](https://github.com/ionic-team/capacitor-plugins/issues/678)) ([0c65780](https://github.com/ionic-team/capacitor-plugins/commit/0c657808083a7f4245027a2248816b3921b813bf)) +* **share:** correct whatsapp file sharing ([#816](https://github.com/ionic-team/capacitor-plugins/issues/816)) ([18b10c4](https://github.com/ionic-team/capacitor-plugins/commit/18b10c493e26a6b62031c3bfb57e1ffbbf926c41)) +* **share:** Prevent share if sharing in progress ([#489](https://github.com/ionic-team/capacitor-plugins/issues/489)) ([3479783](https://github.com/ionic-team/capacitor-plugins/commit/34797837363588f4511403e39017bf6b656685cb)) +* **splash-screen:** avoid conditional downcast warning ([#776](https://github.com/ionic-team/capacitor-plugins/issues/776)) ([87ed912](https://github.com/ionic-team/capacitor-plugins/commit/87ed9128f43f0be498601f0ba89cadeba7a339b4)) +* **splash-screen:** pick first window when there is no key window ([#730](https://github.com/ionic-team/capacitor-plugins/issues/730)) ([0e335ad](https://github.com/ionic-team/capacitor-plugins/commit/0e335ad386da8ceadfdfaa3be982840547fc41b6)) +* **splash-screen:** Use configured storyboard instead of hardcoded value ([#548](https://github.com/ionic-team/capacitor-plugins/issues/548)) ([67dd67f](https://github.com/ionic-team/capacitor-plugins/commit/67dd67fc443ea5494e8482fd4346c5275a42841b)) +* **splash-screen:** Use Locale.ROOT on toLowerCase ([#813](https://github.com/ionic-team/capacitor-plugins/issues/813)) ([ecc55e1](https://github.com/ionic-team/capacitor-plugins/commit/ecc55e172acfe066977a4aac5018a55beef64f53)) +* **status-bar:** Use Locale.ROOT on toUpperCase ([#814](https://github.com/ionic-team/capacitor-plugins/issues/814)) ([bf804ce](https://github.com/ionic-team/capacitor-plugins/commit/bf804ceaa5b7ee94ddeff052511db7c6ee49b4e6)) +* inline source code in esm map files ([#760](https://github.com/ionic-team/capacitor-plugins/issues/760)) ([a960489](https://github.com/ionic-team/capacitor-plugins/commit/a960489a19db0182b90d187a50deff9dfbe51038)) +* **action-sheet:** add back deprecated `ActionSheetOptionStyle` type ([e026425](https://github.com/ionic-team/capacitor-plugins/commit/e0264256532624d5892e9b5468be89cd400cf823)) +* **action-sheet:** change package name to 'actionsheet' ([#57](https://github.com/ionic-team/capacitor-plugins/issues/57)) ([5cf608b](https://github.com/ionic-team/capacitor-plugins/commit/5cf608bb82106297a8610b72c7e636d6bfd372de)) +* **android:** fire localNotificationReceived event on Android ([#217](https://github.com/ionic-team/capacitor-plugins/issues/217)) ([d97682d](https://github.com/ionic-team/capacitor-plugins/commit/d97682d9f3d6f612993716c3bc35d3015c4e0c07)) +* **android:** permissions use "publicStorage" as alias ([#202](https://github.com/ionic-team/capacitor-plugins/issues/202)) ([2dfc7a3](https://github.com/ionic-team/capacitor-plugins/commit/2dfc7a3261a4f98871a86fe6d47fab084a2d1deb)) +* **android:** support writing files without scheme ([#241](https://github.com/ionic-team/capacitor-plugins/issues/241)) ([4285cb1](https://github.com/ionic-team/capacitor-plugins/commit/4285cb1d37ec3361e7ec4da4786502693b04d478)) +* **app:** remove iOS deprecate warnings ([#121](https://github.com/ionic-team/capacitor-plugins/issues/121)) ([d009826](https://github.com/ionic-team/capacitor-plugins/commit/d009826ded4a948041586bcc4d8a0fa51afbea5f)) +* **app:** Update getLaunchUrl return type as can be undefined ([#299](https://github.com/ionic-team/capacitor-plugins/issues/299)) ([cdc446b](https://github.com/ionic-team/capacitor-plugins/commit/cdc446b1349ef55717b12756d3fcb2fbec671a28)) +* **browser:** don't expose load method ([#128](https://github.com/ionic-team/capacitor-plugins/issues/128)) ([945e59b](https://github.com/ionic-team/capacitor-plugins/commit/945e59b622bad42d33804d0ffb4ca9afcb7f9b07)) +* **browser:** prevent crash on popover presentation ([#369](https://github.com/ionic-team/capacitor-plugins/issues/369)) ([a9d4380](https://github.com/ionic-team/capacitor-plugins/commit/a9d43805f35ebaeaaed3285adc2e1f7e1062e009)) +* **camera:** Append change listener only once ([#486](https://github.com/ionic-team/capacitor-plugins/issues/486)) ([5b7021e](https://github.com/ionic-team/capacitor-plugins/commit/5b7021e210649f8501a20ba6549903ecb6d42dcd)) +* **camera:** correct photo resizing on iOS ([#460](https://github.com/ionic-team/capacitor-plugins/issues/460)) ([bc56e03](https://github.com/ionic-team/capacitor-plugins/commit/bc56e034c711b172a7ff503cabd2970adbc14b86)) +* **camera:** decode content uri when retrieving image from gallery ([#277](https://github.com/ionic-team/capacitor-plugins/issues/277)) ([a6cd1ad](https://github.com/ionic-team/capacitor-plugins/commit/a6cd1adc241bf21e4f7f06d24c0db4a4d7382dbc)) +* **camera:** fix camera source on Android ([#164](https://github.com/ionic-team/capacitor-plugins/issues/164)) ([e67f7c6](https://github.com/ionic-team/capacitor-plugins/commit/e67f7c6b06b20d7c3e8f0925c40fd75d23d9d717)) +* **camera:** Make input file hidden ([#484](https://github.com/ionic-team/capacitor-plugins/issues/484)) ([cdc1835](https://github.com/ionic-team/capacitor-plugins/commit/cdc1835f3bbfb8db8e18fccace6103d83dd9edaa)) +* **camera:** query IMAGE_CAPTURE intent required by SDK 30 ([#160](https://github.com/ionic-team/capacitor-plugins/issues/160)) ([6484991](https://github.com/ionic-team/capacitor-plugins/commit/6484991d76d57bac0cbc82b9f050e146ec4732da)) +* **camera:** Remove unused saveCall ([#401](https://github.com/ionic-team/capacitor-plugins/issues/401)) ([95920da](https://github.com/ionic-team/capacitor-plugins/commit/95920da4d1844ed76a162651d5492a22a4038d26)) +* **camera:** return file URL for path, not system path ([#170](https://github.com/ionic-team/capacitor-plugins/issues/170)) ([8a9e5c3](https://github.com/ionic-team/capacitor-plugins/commit/8a9e5c3dba3b232a1cca9f9a1e9b4520022abc09)) +* **clipboard:** prevent NotAllowedError on first method invocation ([#342](https://github.com/ionic-team/capacitor-plugins/issues/342)) ([ab8eecb](https://github.com/ionic-team/capacitor-plugins/commit/ab8eecb873999d6f4321218c60b45335998189eb)) +* **dialogs:** put cancel button of confirm/prompt on the left ([#346](https://github.com/ionic-team/capacitor-plugins/issues/346)) ([1ac23db](https://github.com/ionic-team/capacitor-plugins/commit/1ac23db5162fa94742f18f00daf87a62a63f8dca)) +* **filesystem:** Append doesn't resolve on iOS ([#305](https://github.com/ionic-team/capacitor-plugins/issues/305)) ([98e91cd](https://github.com/ionic-team/capacitor-plugins/commit/98e91cd745fb12bf46f99233bb527f147dbba58b)) +* **filesystem:** Convert stat ctime/mtime timestamp to milliseconds ([#321](https://github.com/ionic-team/capacitor-plugins/issues/321)) ([d978986](https://github.com/ionic-team/capacitor-plugins/commit/d97898662d0ba037e5f8448990a91de5ec6a4234)) +* **filesystem:** copy doesn't resolve on Android ([#233](https://github.com/ionic-team/capacitor-plugins/issues/233)) ([17cbf3b](https://github.com/ionic-team/capacitor-plugins/commit/17cbf3b0ada97f1279fba32b551c380c0e669406)) +* **filesystem:** is not requesting permission on public directories ([#246](https://github.com/ionic-team/capacitor-plugins/issues/246)) ([aa897ab](https://github.com/ionic-team/capacitor-plugins/commit/aa897ab4269e34cd5d762ed645030054ddda7dd6)) +* **filesystem:** Make ctime optional ([#373](https://github.com/ionic-team/capacitor-plugins/issues/373)) ([e3c6212](https://github.com/ionic-team/capacitor-plugins/commit/e3c6212b94c75cf747a8768af5056963683953b2)) +* **filesystem:** rmdir doesn't resolve on iOS ([#239](https://github.com/ionic-team/capacitor-plugins/issues/239)) ([7ca538b](https://github.com/ionic-team/capacitor-plugins/commit/7ca538bb47e2e00080eadfe8d875323c1e198cb2)) +* **filesystem:** Use PermissionState from @capacitor/core ([#148](https://github.com/ionic-team/capacitor-plugins/issues/148)) ([5ce3c5d](https://github.com/ionic-team/capacitor-plugins/commit/5ce3c5d491a35b8771661f3e4eb98aac6df15911)) +* **geolocation:** Make getCurrentPosition return only once ([#470](https://github.com/ionic-team/capacitor-plugins/issues/470)) ([c5f1ceb](https://github.com/ionic-team/capacitor-plugins/commit/c5f1ceb790910b92e3f64d0b7fa8c85d48ea9841)) +* **geolocation:** Replace deprecated call.save with new keepAlive API ([#375](https://github.com/ionic-team/capacitor-plugins/issues/375)) ([e4e7cf4](https://github.com/ionic-team/capacitor-plugins/commit/e4e7cf4afd4a70bf48359c625fa7a548211876d5)) +* **geolocation:** Use the new APIs for handling/saving calls ([#374](https://github.com/ionic-team/capacitor-plugins/issues/374)) ([ebd5b52](https://github.com/ionic-team/capacitor-plugins/commit/ebd5b527cb7f8b6c0016e82d03a0e84287913d3e)) +* **ios:** Coerce 'extra' field to add missing notification data on events ([#231](https://github.com/ionic-team/capacitor-plugins/issues/231)) ([46ce6b2](https://github.com/ionic-team/capacitor-plugins/commit/46ce6b2a72e4b107702b0cfb97007aaf385a3106)) +* **ios:** do not show notifications when in foreground ([#209](https://github.com/ionic-team/capacitor-plugins/issues/209)) ([1994997](https://github.com/ionic-team/capacitor-plugins/commit/1994997a100d7c57477305d933fb835cf9f7c9c8)) +* **keyboard:** remove deprecated warnings ([#122](https://github.com/ionic-team/capacitor-plugins/issues/122)) ([a6e207c](https://github.com/ionic-team/capacitor-plugins/commit/a6e207c47dfac14d6cbcaa2a942b7b04cae3dae8)) +* **keyboard:** Use new Config name for scroll ([#335](https://github.com/ionic-team/capacitor-plugins/issues/335)) ([bec3d22](https://github.com/ionic-team/capacitor-plugins/commit/bec3d22e67dfb22db5b5bb774f53fb01a34f116f)) +* **local-notification:** Throw unavailable if Notification API not supported ([#285](https://github.com/ionic-team/capacitor-plugins/issues/285)) ([a90a88b](https://github.com/ionic-team/capacitor-plugins/commit/a90a88b217f5fa2a257416050afb476dd84d8051)) +* **local-notifications:** Adding check for `new Notification` support ([#295](https://github.com/ionic-team/capacitor-plugins/issues/295)) ([a806f22](https://github.com/ionic-team/capacitor-plugins/commit/a806f22577209322bdc93ef7fe5490d3b0b6e42f)) +* **local-notifications:** Checking for null schedule in notification JSObject ([#258](https://github.com/ionic-team/capacitor-plugins/issues/258)) ([73cb416](https://github.com/ionic-team/capacitor-plugins/commit/73cb4168329622bb5a6625c900090a01fc5eca99)) +* **local-notifications:** don't store notifications if not scheduled ([#310](https://github.com/ionic-team/capacitor-plugins/issues/310)) ([c1445fd](https://github.com/ionic-team/capacitor-plugins/commit/c1445fddc69db27506f83b3ea56d8e90d4384346)) +* **local-notifications:** extra not being returned on notification events ([#340](https://github.com/ionic-team/capacitor-plugins/issues/340)) ([5b03a7f](https://github.com/ionic-team/capacitor-plugins/commit/5b03a7fdbfd2e8293a9fc3726185b516d7efa9a9)) +* **local-notifications:** Make getPending not return already fired notifications ([#256](https://github.com/ionic-team/capacitor-plugins/issues/256)) ([fb96f8a](https://github.com/ionic-team/capacitor-plugins/commit/fb96f8ab8c4776528e5825be6c2e19567462eef8)) +* **local-notifications:** Opt out of Capacitor date serialization ([#264](https://github.com/ionic-team/capacitor-plugins/issues/264)) ([6e447d5](https://github.com/ionic-team/capacitor-plugins/commit/6e447d54aff3cac47df540addf2a0bf05238c158)) +* **push-notifications:** bump iOS deployment target to 12.0 ([#183](https://github.com/ionic-team/capacitor-plugins/issues/183)) ([d5b6503](https://github.com/ionic-team/capacitor-plugins/commit/d5b650312cded1606e39bbddc62acc6af9545997)) +* **push-notifications:** make removeAllListeners available ([#454](https://github.com/ionic-team/capacitor-plugins/issues/454)) ([d92c925](https://github.com/ionic-team/capacitor-plugins/commit/d92c92566b15d3b339e9a4c54471b65fda49a7f0)) +* **push-notifications:** proper return of push notification object properties ([#349](https://github.com/ionic-team/capacitor-plugins/issues/349)) ([733fc06](https://github.com/ionic-team/capacitor-plugins/commit/733fc06af7b62a576fb6214a7fe42838a3bcb93a)) +* **share:** Avoid SecurityError on Android 10 file share ([#63](https://github.com/ionic-team/capacitor-plugins/issues/63)) ([b6a8191](https://github.com/ionic-team/capacitor-plugins/commit/b6a819115c84fe533a97bad9f8784499c492ddcd)) +* **share:** set type to */* if no mine type can be found ([#324](https://github.com/ionic-team/capacitor-plugins/issues/324)) ([40d4baa](https://github.com/ionic-team/capacitor-plugins/commit/40d4baa8b89e55b094ee568daecf8c63a53fc7cb)) +* **splash-screen:** launchAutoHide not working on iOS ([#319](https://github.com/ionic-team/capacitor-plugins/issues/319)) ([2a83fcb](https://github.com/ionic-team/capacitor-plugins/commit/2a83fcb536cdfc5b601f363212353201de40ca5b)) +* **storage:** configure doesn't resolve on Android and iOS ([#266](https://github.com/ionic-team/capacitor-plugins/issues/266)) ([4f51b24](https://github.com/ionic-team/capacitor-plugins/commit/4f51b24d18890ae207090304c153af6c0067fdff)) +* **text-zoom:** Lazy load iOS implementation ([#735](https://github.com/ionic-team/capacitor-plugins/issues/735)) ([5039a74](https://github.com/ionic-team/capacitor-plugins/commit/5039a747efa2bc36674c70bdd9dae4439165ab4d)) +* add es2017 lib to tsconfig ([#180](https://github.com/ionic-team/capacitor-plugins/issues/180)) ([2c3776c](https://github.com/ionic-team/capacitor-plugins/commit/2c3776c38ca025c5ee965dec10ccf1cdb6c02e2f)) +* better ignore rules for npm distribution ([#32](https://github.com/ionic-team/capacitor-plugins/issues/32)) ([b8d55b9](https://github.com/ionic-team/capacitor-plugins/commit/b8d55b9233e4ad7b8a1cd41110b4e580fc2a059f)) +* correct addListeners links ([#655](https://github.com/ionic-team/capacitor-plugins/issues/655)) ([f9871e7](https://github.com/ionic-team/capacitor-plugins/commit/f9871e7bd53478addb21155e148829f550c0e457)) +* Correct missing source_files path ([#590](https://github.com/ionic-team/capacitor-plugins/issues/590)) ([24e0fc2](https://github.com/ionic-team/capacitor-plugins/commit/24e0fc27cc314049012ab9915fa5e7bfb03313e1)) +* normalize use of integers for notification IDs ([#195](https://github.com/ionic-team/capacitor-plugins/issues/195)) ([b56e111](https://github.com/ionic-team/capacitor-plugins/commit/b56e1118227ee58d1872dbb32a18b8484290d3c7)) +* **web:** fix scheduled notifications not being sent ([#220](https://github.com/ionic-team/capacitor-plugins/issues/220)) ([c8e92d6](https://github.com/ionic-team/capacitor-plugins/commit/c8e92d6a178f8b3278b1d3a9c364eb8120d28848)) +* export all TS definitions ([6cd2996](https://github.com/ionic-team/capacitor-plugins/commit/6cd299660fdeb27382ec7f45f0b3a55224cd0ad1)) +* Migrate plugins from Color.parseColor() to WebColor.parseColor() ([#140](https://github.com/ionic-team/capacitor-plugins/issues/140)) ([26625cf](https://github.com/ionic-team/capacitor-plugins/commit/26625cfefe45b8d1f17ce27efbc8b04f23e99d93)) +* remove postpublish scripts ([#656](https://github.com/ionic-team/capacitor-plugins/issues/656)) ([ed6ac49](https://github.com/ionic-team/capacitor-plugins/commit/ed6ac499ebf4a47525071ccbfc36c27503e11f60)) +* support deprecated types from Capacitor 2 ([#139](https://github.com/ionic-team/capacitor-plugins/issues/139)) ([2d7127a](https://github.com/ionic-team/capacitor-plugins/commit/2d7127a488e26f0287951921a6db47c49d817336)) +* support deprecated types from Capacitor 2 ([#210](https://github.com/ionic-team/capacitor-plugins/issues/210)) ([b559e24](https://github.com/ionic-team/capacitor-plugins/commit/b559e24b24174be60129217e87c0bff14bcdd573)) +* Use the event names from Capacitor 2 ([#215](https://github.com/ionic-team/capacitor-plugins/issues/215)) ([008fe9e](https://github.com/ionic-team/capacitor-plugins/commit/008fe9e9bf6a960b0ab7b6fc4d5014f10ba13df8)) +* **push-notifications:** remove unused Firebase/Messaging dependency ([#186](https://github.com/ionic-team/capacitor-plugins/issues/186)) ([0f4ca7c](https://github.com/ionic-team/capacitor-plugins/commit/0f4ca7ceaf67ced40b2cf2b359001b1ab060a3a6)) +* **status-bar:** remove deprecate warnings ([#120](https://github.com/ionic-team/capacitor-plugins/issues/120)) ([5dcfb25](https://github.com/ionic-team/capacitor-plugins/commit/5dcfb25b7307e631873fc66523ffccd206e07875)) +* **storage:** Remove warning on getString usage ([#85](https://github.com/ionic-team/capacitor-plugins/issues/85)) ([db9c9c0](https://github.com/ionic-team/capacitor-plugins/commit/db9c9c0d6743488e13c86e3b4efd192b4a28a193)) +* use correct package in manifest files ([#22](https://github.com/ionic-team/capacitor-plugins/issues/22)) ([ab62987](https://github.com/ionic-team/capacitor-plugins/commit/ab629877e1951f944594f1b23e1bffefcbc783dd)) + + +### Features + +* **android:** implements Activity Result API changes for permissions and activity results ([#222](https://github.com/ionic-team/capacitor-plugins/issues/222)) ([f671b9f](https://github.com/ionic-team/capacitor-plugins/commit/f671b9f4b472806ef43db6dcf302d4503cf1828c)) +* **google-maps:** Google Maps Bounds ([14a045d](https://github.com/ionic-team/capacitor-plugins/commit/14a045d3880124996b2770cec7b3e28a9f13d231)) +* set targetSDK default value to 32 ([#970](https://github.com/ionic-team/capacitor-plugins/issues/970)) ([fa70d96](https://github.com/ionic-team/capacitor-plugins/commit/fa70d96f141af751aae53ceb5642c46b204f5958)) +* **action-sheet:** Make title optional ([#805](https://github.com/ionic-team/capacitor-plugins/issues/805)) ([2018f78](https://github.com/ionic-team/capacitor-plugins/commit/2018f7823cc25ea39c3533772512d221d2dba926)) +* **android:** support for minimizeApp ([#743](https://github.com/ionic-team/capacitor-plugins/issues/743)) ([3ec2008](https://github.com/ionic-team/capacitor-plugins/commit/3ec2008bc0311c837346ecbdd0afd105149b427a)) +* **app:** Add canGoBack to backButton event ([#265](https://github.com/ionic-team/capacitor-plugins/issues/265)) ([6d7861e](https://github.com/ionic-team/capacitor-plugins/commit/6d7861e78ff7990a21396d05270c622d42850a02)) +* **app:** return promise in exitApp ([#777](https://github.com/ionic-team/capacitor-plugins/issues/777)) ([38e1efc](https://github.com/ionic-team/capacitor-plugins/commit/38e1efc742c7d9e887dfae3848261476202159c1)) +* **camera:** Add new method for multiple image picking from gallery ([#671](https://github.com/ionic-team/capacitor-plugins/issues/671)) ([a49c590](https://github.com/ionic-team/capacitor-plugins/commit/a49c5901683da12438fbafbd1bf6ae91133d18ed)) +* **camera:** Return if image was saved to gallery ([#599](https://github.com/ionic-team/capacitor-plugins/issues/599)) ([594af3b](https://github.com/ionic-team/capacitor-plugins/commit/594af3be0982371e6c61e4bdb830c6bbb3963913)) +* **camera:** Support for 1 Gallery app ([#791](https://github.com/ionic-team/capacitor-plugins/issues/791)) ([77e8c97](https://github.com/ionic-team/capacitor-plugins/commit/77e8c979394d5fb1804fc097ecaeee46a973e640)) +* **camera:** Support for Samsung Gallery app on pickImages ([#706](https://github.com/ionic-team/capacitor-plugins/issues/706)) ([fd059fc](https://github.com/ionic-team/capacitor-plugins/commit/fd059fcd2e53661e95e230f684a6d32408db6787)) +* **camera:** use a distinguishable permission denied string for camera and photos ([#379](https://github.com/ionic-team/capacitor-plugins/issues/379)) ([c71657f](https://github.com/ionic-team/capacitor-plugins/commit/c71657f7e14eae4efd4d2c7d00d77a7b329a7920)) +* **camera:** Use same error messages for permission deny ([#404](https://github.com/ionic-team/capacitor-plugins/issues/404)) ([fffcd47](https://github.com/ionic-team/capacitor-plugins/commit/fffcd47f0237b6997bfa4ce430ef29392047ea0e)) +* **device:** Add getLanguageTag function ([#939](https://github.com/ionic-team/capacitor-plugins/issues/939)) ([d268e4a](https://github.com/ionic-team/capacitor-plugins/commit/d268e4a3d5a0a0279bae6a971b0d6e65481f1899)) +* **device:** Add realDiskTotal and realDiskFree properties ([#694](https://github.com/ionic-team/capacitor-plugins/issues/694)) ([3f67643](https://github.com/ionic-team/capacitor-plugins/commit/3f67643edf4cfd90a84d4606c4c6349b72531b92)) +* **device:** model now reflects exact model on iOS ([#929](https://github.com/ionic-team/capacitor-plugins/issues/929)) ([302d813](https://github.com/ionic-team/capacitor-plugins/commit/302d813991a755c89fbf57a6f5b2c3a2e1cd79aa)) +* **dialog:** Make title optional ([#940](https://github.com/ionic-team/capacitor-plugins/issues/940)) ([497f627](https://github.com/ionic-team/capacitor-plugins/commit/497f6275ee6bc71295403e2cdc5a74b9cc31a310)) +* **filesystem:** Make readDir return files information ([#949](https://github.com/ionic-team/capacitor-plugins/issues/949)) ([0a9f43d](https://github.com/ionic-team/capacitor-plugins/commit/0a9f43dffd3815f600c35ed4528c017644fdb55e)) +* **filesystem:** Return path of copied file ([#931](https://github.com/ionic-team/capacitor-plugins/issues/931)) ([310f583](https://github.com/ionic-team/capacitor-plugins/commit/310f583ccec58730ab8046a1618782c950c60656)) +* **geolocation:** Throw error if location is disabled ([#589](https://github.com/ionic-team/capacitor-plugins/issues/589)) ([14724c5](https://github.com/ionic-team/capacitor-plugins/commit/14724c5ec5b23bf94f6f3511bbe204482768d10f)) +* **keyboard:** Use KeyboardStyle for style config option ([#969](https://github.com/ionic-team/capacitor-plugins/issues/969)) ([42a01b4](https://github.com/ionic-team/capacitor-plugins/commit/42a01b46d5a9e39bfb3ac05d5595aecaeb790557)) +* **push-notifications:** Allow to show while in foreground ([#919](https://github.com/ionic-team/capacitor-plugins/issues/919)) ([a90b5fd](https://github.com/ionic-team/capacitor-plugins/commit/a90b5fd4fe82d660c96a8be55e360d15f9e5e8c6)) +* Upgrade gradle to 7.4 ([#826](https://github.com/ionic-team/capacitor-plugins/issues/826)) ([5db0906](https://github.com/ionic-team/capacitor-plugins/commit/5db0906f6264287c4f8e69dbaecf19d4d387824b)) +* Use java 11 ([#910](https://github.com/ionic-team/capacitor-plugins/issues/910)) ([5acb2a2](https://github.com/ionic-team/capacitor-plugins/commit/5acb2a288a413492b163e4e97da46a085d9e4be0)) +* **filesystem:** support Library directory ([#666](https://github.com/ionic-team/capacitor-plugins/issues/666)) ([ce7ee95](https://github.com/ionic-team/capacitor-plugins/commit/ce7ee958b141f1dd4f86493923455f8264d0b6db)) +* **geolocation:** Add new alias for coarse location ([#684](https://github.com/ionic-team/capacitor-plugins/issues/684)) ([7563040](https://github.com/ionic-team/capacitor-plugins/commit/7563040983ad397e28616246e7ed5ffce69727c2)) +* **geolocation:** Error if Google Play Services are not available ([#709](https://github.com/ionic-team/capacitor-plugins/issues/709)) ([fc79c43](https://github.com/ionic-team/capacitor-plugins/commit/fc79c4319c54cbcd5dbbb7221dfdd03d0515805b)) +* **haptics:** Implement duration for vibration ([#618](https://github.com/ionic-team/capacitor-plugins/issues/618)) ([78e6b68](https://github.com/ionic-team/capacitor-plugins/commit/78e6b6886fa50318b1bfbe229e7318e521e3c245)) +* **local-notifications:** Add weekday scheduling support for Android and iOS ([#756](https://github.com/ionic-team/capacitor-plugins/issues/756)) ([430b485](https://github.com/ionic-team/capacitor-plugins/commit/430b48592ce59ccc967dd9a081873d7dc3937e93)) +* **push-notifications:** Add new type for registrationError ([#808](https://github.com/ionic-team/capacitor-plugins/issues/808)) ([e5e78bb](https://github.com/ionic-team/capacitor-plugins/commit/e5e78bbbff020e625ccfd49c8ae36b4f1609a242)) +* set targetSDK default value to 31 ([#824](https://github.com/ionic-team/capacitor-plugins/issues/824)) ([3ee10de](https://github.com/ionic-team/capacitor-plugins/commit/3ee10de98067984c1a4e75295d001c5a895c47f4)) +* **app-launcher:** make openUrl open urls on web ([#152](https://github.com/ionic-team/capacitor-plugins/issues/152)) ([2eba7b4](https://github.com/ionic-team/capacitor-plugins/commit/2eba7b41a05be2f63c916f51aa4b36ef548ef87c)) +* **device:** add browser/webview version to getInfo() ([#109](https://github.com/ionic-team/capacitor-plugins/issues/109)) ([48c49c1](https://github.com/ionic-team/capacitor-plugins/commit/48c49c1cd1ffc86b40b02dd3778c0a3079cdc00c)) +* **device:** Add deviceInfo.name implementation for Android ([#88](https://github.com/ionic-team/capacitor-plugins/issues/88)) ([bdc3b38](https://github.com/ionic-team/capacitor-plugins/commit/bdc3b38f70ecc7898e2bb23c1cceaea8903f26d9)) +* **device:** Add getId function ([#370](https://github.com/ionic-team/capacitor-plugins/issues/370)) ([96664c6](https://github.com/ionic-team/capacitor-plugins/commit/96664c630140112af7e50569b98b00f774480949)) +* **filesystem:** Allow the use of absolute urls on iOS and web ([#250](https://github.com/ionic-team/capacitor-plugins/issues/250)) ([03ad97c](https://github.com/ionic-team/capacitor-plugins/commit/03ad97c1b7450e864504198853aac2b3bdc4b8a4)) +* **keyboard:** Add default style option for setStyle ([#334](https://github.com/ionic-team/capacitor-plugins/issues/334)) ([9dbb809](https://github.com/ionic-team/capacitor-plugins/commit/9dbb809ce3219d517e62b235406d2b798c95425c)) +* **keyboard:** add types for config files ([#115](https://github.com/ionic-team/capacitor-plugins/issues/115)) ([09bba16](https://github.com/ionic-team/capacitor-plugins/commit/09bba168242c26b3816ab5ff5b15f22531935fec)) +* **keyboard:** Make resize work in apps that use scenes ([#729](https://github.com/ionic-team/capacitor-plugins/issues/729)) ([6dde082](https://github.com/ionic-team/capacitor-plugins/commit/6dde082d1683daa923e6f42678785bc679f63b02)) +* **Keyboard:** Add resizeOnFullScreen plugin configuration ([#627](https://github.com/ionic-team/capacitor-plugins/issues/627)) ([8e87836](https://github.com/ionic-team/capacitor-plugins/commit/8e8783622d6e77c38c4aa741a622455302f30486)) +* **local-notifications:** add more info to pending notifications ([#211](https://github.com/ionic-team/capacitor-plugins/issues/211)) ([7c50487](https://github.com/ionic-team/capacitor-plugins/commit/7c50487d40836380a27bd4c8d3655d83e0c3a720)) +* **local-notifications:** Adding summary text to grouped notifications ([#296](https://github.com/ionic-team/capacitor-plugins/issues/296)) ([f625bd2](https://github.com/ionic-team/capacitor-plugins/commit/f625bd28bc00dbd0b51d7bdecf5e6f3077dcc7a9)) +* **local-notifications:** Fire local notifications while app is idle ([#237](https://github.com/ionic-team/capacitor-plugins/issues/237)) ([43380ef](https://github.com/ionic-team/capacitor-plugins/commit/43380efa8901adf9d669d0c1ef20038a2fd7df8e)) +* **local-notifications:** Support for Big Text and Inbox Notification Style ([#280](https://github.com/ionic-team/capacitor-plugins/issues/280)) ([dc96ef9](https://github.com/ionic-team/capacitor-plugins/commit/dc96ef923725f5b53346431d35f82d5ff13f4e17)) +* **local-notifications:** Support setting seconds in Schedule "on" ([#253](https://github.com/ionic-team/capacitor-plugins/issues/253)) ([4ec8d06](https://github.com/ionic-team/capacitor-plugins/commit/4ec8d06e0cb52403e541a05e5c3518d4c5ea754e)) +* **share:** Add canShare method to check availability ([#748](https://github.com/ionic-team/capacitor-plugins/issues/748)) ([3883d82](https://github.com/ionic-team/capacitor-plugins/commit/3883d82952a4453797b86c562af27f9b05e82a18)) +* **splash-screen:** add useDialog and layoutName options for Android ([#519](https://github.com/ionic-team/capacitor-plugins/issues/519)) ([f48733f](https://github.com/ionic-team/capacitor-plugins/commit/f48733fd42a49d718a70c2fd36d28355a64b7a88)) +* **splash-screen:** Make splash work in apps that use scenes ([#631](https://github.com/ionic-team/capacitor-plugins/issues/631)) ([cf0d214](https://github.com/ionic-team/capacitor-plugins/commit/cf0d2143c225336984a6bc8fa7ef814a18b02bd1)) +* **splash-screen:** Use Launch Storyboard for splash ([#516](https://github.com/ionic-team/capacitor-plugins/issues/516)) ([0292dab](https://github.com/ionic-team/capacitor-plugins/commit/0292dab65ac9c0f81e632eaf711b13b051f4da92)) +* **storage:** Add removeOld function ([#585](https://github.com/ionic-team/capacitor-plugins/issues/585)) ([698350e](https://github.com/ionic-team/capacitor-plugins/commit/698350e38a756abc90fb38212b8adfa890c77ce5)) +* **storage:** make StorageConfiguration init public ([#532](https://github.com/ionic-team/capacitor-plugins/issues/532)) ([4271b5d](https://github.com/ionic-team/capacitor-plugins/commit/4271b5d18a98201582bd95f41d5b5104c83e5b29)) +* **web:** implement ActionPerformed and Received events ([#219](https://github.com/ionic-team/capacitor-plugins/issues/219)) ([e062901](https://github.com/ionic-team/capacitor-plugins/commit/e062901fc2e55cf6b6dc1ab20258d80a0be8b2d9)) +* Action Sheet plugin ([#42](https://github.com/ionic-team/capacitor-plugins/issues/42)) ([8435243](https://github.com/ionic-team/capacitor-plugins/commit/84352432587a424588e81a06bdde5cd4d83aa2cd)) +* add commonjs output format ([#179](https://github.com/ionic-team/capacitor-plugins/issues/179)) ([8e9e098](https://github.com/ionic-team/capacitor-plugins/commit/8e9e09862064b3f6771d7facbc4008e995d9b463)) +* App plugin ([#71](https://github.com/ionic-team/capacitor-plugins/issues/71)) ([94e4219](https://github.com/ionic-team/capacitor-plugins/commit/94e4219e61fbb7a51075cc430f29fc08254f659c)) +* AppLauncher plugin ([#74](https://github.com/ionic-team/capacitor-plugins/issues/74)) ([934bdb1](https://github.com/ionic-team/capacitor-plugins/commit/934bdb1d933e14c0bfdda37e948d34e1ba6f7c60)) +* Browser plugin ([#16](https://github.com/ionic-team/capacitor-plugins/issues/16)) ([6ad5597](https://github.com/ionic-team/capacitor-plugins/commit/6ad559768ad853ac11d94e39bac34a4515362735)) +* Camera plugin ([#33](https://github.com/ionic-team/capacitor-plugins/issues/33)) ([4864928](https://github.com/ionic-team/capacitor-plugins/commit/48649288b1ba45e1901ad077b3b7b7314de04d4a)) +* Clipboard plugin ([fd89544](https://github.com/ionic-team/capacitor-plugins/commit/fd895448fd7c6d105716b31eb4fe42762328513a)) +* Device plugin ([#47](https://github.com/ionic-team/capacitor-plugins/issues/47)) ([9870e30](https://github.com/ionic-team/capacitor-plugins/commit/9870e3006094062d7b10df6ab59aa9da35f6c34b)) +* Dialog plugin ([#44](https://github.com/ionic-team/capacitor-plugins/issues/44)) ([d7f0dd5](https://github.com/ionic-team/capacitor-plugins/commit/d7f0dd547699734aa44528d01662e6f984668121)) +* Filesystem plugin ([#19](https://github.com/ionic-team/capacitor-plugins/issues/19)) ([3b86a4a](https://github.com/ionic-team/capacitor-plugins/commit/3b86a4a972e00eaed1d078bfcc69af6136222dc4)) +* Geolocation plugin ([#13](https://github.com/ionic-team/capacitor-plugins/issues/13)) ([911ae71](https://github.com/ionic-team/capacitor-plugins/commit/911ae71e6aef4cfa9fb3ab5b0c13f3c06ef6b15c)) +* Haptics plugin ([#5](https://github.com/ionic-team/capacitor-plugins/issues/5)) ([95322d3](https://github.com/ionic-team/capacitor-plugins/commit/95322d385c855cff50582a7d3daff83fe4fe9e90)) +* Keyboard plugin ([#59](https://github.com/ionic-team/capacitor-plugins/issues/59)) ([3a65a9a](https://github.com/ionic-team/capacitor-plugins/commit/3a65a9a9757a34c3cd803da7479b9403d8689511)) +* Local Notifications plugin ([#94](https://github.com/ionic-team/capacitor-plugins/issues/94)) ([e59ba9c](https://github.com/ionic-team/capacitor-plugins/commit/e59ba9ceea78a26ec60e521825f228baa9d74577)) +* Motion plugin ([#17](https://github.com/ionic-team/capacitor-plugins/issues/17)) ([21ace16](https://github.com/ionic-team/capacitor-plugins/commit/21ace1670b803eec3a8d41d06c32933a170bf4be)) +* Network plugin ([#8](https://github.com/ionic-team/capacitor-plugins/issues/8)) ([08d9891](https://github.com/ionic-team/capacitor-plugins/commit/08d9891710d576ee3c660b4d8dce89c4169d3e0b)) +* Push Notifications plugin ([#126](https://github.com/ionic-team/capacitor-plugins/issues/126)) ([0bcd833](https://github.com/ionic-team/capacitor-plugins/commit/0bcd833a6503061be45253b21fca9bd75576efc8)) +* Screen Reader plugin ([#1](https://github.com/ionic-team/capacitor-plugins/issues/1)) ([d0ab633](https://github.com/ionic-team/capacitor-plugins/commit/d0ab63335a3ba1d303dc11e0fc72767200e6390b)) +* Share plugin ([#39](https://github.com/ionic-team/capacitor-plugins/issues/39)) ([9076c8e](https://github.com/ionic-team/capacitor-plugins/commit/9076c8e6b83b80514d23c809035fd7579b2e607a)) +* SplashScreen plugin ([#149](https://github.com/ionic-team/capacitor-plugins/issues/149)) ([c5f44be](https://github.com/ionic-team/capacitor-plugins/commit/c5f44bee46d06bd9a2623cd907862633ee5331eb)) +* Status Bar plugin ([#58](https://github.com/ionic-team/capacitor-plugins/issues/58)) ([9a04a5d](https://github.com/ionic-team/capacitor-plugins/commit/9a04a5daa16a283383afba58acde1d11d81378ec)) +* Storage plugin ([#15](https://github.com/ionic-team/capacitor-plugins/issues/15)) ([9dfdd85](https://github.com/ionic-team/capacitor-plugins/commit/9dfdd85b39c0df90db416a4bed094d03640fbe34)) +* Text Zoom plugin ([#9](https://github.com/ionic-team/capacitor-plugins/issues/9)) ([cc18d0f](https://github.com/ionic-team/capacitor-plugins/commit/cc18d0fb1b6f4509d95a4114c92255d8d7873311)) +* Toast plugin ([#52](https://github.com/ionic-team/capacitor-plugins/issues/52)) ([b52dc47](https://github.com/ionic-team/capacitor-plugins/commit/b52dc471291bcf6ad54ed1ffde6ecf3327ecd747)) diff --git a/README.md b/README.md index 13cee43be..103d1fbc0 100644 --- a/README.md +++ b/README.md @@ -2,37 +2,40 @@ This repository contains the official Capacitor plugins maintained by the Capacitor team. You can find more plugins in the [Capacitor Community](https://github.com/capacitor-community/). -> ### :rotating_light: These plugins are for Capacitor 3 :rotating_light: +> ### :rotating_light: These plugins are for Capacitor 4 :rotating_light: > > Capacitor 2 core plugins are bundled with Capacitor itself. +> +> For Capacitor 3, use the 1.x version of the plugins. ## Plugins | Package | Source | Version | | --- | --- | --- | -| [`@capacitor/action-sheet`](https://capacitorjs.com/docs/v3/apis/action-sheet) | [`./action-sheet`](./action-sheet) | [![npm badge](https://img.shields.io/npm/v/@capacitor/action-sheet?style=flat-square)](https://www.npmjs.com/package/@capacitor/action-sheet) -| [`@capacitor/app-launcher`](https://capacitorjs.com/docs/v3/apis/app-launcher) | [`./app-launcher`](./app-launcher) | [![npm badge](https://img.shields.io/npm/v/@capacitor/app-launcher?style=flat-square)](https://www.npmjs.com/package/@capacitor/app-launcher) -| [`@capacitor/app`](https://capacitorjs.com/docs/v3/apis/app) | [`./app`](./app) | [![npm badge](https://img.shields.io/npm/v/@capacitor/app?style=flat-square)](https://www.npmjs.com/package/@capacitor/app) -| [`@capacitor/browser`](https://capacitorjs.com/docs/v3/apis/browser) | [`./browser`](./browser) | [![npm badge](https://img.shields.io/npm/v/@capacitor/browser?style=flat-square)](https://www.npmjs.com/package/@capacitor/browser) -| [`@capacitor/camera`](https://capacitorjs.com/docs/v3/apis/camera) | [`./camera`](./camera) | [![npm badge](https://img.shields.io/npm/v/@capacitor/camera?style=flat-square)](https://www.npmjs.com/package/@capacitor/camera) -| [`@capacitor/clipboard`](https://capacitorjs.com/docs/v3/apis/clipboard) | [`./clipboard`](./clipboard) | [![npm badge](https://img.shields.io/npm/v/@capacitor/clipboard?style=flat-square)](https://www.npmjs.com/package/@capacitor/clipboard) -| [`@capacitor/device`](https://capacitorjs.com/docs/v3/apis/device) | [`./device`](./device) | [![npm badge](https://img.shields.io/npm/v/@capacitor/device?style=flat-square)](https://www.npmjs.com/package/@capacitor/device) -| [`@capacitor/dialog`](https://capacitorjs.com/docs/v3/apis/dialog) | [`./dialog`](./dialog) | [![npm badge](https://img.shields.io/npm/v/@capacitor/dialog?style=flat-square)](https://www.npmjs.com/package/@capacitor/dialog) -| [`@capacitor/filesystem`](https://capacitorjs.com/docs/v3/apis/filesystem) | [`./filesystem`](./filesystem) | [![npm badge](https://img.shields.io/npm/v/@capacitor/filesystem?style=flat-square)](https://www.npmjs.com/package/@capacitor/filesystem) -| [`@capacitor/geolocation`](https://capacitorjs.com/docs/v3/apis/geolocation) | [`./geolocation`](./geolocation) | [![npm badge](https://img.shields.io/npm/v/@capacitor/geolocation?style=flat-square)](https://www.npmjs.com/package/@capacitor/geolocation) -| [`@capacitor/haptics`](https://capacitorjs.com/docs/v3/apis/haptics) | [`./haptics`](./haptics) | [![npm badge](https://img.shields.io/npm/v/@capacitor/haptics?style=flat-square)](https://www.npmjs.com/package/@capacitor/haptics) -| [`@capacitor/keyboard`](https://capacitorjs.com/docs/v3/apis/keyboard) | [`./keyboard`](./keyboard) | [![npm badge](https://img.shields.io/npm/v/@capacitor/keyboard?style=flat-square)](https://www.npmjs.com/package/@capacitor/keyboard) -| [`@capacitor/local-notifications`](https://capacitorjs.com/docs/v3/apis/local-notifications) | [`./local-notifications`](./local-notifications) | [![npm badge](https://img.shields.io/npm/v/@capacitor/local-notifications?style=flat-square)](https://www.npmjs.com/package/@capacitor/local-notifications) -| [`@capacitor/motion`](https://capacitorjs.com/docs/v3/apis/motion) | [`./motion`](./motion) | [![npm badge](https://img.shields.io/npm/v/@capacitor/motion?style=flat-square)](https://www.npmjs.com/package/@capacitor/motion) -| [`@capacitor/network`](https://capacitorjs.com/docs/v3/apis/network) | [`./network`](./network) | [![npm badge](https://img.shields.io/npm/v/@capacitor/network?style=flat-square)](https://www.npmjs.com/package/@capacitor/network) -| [`@capacitor/push-notifications`](https://capacitorjs.com/docs/v3/apis/push-notifications) | [`./push-notifications`](./push-notifications) | [![npm badge](https://img.shields.io/npm/v/@capacitor/push-notifications?style=flat-square)](https://www.npmjs.com/package/@capacitor/push-notifications) -| [`@capacitor/screen-reader`](https://capacitorjs.com/docs/v3/apis/screen-reader) | [`./screen-reader`](./screen-reader) | [![npm badge](https://img.shields.io/npm/v/@capacitor/screen-reader?style=flat-square)](https://www.npmjs.com/package/@capacitor/screen-reader) -| [`@capacitor/share`](https://capacitorjs.com/docs/v3/apis/share) | [`./share`](./share) | [![npm badge](https://img.shields.io/npm/v/@capacitor/share?style=flat-square)](https://www.npmjs.com/package/@capacitor/share) -| [`@capacitor/splash-screen`](https://capacitorjs.com/docs/v3/apis/splash-screen) | [`./splash-screen`](./splash-screen) | [![npm badge](https://img.shields.io/npm/v/@capacitor/splash-screen?style=flat-square)](https://www.npmjs.com/package/@capacitor/splash-screen) -| [`@capacitor/status-bar`](https://capacitorjs.com/docs/v3/apis/status-bar) | [`./status-bar`](./status-bar) | [![npm badge](https://img.shields.io/npm/v/@capacitor/status-bar?style=flat-square)](https://www.npmjs.com/package/@capacitor/status-bar) -| [`@capacitor/storage`](https://capacitorjs.com/docs/v3/apis/storage) | [`./storage`](./storage) | [![npm badge](https://img.shields.io/npm/v/@capacitor/storage?style=flat-square)](https://www.npmjs.com/package/@capacitor/storage) -| [`@capacitor/text-zoom`](https://capacitorjs.com/docs/v3/apis/text-zoom) | [`./text-zoom`](./text-zoom) | [![npm badge](https://img.shields.io/npm/v/@capacitor/text-zoom?style=flat-square)](https://www.npmjs.com/package/@capacitor/text-zoom) -| [`@capacitor/toast`](https://capacitorjs.com/docs/v3/apis/toast) | [`./toast`](./toast) | [![npm badge](https://img.shields.io/npm/v/@capacitor/toast?style=flat-square)](https://www.npmjs.com/package/@capacitor/toast) +| [`@capacitor/action-sheet`](https://capacitorjs.com/docs/apis/action-sheet) | [`./action-sheet`](./action-sheet) | [![npm badge](https://img.shields.io/npm/v/@capacitor/action-sheet?style=flat-square)](https://www.npmjs.com/package/@capacitor/action-sheet) +| [`@capacitor/app-launcher`](https://capacitorjs.com/docs/apis/app-launcher) | [`./app-launcher`](./app-launcher) | [![npm badge](https://img.shields.io/npm/v/@capacitor/app-launcher?style=flat-square)](https://www.npmjs.com/package/@capacitor/app-launcher) +| [`@capacitor/app`](https://capacitorjs.com/docs/apis/app) | [`./app`](./app) | [![npm badge](https://img.shields.io/npm/v/@capacitor/app?style=flat-square)](https://www.npmjs.com/package/@capacitor/app) +| [`@capacitor/browser`](https://capacitorjs.com/docs/apis/browser) | [`./browser`](./browser) | [![npm badge](https://img.shields.io/npm/v/@capacitor/browser?style=flat-square)](https://www.npmjs.com/package/@capacitor/browser) +| [`@capacitor/camera`](https://capacitorjs.com/docs/apis/camera) | [`./camera`](./camera) | [![npm badge](https://img.shields.io/npm/v/@capacitor/camera?style=flat-square)](https://www.npmjs.com/package/@capacitor/camera) +| [`@capacitor/clipboard`](https://capacitorjs.com/docs/apis/clipboard) | [`./clipboard`](./clipboard) | [![npm badge](https://img.shields.io/npm/v/@capacitor/clipboard?style=flat-square)](https://www.npmjs.com/package/@capacitor/clipboard) +| [`@capacitor/device`](https://capacitorjs.com/docs/apis/device) | [`./device`](./device) | [![npm badge](https://img.shields.io/npm/v/@capacitor/device?style=flat-square)](https://www.npmjs.com/package/@capacitor/device) +| [`@capacitor/dialog`](https://capacitorjs.com/docs/apis/dialog) | [`./dialog`](./dialog) | [![npm badge](https://img.shields.io/npm/v/@capacitor/dialog?style=flat-square)](https://www.npmjs.com/package/@capacitor/dialog) +| [`@capacitor/filesystem`](https://capacitorjs.com/docs/apis/filesystem) | [`./filesystem`](./filesystem) | [![npm badge](https://img.shields.io/npm/v/@capacitor/filesystem?style=flat-square)](https://www.npmjs.com/package/@capacitor/filesystem) +| [`@capacitor/geolocation`](https://capacitorjs.com/docs/apis/geolocation) | [`./geolocation`](./geolocation) | [![npm badge](https://img.shields.io/npm/v/@capacitor/geolocation?style=flat-square)](https://www.npmjs.com/package/@capacitor/geolocation) +| [`@capacitor/google-maps`](https://capacitorjs.com/docs/apis/google-maps) | [`./google-maps`](./google-maps) | [![npm badge](https://img.shields.io/npm/v/@capacitor/google-maps?style=flat-square)](https://www.npmjs.com/package/@capacitor/google-maps) +| [`@capacitor/haptics`](https://capacitorjs.com/docs/apis/haptics) | [`./haptics`](./haptics) | [![npm badge](https://img.shields.io/npm/v/@capacitor/haptics?style=flat-square)](https://www.npmjs.com/package/@capacitor/haptics) +| [`@capacitor/keyboard`](https://capacitorjs.com/docs/apis/keyboard) | [`./keyboard`](./keyboard) | [![npm badge](https://img.shields.io/npm/v/@capacitor/keyboard?style=flat-square)](https://www.npmjs.com/package/@capacitor/keyboard) +| [`@capacitor/local-notifications`](https://capacitorjs.com/docs/apis/local-notifications) | [`./local-notifications`](./local-notifications) | [![npm badge](https://img.shields.io/npm/v/@capacitor/local-notifications?style=flat-square)](https://www.npmjs.com/package/@capacitor/local-notifications) +| [`@capacitor/motion`](https://capacitorjs.com/docs/apis/motion) | [`./motion`](./motion) | [![npm badge](https://img.shields.io/npm/v/@capacitor/motion?style=flat-square)](https://www.npmjs.com/package/@capacitor/motion) +| [`@capacitor/network`](https://capacitorjs.com/docs/apis/network) | [`./network`](./network) | [![npm badge](https://img.shields.io/npm/v/@capacitor/network?style=flat-square)](https://www.npmjs.com/package/@capacitor/network) +| [`@capacitor/preferences`](https://capacitorjs.com/docs/apis/preferences) | [`./preferences`](./preferences) | [![npm badge](https://img.shields.io/npm/v/@capacitor/preferences?style=flat-square)](https://www.npmjs.com/package/@capacitor/preferences) +| [`@capacitor/push-notifications`](https://capacitorjs.com/docs/apis/push-notifications) | [`./push-notifications`](./push-notifications) | [![npm badge](https://img.shields.io/npm/v/@capacitor/push-notifications?style=flat-square)](https://www.npmjs.com/package/@capacitor/push-notifications) +| [`@capacitor/screen-reader`](https://capacitorjs.com/docs/apis/screen-reader) | [`./screen-reader`](./screen-reader) | [![npm badge](https://img.shields.io/npm/v/@capacitor/screen-reader?style=flat-square)](https://www.npmjs.com/package/@capacitor/screen-reader) +| [`@capacitor/share`](https://capacitorjs.com/docs/apis/share) | [`./share`](./share) | [![npm badge](https://img.shields.io/npm/v/@capacitor/share?style=flat-square)](https://www.npmjs.com/package/@capacitor/share) +| [`@capacitor/splash-screen`](https://capacitorjs.com/docs/apis/splash-screen) | [`./splash-screen`](./splash-screen) | [![npm badge](https://img.shields.io/npm/v/@capacitor/splash-screen?style=flat-square)](https://www.npmjs.com/package/@capacitor/splash-screen) +| [`@capacitor/status-bar`](https://capacitorjs.com/docs/apis/status-bar) | [`./status-bar`](./status-bar) | [![npm badge](https://img.shields.io/npm/v/@capacitor/status-bar?style=flat-square)](https://www.npmjs.com/package/@capacitor/status-bar) +| [`@capacitor/text-zoom`](https://capacitorjs.com/docs/apis/text-zoom) | [`./text-zoom`](./text-zoom) | [![npm badge](https://img.shields.io/npm/v/@capacitor/text-zoom?style=flat-square)](https://www.npmjs.com/package/@capacitor/text-zoom) +| [`@capacitor/toast`](https://capacitorjs.com/docs/apis/toast) | [`./toast`](./toast) | [![npm badge](https://img.shields.io/npm/v/@capacitor/toast?style=flat-square)](https://www.npmjs.com/package/@capacitor/toast) ## Contributing diff --git a/action-sheet/CHANGELOG.md b/action-sheet/CHANGELOG.md index e11860289..84f2be12b 100644 --- a/action-sheet/CHANGELOG.md +++ b/action-sheet/CHANGELOG.md @@ -3,6 +3,98 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.1.0](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/action-sheet@1.0.8...@capacitor/action-sheet@4.1.0) (2022-11-16) + + + +## 4.0.1 (2022-07-28) + + + +# 4.0.0 (2022-07-27) + + + +# 4.0.0-beta.2 (2022-07-08) + + + +# 4.0.0-beta.0 (2022-06-27) + + +### Features + +* set targetSDK default value to 32 ([#970](https://github.com/ionic-team/capacitor-plugins/issues/970)) ([fa70d96](https://github.com/ionic-team/capacitor-plugins/commit/fa70d96f141af751aae53ceb5642c46b204f5958)) +* Use java 11 ([#910](https://github.com/ionic-team/capacitor-plugins/issues/910)) ([5acb2a2](https://github.com/ionic-team/capacitor-plugins/commit/5acb2a288a413492b163e4e97da46a085d9e4be0)) +* **action-sheet:** Make title optional ([#805](https://github.com/ionic-team/capacitor-plugins/issues/805)) ([2018f78](https://github.com/ionic-team/capacitor-plugins/commit/2018f7823cc25ea39c3533772512d221d2dba926)) +* set targetSDK default value to 31 ([#824](https://github.com/ionic-team/capacitor-plugins/issues/824)) ([3ee10de](https://github.com/ionic-team/capacitor-plugins/commit/3ee10de98067984c1a4e75295d001c5a895c47f4)) +* Upgrade gradle to 7.4 ([#826](https://github.com/ionic-team/capacitor-plugins/issues/826)) ([5db0906](https://github.com/ionic-team/capacitor-plugins/commit/5db0906f6264287c4f8e69dbaecf19d4d387824b)) + + + + + +## [4.0.1](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0...4.0.1) (2022-07-28) + +**Note:** Version bump only for package @capacitor/action-sheet + + + + + +# [4.0.0](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0-beta.2...4.0.0) (2022-07-27) + +**Note:** Version bump only for package @capacitor/action-sheet + + + + + +# [4.0.0-beta.2](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0-beta.0...4.0.0-beta.2) (2022-07-08) + +**Note:** Version bump only for package @capacitor/action-sheet + + + + + +# 4.0.0-beta.0 (2022-06-27) + + +### Bug Fixes + +* add es2017 lib to tsconfig ([#180](https://github.com/ionic-team/capacitor-plugins/issues/180)) ([2c3776c](https://github.com/ionic-team/capacitor-plugins/commit/2c3776c38ca025c5ee965dec10ccf1cdb6c02e2f)) +* correct addListeners links ([#655](https://github.com/ionic-team/capacitor-plugins/issues/655)) ([f9871e7](https://github.com/ionic-team/capacitor-plugins/commit/f9871e7bd53478addb21155e148829f550c0e457)) +* inline source code in esm map files ([#760](https://github.com/ionic-team/capacitor-plugins/issues/760)) ([a960489](https://github.com/ionic-team/capacitor-plugins/commit/a960489a19db0182b90d187a50deff9dfbe51038)) +* Migrate plugins from Color.parseColor() to WebColor.parseColor() ([#140](https://github.com/ionic-team/capacitor-plugins/issues/140)) ([26625cf](https://github.com/ionic-team/capacitor-plugins/commit/26625cfefe45b8d1f17ce27efbc8b04f23e99d93)) +* remove postpublish scripts ([#656](https://github.com/ionic-team/capacitor-plugins/issues/656)) ([ed6ac49](https://github.com/ionic-team/capacitor-plugins/commit/ed6ac499ebf4a47525071ccbfc36c27503e11f60)) +* **action-sheet:** add back deprecated `ActionSheetOptionStyle` type ([e026425](https://github.com/ionic-team/capacitor-plugins/commit/e0264256532624d5892e9b5468be89cd400cf823)) +* support deprecated types from Capacitor 2 ([#139](https://github.com/ionic-team/capacitor-plugins/issues/139)) ([2d7127a](https://github.com/ionic-team/capacitor-plugins/commit/2d7127a488e26f0287951921a6db47c49d817336)) +* **action-sheet:** change package name to 'actionsheet' ([#57](https://github.com/ionic-team/capacitor-plugins/issues/57)) ([5cf608b](https://github.com/ionic-team/capacitor-plugins/commit/5cf608bb82106297a8610b72c7e636d6bfd372de)) + + +### Features + +* Action Sheet plugin ([#42](https://github.com/ionic-team/capacitor-plugins/issues/42)) ([8435243](https://github.com/ionic-team/capacitor-plugins/commit/84352432587a424588e81a06bdde5cd4d83aa2cd)) +* set targetSDK default value to 32 ([#970](https://github.com/ionic-team/capacitor-plugins/issues/970)) ([fa70d96](https://github.com/ionic-team/capacitor-plugins/commit/fa70d96f141af751aae53ceb5642c46b204f5958)) +* Use java 11 ([#910](https://github.com/ionic-team/capacitor-plugins/issues/910)) ([5acb2a2](https://github.com/ionic-team/capacitor-plugins/commit/5acb2a288a413492b163e4e97da46a085d9e4be0)) +* **action-sheet:** Make title optional ([#805](https://github.com/ionic-team/capacitor-plugins/issues/805)) ([2018f78](https://github.com/ionic-team/capacitor-plugins/commit/2018f7823cc25ea39c3533772512d221d2dba926)) +* add commonjs output format ([#179](https://github.com/ionic-team/capacitor-plugins/issues/179)) ([8e9e098](https://github.com/ionic-team/capacitor-plugins/commit/8e9e09862064b3f6771d7facbc4008e995d9b463)) +* set targetSDK default value to 31 ([#824](https://github.com/ionic-team/capacitor-plugins/issues/824)) ([3ee10de](https://github.com/ionic-team/capacitor-plugins/commit/3ee10de98067984c1a4e75295d001c5a895c47f4)) +* Upgrade gradle to 7.4 ([#826](https://github.com/ionic-team/capacitor-plugins/issues/826)) ([5db0906](https://github.com/ionic-team/capacitor-plugins/commit/5db0906f6264287c4f8e69dbaecf19d4d387824b)) + + + + + +## [1.0.8](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/action-sheet@1.0.7...@capacitor/action-sheet@1.0.8) (2022-02-10) + +**Note:** Version bump only for package @capacitor/action-sheet + + + + + ## [1.0.7](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/action-sheet@1.0.6...@capacitor/action-sheet@1.0.7) (2022-01-19) diff --git a/action-sheet/CapacitorActionSheet.podspec b/action-sheet/CapacitorActionSheet.podspec index cd70d07fd..ea4f9dab9 100644 --- a/action-sheet/CapacitorActionSheet.podspec +++ b/action-sheet/CapacitorActionSheet.podspec @@ -11,7 +11,7 @@ Pod::Spec.new do |s| s.author = package['author'] s.source = { :git => 'https://github.com/ionic-team/capacitor-plugins.git', :tag => package['name'] + '@' + package['version'] } s.source_files = 'ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}', 'action-sheet/ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}' - s.ios.deployment_target = '12.0' + s.ios.deployment_target = '13.0' s.dependency 'Capacitor' s.swift_version = '5.1' end diff --git a/action-sheet/README.md b/action-sheet/README.md index 2ac412535..6333ae006 100644 --- a/action-sheet/README.md +++ b/action-sheet/README.md @@ -13,7 +13,11 @@ npx cap sync This plugin will use the following project variables (defined in your app's `variables.gradle` file): -- `$androidxMaterialVersion`: version of `com.google.android.material:material` (default: `1.3.0`) +- `$androidxMaterialVersion`: version of `com.google.android.material:material` (default: `1.6.1`) + +## PWA Notes + +[PWA Elements](https://capacitorjs.com/docs/web/pwa-elements) are required for Action Sheet plugin to work. ## Example diff --git a/action-sheet/android/build.gradle b/action-sheet/android/build.gradle index 26fad3155..91c2c8917 100644 --- a/action-sheet/android/build.gradle +++ b/action-sheet/android/build.gradle @@ -1,28 +1,40 @@ ext { - junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.1' - androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.2.0' - androidxMaterialVersion = project.hasProperty('androidxMaterialVersion') ? rootProject.ext.androidxMaterialVersion : '1.3.0' - androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.1.2' - androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.3.0' + capacitorVersion = System.getenv('CAPACITOR_VERSION') + junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.2' + androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.4.2' + androidxMaterialVersion = project.hasProperty('androidxMaterialVersion') ? rootProject.ext.androidxMaterialVersion : '1.6.1' + androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.1.3' + androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.4.0' } buildscript { repositories { google() mavenCentral() + maven { + url "https://plugins.gradle.org/m2/" + } } dependencies { - classpath 'com.android.tools.build:gradle:4.2.1' + classpath 'com.android.tools.build:gradle:7.2.1' + if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + classpath 'io.github.gradle-nexus:publish-plugin:1.1.0' + } } } apply plugin: 'com.android.library' +if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + apply plugin: 'io.github.gradle-nexus.publish-plugin' + apply from: file('../../scripts/android/publish-root.gradle') + apply from: file('../../scripts/android/publish-module.gradle') +} android { - compileSdkVersion project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 30 + compileSdkVersion project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 32 defaultConfig { - minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 21 - targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 30 + minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 22 + targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 32 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" @@ -37,21 +49,26 @@ android { abortOnError false } compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility JavaVersion.VERSION_11 + targetCompatibility JavaVersion.VERSION_11 } } repositories { google() mavenCentral() - jcenter() } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation project(':capacitor-android') + + if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + implementation "com.capacitorjs:core:$capacitorVersion" + } else { + implementation project(':capacitor-android') + } + implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion" implementation "com.google.android.material:material:$androidxMaterialVersion" testImplementation "junit:junit:$junitVersion" diff --git a/action-sheet/android/gradle/wrapper/gradle-wrapper.jar b/action-sheet/android/gradle/wrapper/gradle-wrapper.jar index e708b1c02..41d9927a4 100644 Binary files a/action-sheet/android/gradle/wrapper/gradle-wrapper.jar and b/action-sheet/android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/action-sheet/android/gradle/wrapper/gradle-wrapper.properties b/action-sheet/android/gradle/wrapper/gradle-wrapper.properties index 3c4101c3e..92f06b50f 100644 --- a/action-sheet/android/gradle/wrapper/gradle-wrapper.properties +++ b/action-sheet/android/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/action-sheet/android/gradlew b/action-sheet/android/gradlew index 4f906e0c8..1b6c78733 100755 --- a/action-sheet/android/gradlew +++ b/action-sheet/android/gradlew @@ -1,7 +1,7 @@ -#!/usr/bin/env sh +#!/bin/sh # -# Copyright 2015 the original author or authors. +# Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,67 +17,101 @@ # ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` +APP_BASE_NAME=${0##*/} # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar @@ -87,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -98,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" + JAVACMD=java which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the @@ -106,80 +140,95 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=`expr $i + 1` + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" diff --git a/action-sheet/android/src/main/java/com/capacitorjs/plugins/actionsheet/ActionSheet.java b/action-sheet/android/src/main/java/com/capacitorjs/plugins/actionsheet/ActionSheet.java index 2690ea396..13a78f11a 100644 --- a/action-sheet/android/src/main/java/com/capacitorjs/plugins/actionsheet/ActionSheet.java +++ b/action-sheet/android/src/main/java/com/capacitorjs/plugins/actionsheet/ActionSheet.java @@ -86,11 +86,13 @@ public void setupDialog(Dialog dialog, int style) { LinearLayout layout = new LinearLayout(getContext()); layout.setOrientation(LinearLayout.VERTICAL); layout.setPadding(layoutPaddingPx16, layoutPaddingPx16, layoutPaddingPx16, layoutPaddingPx16); - TextView ttv = new TextView(getContext()); - ttv.setTextColor(Color.parseColor("#757575")); - ttv.setPadding(layoutPaddingPx8, layoutPaddingPx8, layoutPaddingPx8, layoutPaddingPx8); - ttv.setText(title); - layout.addView(ttv); + if (title != null) { + TextView ttv = new TextView(getContext()); + ttv.setTextColor(Color.parseColor("#757575")); + ttv.setPadding(layoutPaddingPx8, layoutPaddingPx8, layoutPaddingPx8, layoutPaddingPx8); + ttv.setText(title); + layout.addView(ttv); + } for (int i = 0; i < options.length; i++) { final int optionIndex = i; diff --git a/action-sheet/android/src/main/java/com/capacitorjs/plugins/actionsheet/ActionSheetPlugin.java b/action-sheet/android/src/main/java/com/capacitorjs/plugins/actionsheet/ActionSheetPlugin.java index 4c62a8ae7..7ca88b8e4 100644 --- a/action-sheet/android/src/main/java/com/capacitorjs/plugins/actionsheet/ActionSheetPlugin.java +++ b/action-sheet/android/src/main/java/com/capacitorjs/plugins/actionsheet/ActionSheetPlugin.java @@ -20,10 +20,6 @@ public class ActionSheetPlugin extends Plugin { public void showActions(final PluginCall call) { String title = call.getString("title"); JSArray options = call.getArray("options"); - if (title == null) { - call.reject("Must supply a title"); - return; - } if (options == null) { call.reject("Must supply options"); return; diff --git a/action-sheet/ios/Plugin.xcodeproj/project.pbxproj b/action-sheet/ios/Plugin.xcodeproj/project.pbxproj index 224111dcc..6f11bdc1d 100644 --- a/action-sheet/ios/Plugin.xcodeproj/project.pbxproj +++ b/action-sheet/ios/Plugin.xcodeproj/project.pbxproj @@ -386,7 +386,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -446,7 +446,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; @@ -469,12 +469,13 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Plugin/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks $(FRAMEWORK_SEARCH_PATHS)\n$(FRAMEWORK_SEARCH_PATHS)\n$(FRAMEWORK_SEARCH_PATHS)"; ONLY_ACTIVE_ARCH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.getcapacitor.Plugin; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; + SUPPORTS_MACCATALYST = NO; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -494,12 +495,13 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Plugin/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks $(FRAMEWORK_SEARCH_PATHS)"; ONLY_ACTIVE_ARCH = NO; PRODUCT_BUNDLE_IDENTIFIER = com.getcapacitor.Plugin; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; + SUPPORTS_MACCATALYST = NO; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; diff --git a/action-sheet/ios/Plugin/ActionSheet.swift b/action-sheet/ios/Plugin/ActionSheet.swift index 72a18211d..ceeff00fd 100644 --- a/action-sheet/ios/Plugin/ActionSheet.swift +++ b/action-sheet/ios/Plugin/ActionSheet.swift @@ -3,7 +3,7 @@ import UIKit @objc public class ActionSheet: NSObject { - @objc public func buildActionSheet(title: String, message: String, actions: [UIAlertAction]) -> UIAlertController { + @objc public func buildActionSheet(title: String?, message: String?, actions: [UIAlertAction]) -> UIAlertController { let controller = UIAlertController(title: title, message: message, preferredStyle: .actionSheet) for action in actions { controller.addAction(action) diff --git a/action-sheet/ios/Plugin/ActionSheetPlugin.swift b/action-sheet/ios/Plugin/ActionSheetPlugin.swift index 140b2b155..8b044478d 100644 --- a/action-sheet/ios/Plugin/ActionSheetPlugin.swift +++ b/action-sheet/ios/Plugin/ActionSheetPlugin.swift @@ -10,11 +10,8 @@ public class ActionSheetPlugin: CAPPlugin { private let implementation = ActionSheet() @objc func showActions(_ call: CAPPluginCall) { - guard let title = call.options["title"] as? String else { - call.reject("title must be provided") - return - } - let message = call.options["message"] as? String ?? "" + let title = call.options["title"] as? String + let message = call.options["message"] as? String let options = call.getArray("options", JSObject.self) ?? [] var alertActions = [UIAlertAction]() diff --git a/action-sheet/ios/Podfile b/action-sheet/ios/Podfile index 54a00c161..dee40960f 100644 --- a/action-sheet/ios/Podfile +++ b/action-sheet/ios/Podfile @@ -1,4 +1,4 @@ -platform :ios, '12.0' +platform :ios, '13.0' def capacitor_pods # Comment the next line if you're not using Swift and don't want to use dynamic frameworks diff --git a/action-sheet/package.json b/action-sheet/package.json index a1cf2746e..8b430e267 100644 --- a/action-sheet/package.json +++ b/action-sheet/package.json @@ -1,6 +1,6 @@ { "name": "@capacitor/action-sheet", - "version": "1.0.7", + "version": "4.1.0", "description": "The Action Sheet API provides access to native Action Sheets, which come up from the bottom of the screen and display actions a user can take.", "main": "dist/plugin.cjs.js", "module": "dist/esm/index.js", @@ -29,7 +29,7 @@ ], "scripts": { "verify": "npm run verify:ios && npm run verify:android && npm run verify:web", - "verify:ios": "cd ios && pod install && xcodebuild -workspace Plugin.xcworkspace -scheme Plugin && cd ..", + "verify:ios": "cd ios && pod install && xcodebuild -workspace Plugin.xcworkspace -scheme Plugin -destination generic/platform=iOS && cd ..", "verify:android": "cd android && ./gradlew clean build test && cd ..", "verify:web": "npm run build", "lint": "npm run eslint && npm run prettier -- --check && npm run swiftlint -- lint", @@ -45,10 +45,10 @@ "publish:cocoapod": "pod trunk push ./CapacitorActionSheet.podspec --allow-warnings" }, "devDependencies": { - "@capacitor/android": "^3.0.0", - "@capacitor/core": "^3.0.0", - "@capacitor/docgen": "0.0.18", - "@capacitor/ios": "^3.0.0", + "@capacitor/android": "^4.0.0", + "@capacitor/core": "^4.0.0", + "@capacitor/docgen": "0.2.0", + "@capacitor/ios": "^4.0.0", "@ionic/eslint-config": "^0.3.0", "@ionic/prettier-config": "~1.0.1", "@ionic/swiftlint-config": "^1.1.2", @@ -61,7 +61,7 @@ "typescript": "~4.1.5" }, "peerDependencies": { - "@capacitor/core": "^3.0.0" + "@capacitor/core": "^4.0.0" }, "prettier": "@ionic/prettier-config", "swiftlint": "@ionic/swiftlint-config", diff --git a/action-sheet/src/definitions.ts b/action-sheet/src/definitions.ts index 98f65a1c5..84dbfbaae 100644 --- a/action-sheet/src/definitions.ts +++ b/action-sheet/src/definitions.ts @@ -4,7 +4,7 @@ export interface ShowActionsOptions { * * @since 1.0.0 */ - title: string; + title?: string; /** * A message to show under the title. diff --git a/app-launcher/CHANGELOG.md b/app-launcher/CHANGELOG.md index 98dee72f2..3c63582b1 100644 --- a/app-launcher/CHANGELOG.md +++ b/app-launcher/CHANGELOG.md @@ -3,6 +3,94 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.1.0](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/app-launcher@1.0.9...@capacitor/app-launcher@4.1.0) (2022-11-16) + + + +## 4.0.1 (2022-07-28) + + + +# 4.0.0 (2022-07-27) + + + +# 4.0.0-beta.2 (2022-07-08) + + + +# 4.0.0-beta.0 (2022-06-27) + + +### Features + +* set targetSDK default value to 31 ([#824](https://github.com/ionic-team/capacitor-plugins/issues/824)) ([3ee10de](https://github.com/ionic-team/capacitor-plugins/commit/3ee10de98067984c1a4e75295d001c5a895c47f4)) +* set targetSDK default value to 32 ([#970](https://github.com/ionic-team/capacitor-plugins/issues/970)) ([fa70d96](https://github.com/ionic-team/capacitor-plugins/commit/fa70d96f141af751aae53ceb5642c46b204f5958)) +* Upgrade gradle to 7.4 ([#826](https://github.com/ionic-team/capacitor-plugins/issues/826)) ([5db0906](https://github.com/ionic-team/capacitor-plugins/commit/5db0906f6264287c4f8e69dbaecf19d4d387824b)) +* Use java 11 ([#910](https://github.com/ionic-team/capacitor-plugins/issues/910)) ([5acb2a2](https://github.com/ionic-team/capacitor-plugins/commit/5acb2a288a413492b163e4e97da46a085d9e4be0)) + + + + + +## [4.0.1](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0...4.0.1) (2022-07-28) + +**Note:** Version bump only for package @capacitor/app-launcher + + + + + +# [4.0.0](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0-beta.2...4.0.0) (2022-07-27) + +**Note:** Version bump only for package @capacitor/app-launcher + + + + + +# [4.0.0-beta.2](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0-beta.0...4.0.0-beta.2) (2022-07-08) + +**Note:** Version bump only for package @capacitor/app-launcher + + + + + +# 4.0.0-beta.0 (2022-06-27) + + +### Bug Fixes + +* add es2017 lib to tsconfig ([#180](https://github.com/ionic-team/capacitor-plugins/issues/180)) ([2c3776c](https://github.com/ionic-team/capacitor-plugins/commit/2c3776c38ca025c5ee965dec10ccf1cdb6c02e2f)) +* correct addListeners links ([#655](https://github.com/ionic-team/capacitor-plugins/issues/655)) ([f9871e7](https://github.com/ionic-team/capacitor-plugins/commit/f9871e7bd53478addb21155e148829f550c0e457)) +* inline source code in esm map files ([#760](https://github.com/ionic-team/capacitor-plugins/issues/760)) ([a960489](https://github.com/ionic-team/capacitor-plugins/commit/a960489a19db0182b90d187a50deff9dfbe51038)) +* remove postpublish scripts ([#656](https://github.com/ionic-team/capacitor-plugins/issues/656)) ([ed6ac49](https://github.com/ionic-team/capacitor-plugins/commit/ed6ac499ebf4a47525071ccbfc36c27503e11f60)) +* support deprecated types from Capacitor 2 ([#139](https://github.com/ionic-team/capacitor-plugins/issues/139)) ([2d7127a](https://github.com/ionic-team/capacitor-plugins/commit/2d7127a488e26f0287951921a6db47c49d817336)) + + +### Features + +* add commonjs output format ([#179](https://github.com/ionic-team/capacitor-plugins/issues/179)) ([8e9e098](https://github.com/ionic-team/capacitor-plugins/commit/8e9e09862064b3f6771d7facbc4008e995d9b463)) +* AppLauncher plugin ([#74](https://github.com/ionic-team/capacitor-plugins/issues/74)) ([934bdb1](https://github.com/ionic-team/capacitor-plugins/commit/934bdb1d933e14c0bfdda37e948d34e1ba6f7c60)) +* set targetSDK default value to 31 ([#824](https://github.com/ionic-team/capacitor-plugins/issues/824)) ([3ee10de](https://github.com/ionic-team/capacitor-plugins/commit/3ee10de98067984c1a4e75295d001c5a895c47f4)) +* set targetSDK default value to 32 ([#970](https://github.com/ionic-team/capacitor-plugins/issues/970)) ([fa70d96](https://github.com/ionic-team/capacitor-plugins/commit/fa70d96f141af751aae53ceb5642c46b204f5958)) +* Upgrade gradle to 7.4 ([#826](https://github.com/ionic-team/capacitor-plugins/issues/826)) ([5db0906](https://github.com/ionic-team/capacitor-plugins/commit/5db0906f6264287c4f8e69dbaecf19d4d387824b)) +* Use java 11 ([#910](https://github.com/ionic-team/capacitor-plugins/issues/910)) ([5acb2a2](https://github.com/ionic-team/capacitor-plugins/commit/5acb2a288a413492b163e4e97da46a085d9e4be0)) +* **app-launcher:** make openUrl open urls on web ([#152](https://github.com/ionic-team/capacitor-plugins/issues/152)) ([2eba7b4](https://github.com/ionic-team/capacitor-plugins/commit/2eba7b41a05be2f63c916f51aa4b36ef548ef87c)) + + + + + +## [1.0.9](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/app-launcher@1.0.8...@capacitor/app-launcher@1.0.9) (2022-03-03) + +**Note:** Version bump only for package @capacitor/app-launcher + + + + + ## [1.0.8](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/app-launcher@1.0.7...@capacitor/app-launcher@1.0.8) (2022-01-19) diff --git a/app-launcher/CapacitorAppLauncher.podspec b/app-launcher/CapacitorAppLauncher.podspec index 7d9aba6f2..0f24e8075 100644 --- a/app-launcher/CapacitorAppLauncher.podspec +++ b/app-launcher/CapacitorAppLauncher.podspec @@ -11,7 +11,7 @@ Pod::Spec.new do |s| s.author = package['author'] s.source = { :git => 'https://github.com/ionic-team/capacitor-plugins.git', :tag => package['name'] + '@' + package['version'] } s.source_files = 'ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}', 'app-launcher/ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}' - s.ios.deployment_target = '12.0' + s.ios.deployment_target = '13.0' s.dependency 'Capacitor' s.swift_version = '5.1' end diff --git a/app-launcher/README.md b/app-launcher/README.md index 5772b426e..f454c550a 100644 --- a/app-launcher/README.md +++ b/app-launcher/README.md @@ -30,7 +30,7 @@ import { AppLauncher } from '@capacitor/app-launcher'; const checkCanOpenUrl = async () => { const { value } = await AppLauncher.canOpenUrl({ url: 'com.getcapacitor.myapp' }); - alert('Can open url: ', value); + console.log('Can open url: ', value); }; const openPortfolioPage = async () => { diff --git a/app-launcher/android/build.gradle b/app-launcher/android/build.gradle index 56ee0b28b..43252f49c 100644 --- a/app-launcher/android/build.gradle +++ b/app-launcher/android/build.gradle @@ -1,27 +1,39 @@ ext { - junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.1' - androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.2.0' - androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.1.2' - androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.3.0' + capacitorVersion = System.getenv('CAPACITOR_VERSION') + junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.2' + androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.4.2' + androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.1.3' + androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.4.0' } buildscript { repositories { google() mavenCentral() + maven { + url "https://plugins.gradle.org/m2/" + } } dependencies { - classpath 'com.android.tools.build:gradle:4.2.1' + classpath 'com.android.tools.build:gradle:7.2.1' + if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + classpath 'io.github.gradle-nexus:publish-plugin:1.1.0' + } } } apply plugin: 'com.android.library' +if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + apply plugin: 'io.github.gradle-nexus.publish-plugin' + apply from: file('../../scripts/android/publish-root.gradle') + apply from: file('../../scripts/android/publish-module.gradle') +} android { - compileSdkVersion project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 30 + compileSdkVersion project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 32 defaultConfig { - minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 21 - targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 30 + minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 22 + targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 32 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" @@ -36,21 +48,26 @@ android { abortOnError false } compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility JavaVersion.VERSION_11 + targetCompatibility JavaVersion.VERSION_11 } } repositories { google() mavenCentral() - jcenter() } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation project(':capacitor-android') + + if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + implementation "com.capacitorjs:core:$capacitorVersion" + } else { + implementation project(':capacitor-android') + } + implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion" testImplementation "junit:junit:$junitVersion" androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion" diff --git a/app-launcher/android/gradle/wrapper/gradle-wrapper.jar b/app-launcher/android/gradle/wrapper/gradle-wrapper.jar index e708b1c02..41d9927a4 100644 Binary files a/app-launcher/android/gradle/wrapper/gradle-wrapper.jar and b/app-launcher/android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/app-launcher/android/gradle/wrapper/gradle-wrapper.properties b/app-launcher/android/gradle/wrapper/gradle-wrapper.properties index 3c4101c3e..92f06b50f 100644 --- a/app-launcher/android/gradle/wrapper/gradle-wrapper.properties +++ b/app-launcher/android/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/app-launcher/android/gradlew b/app-launcher/android/gradlew index 4f906e0c8..1b6c78733 100755 --- a/app-launcher/android/gradlew +++ b/app-launcher/android/gradlew @@ -1,7 +1,7 @@ -#!/usr/bin/env sh +#!/bin/sh # -# Copyright 2015 the original author or authors. +# Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,67 +17,101 @@ # ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` +APP_BASE_NAME=${0##*/} # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar @@ -87,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -98,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" + JAVACMD=java which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the @@ -106,80 +140,95 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=`expr $i + 1` + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" diff --git a/app-launcher/ios/Plugin.xcodeproj/project.pbxproj b/app-launcher/ios/Plugin.xcodeproj/project.pbxproj index 097864b6f..e971bf95c 100644 --- a/app-launcher/ios/Plugin.xcodeproj/project.pbxproj +++ b/app-launcher/ios/Plugin.xcodeproj/project.pbxproj @@ -382,7 +382,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -442,7 +442,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; @@ -465,12 +465,13 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Plugin/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks $(FRAMEWORK_SEARCH_PATHS)\n$(FRAMEWORK_SEARCH_PATHS)\n$(FRAMEWORK_SEARCH_PATHS)"; ONLY_ACTIVE_ARCH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.getcapacitor.Plugin; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; + SUPPORTS_MACCATALYST = NO; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -490,12 +491,13 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Plugin/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks $(FRAMEWORK_SEARCH_PATHS)"; ONLY_ACTIVE_ARCH = NO; PRODUCT_BUNDLE_IDENTIFIER = com.getcapacitor.Plugin; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; + SUPPORTS_MACCATALYST = NO; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; diff --git a/app-launcher/ios/Podfile b/app-launcher/ios/Podfile index 54a00c161..dee40960f 100644 --- a/app-launcher/ios/Podfile +++ b/app-launcher/ios/Podfile @@ -1,4 +1,4 @@ -platform :ios, '12.0' +platform :ios, '13.0' def capacitor_pods # Comment the next line if you're not using Swift and don't want to use dynamic frameworks diff --git a/app-launcher/package.json b/app-launcher/package.json index bf51078ed..f9302a98f 100644 --- a/app-launcher/package.json +++ b/app-launcher/package.json @@ -1,6 +1,6 @@ { "name": "@capacitor/app-launcher", - "version": "1.0.8", + "version": "4.1.0", "description": "The AppLauncher API allows to open other apps", "main": "dist/plugin.cjs.js", "module": "dist/esm/index.js", @@ -29,7 +29,7 @@ ], "scripts": { "verify": "npm run verify:ios && npm run verify:android && npm run verify:web", - "verify:ios": "cd ios && pod install && xcodebuild -workspace Plugin.xcworkspace -scheme Plugin && cd ..", + "verify:ios": "cd ios && pod install && xcodebuild -workspace Plugin.xcworkspace -scheme Plugin -destination generic/platform=iOS && cd ..", "verify:android": "cd android && ./gradlew clean build test && cd ..", "verify:web": "npm run build", "lint": "npm run eslint && npm run prettier -- --check && npm run swiftlint -- lint", @@ -45,10 +45,10 @@ "publish:cocoapod": "pod trunk push ./CapacitorAppLauncher.podspec --allow-warnings" }, "devDependencies": { - "@capacitor/android": "^3.0.0", - "@capacitor/core": "^3.0.0", - "@capacitor/docgen": "0.0.18", - "@capacitor/ios": "^3.0.0", + "@capacitor/android": "^4.0.0", + "@capacitor/core": "^4.0.0", + "@capacitor/docgen": "0.2.0", + "@capacitor/ios": "^4.0.0", "@ionic/eslint-config": "^0.3.0", "@ionic/prettier-config": "~1.0.1", "@ionic/swiftlint-config": "^1.1.2", @@ -61,7 +61,7 @@ "typescript": "~4.1.5" }, "peerDependencies": { - "@capacitor/core": "^3.0.0" + "@capacitor/core": "^4.0.0" }, "prettier": "@ionic/prettier-config", "swiftlint": "@ionic/swiftlint-config", diff --git a/app/CHANGELOG.md b/app/CHANGELOG.md index 70eb10827..87eb20631 100644 --- a/app/CHANGELOG.md +++ b/app/CHANGELOG.md @@ -3,6 +3,122 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [4.1.1](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/app@4.1.0...@capacitor/app@4.1.1) (2022-11-16) + +**Note:** Version bump only for package @capacitor/app + + + + + +# [4.1.0](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/app@1.1.1...@capacitor/app@4.1.0) (2022-10-21) + + +### Features + +* **app:** Add pause and resume event listeners ([#1220](https://github.com/ionic-team/capacitor-plugins/issues/1220)) ([7e93c88](https://github.com/ionic-team/capacitor-plugins/commit/7e93c888a3e3daae95c2f465941a4097484adae8)) + + + +## 4.0.1 (2022-07-28) + + + +# 4.0.0 (2022-07-27) + + + +# 4.0.0-beta.2 (2022-07-08) + + + +# 4.0.0-beta.0 (2022-06-27) + + +### Bug Fixes + +* Make removeAllListeners return a promise ([#895](https://github.com/ionic-team/capacitor-plugins/issues/895)) ([e5c49d6](https://github.com/ionic-team/capacitor-plugins/commit/e5c49d64445dca70286334e6a0441d8021197b13)) +* **app:** get correct build value ([#858](https://github.com/ionic-team/capacitor-plugins/issues/858)) ([4d3b125](https://github.com/ionic-team/capacitor-plugins/commit/4d3b1253c5a9c699c146526fab64c4184f810469)) + + +### Features + +* set targetSDK default value to 32 ([#970](https://github.com/ionic-team/capacitor-plugins/issues/970)) ([fa70d96](https://github.com/ionic-team/capacitor-plugins/commit/fa70d96f141af751aae53ceb5642c46b204f5958)) +* Use java 11 ([#910](https://github.com/ionic-team/capacitor-plugins/issues/910)) ([5acb2a2](https://github.com/ionic-team/capacitor-plugins/commit/5acb2a288a413492b163e4e97da46a085d9e4be0)) +* **app:** return promise in exitApp ([#777](https://github.com/ionic-team/capacitor-plugins/issues/777)) ([38e1efc](https://github.com/ionic-team/capacitor-plugins/commit/38e1efc742c7d9e887dfae3848261476202159c1)) +* set targetSDK default value to 31 ([#824](https://github.com/ionic-team/capacitor-plugins/issues/824)) ([3ee10de](https://github.com/ionic-team/capacitor-plugins/commit/3ee10de98067984c1a4e75295d001c5a895c47f4)) +* Upgrade gradle to 7.4 ([#826](https://github.com/ionic-team/capacitor-plugins/issues/826)) ([5db0906](https://github.com/ionic-team/capacitor-plugins/commit/5db0906f6264287c4f8e69dbaecf19d4d387824b)) + + + + + +## [4.0.1](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0...4.0.1) (2022-07-28) + +**Note:** Version bump only for package @capacitor/app + + + + + +# [4.0.0](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0-beta.2...4.0.0) (2022-07-27) + +**Note:** Version bump only for package @capacitor/app + + + + + +# [4.0.0-beta.2](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0-beta.0...4.0.0-beta.2) (2022-07-08) + +**Note:** Version bump only for package @capacitor/app + + + + + +# 4.0.0-beta.0 (2022-06-27) + + +### Bug Fixes + +* Make removeAllListeners return a promise ([#895](https://github.com/ionic-team/capacitor-plugins/issues/895)) ([e5c49d6](https://github.com/ionic-team/capacitor-plugins/commit/e5c49d64445dca70286334e6a0441d8021197b13)) +* **app:** get correct build value ([#858](https://github.com/ionic-team/capacitor-plugins/issues/858)) ([4d3b125](https://github.com/ionic-team/capacitor-plugins/commit/4d3b1253c5a9c699c146526fab64c4184f810469)) +* correct addListeners links ([#655](https://github.com/ionic-team/capacitor-plugins/issues/655)) ([f9871e7](https://github.com/ionic-team/capacitor-plugins/commit/f9871e7bd53478addb21155e148829f550c0e457)) +* inline source code in esm map files ([#760](https://github.com/ionic-team/capacitor-plugins/issues/760)) ([a960489](https://github.com/ionic-team/capacitor-plugins/commit/a960489a19db0182b90d187a50deff9dfbe51038)) +* **app:** Don't unset App Listeners on removeAllListeners ([#716](https://github.com/ionic-team/capacitor-plugins/issues/716)) ([17f2ee8](https://github.com/ionic-team/capacitor-plugins/commit/17f2ee8743e1366dd74771bdad9829cc5f3891e8)) +* remove postpublish scripts ([#656](https://github.com/ionic-team/capacitor-plugins/issues/656)) ([ed6ac49](https://github.com/ionic-team/capacitor-plugins/commit/ed6ac499ebf4a47525071ccbfc36c27503e11f60)) +* **app:** Update getLaunchUrl return type as can be undefined ([#299](https://github.com/ionic-team/capacitor-plugins/issues/299)) ([cdc446b](https://github.com/ionic-team/capacitor-plugins/commit/cdc446b1349ef55717b12756d3fcb2fbec671a28)) +* **app:** use alternative to deprecated versionCode ([#491](https://github.com/ionic-team/capacitor-plugins/issues/491)) ([6ebabf7](https://github.com/ionic-team/capacitor-plugins/commit/6ebabf77f1b9a954b25fdad8aaf9a89638d8366b)) +* add es2017 lib to tsconfig ([#180](https://github.com/ionic-team/capacitor-plugins/issues/180)) ([2c3776c](https://github.com/ionic-team/capacitor-plugins/commit/2c3776c38ca025c5ee965dec10ccf1cdb6c02e2f)) +* support deprecated types from Capacitor 2 ([#139](https://github.com/ionic-team/capacitor-plugins/issues/139)) ([2d7127a](https://github.com/ionic-team/capacitor-plugins/commit/2d7127a488e26f0287951921a6db47c49d817336)) +* **app:** remove iOS deprecate warnings ([#121](https://github.com/ionic-team/capacitor-plugins/issues/121)) ([d009826](https://github.com/ionic-team/capacitor-plugins/commit/d009826ded4a948041586bcc4d8a0fa51afbea5f)) + + +### Features + +* set targetSDK default value to 32 ([#970](https://github.com/ionic-team/capacitor-plugins/issues/970)) ([fa70d96](https://github.com/ionic-team/capacitor-plugins/commit/fa70d96f141af751aae53ceb5642c46b204f5958)) +* Use java 11 ([#910](https://github.com/ionic-team/capacitor-plugins/issues/910)) ([5acb2a2](https://github.com/ionic-team/capacitor-plugins/commit/5acb2a288a413492b163e4e97da46a085d9e4be0)) +* **app:** return promise in exitApp ([#777](https://github.com/ionic-team/capacitor-plugins/issues/777)) ([38e1efc](https://github.com/ionic-team/capacitor-plugins/commit/38e1efc742c7d9e887dfae3848261476202159c1)) +* set targetSDK default value to 31 ([#824](https://github.com/ionic-team/capacitor-plugins/issues/824)) ([3ee10de](https://github.com/ionic-team/capacitor-plugins/commit/3ee10de98067984c1a4e75295d001c5a895c47f4)) +* Upgrade gradle to 7.4 ([#826](https://github.com/ionic-team/capacitor-plugins/issues/826)) ([5db0906](https://github.com/ionic-team/capacitor-plugins/commit/5db0906f6264287c4f8e69dbaecf19d4d387824b)) +* **android:** support for minimizeApp ([#743](https://github.com/ionic-team/capacitor-plugins/issues/743)) ([3ec2008](https://github.com/ionic-team/capacitor-plugins/commit/3ec2008bc0311c837346ecbdd0afd105149b427a)) +* **app:** Add canGoBack to backButton event ([#265](https://github.com/ionic-team/capacitor-plugins/issues/265)) ([6d7861e](https://github.com/ionic-team/capacitor-plugins/commit/6d7861e78ff7990a21396d05270c622d42850a02)) +* add commonjs output format ([#179](https://github.com/ionic-team/capacitor-plugins/issues/179)) ([8e9e098](https://github.com/ionic-team/capacitor-plugins/commit/8e9e09862064b3f6771d7facbc4008e995d9b463)) +* App plugin ([#71](https://github.com/ionic-team/capacitor-plugins/issues/71)) ([94e4219](https://github.com/ionic-team/capacitor-plugins/commit/94e4219e61fbb7a51075cc430f29fc08254f659c)) + + + + + +## [1.1.1](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/app@1.1.0...@capacitor/app@1.1.1) (2022-03-03) + +**Note:** Version bump only for package @capacitor/app + + + + + # [1.1.0](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/app@1.0.7...@capacitor/app@1.1.0) (2022-01-19) diff --git a/app/CapacitorApp.podspec b/app/CapacitorApp.podspec index cec3ad2c4..98787945d 100644 --- a/app/CapacitorApp.podspec +++ b/app/CapacitorApp.podspec @@ -11,7 +11,7 @@ Pod::Spec.new do |s| s.author = package['author'] s.source = { :git => 'https://github.com/ionic-team/capacitor-plugins.git', :tag => package['name'] + '@' + package['version'] } s.source_files = 'ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}', 'app/ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}' - s.ios.deployment_target = '12.0' + s.ios.deployment_target = '13.0' s.dependency 'Capacitor' s.swift_version = '5.1' end diff --git a/app/README.md b/app/README.md index 31a428720..5c0ec03ea 100644 --- a/app/README.md +++ b/app/README.md @@ -63,7 +63,7 @@ App.addListener('appRestoredResult', data => { const checkAppLaunchUrl = async () => { const { url } = await App.getLaunchUrl(); - alert('App opened with URL: ' + url); + console.log('App opened with URL: ' + url); }; ``` @@ -77,6 +77,8 @@ const checkAppLaunchUrl = async () => { * [`getLaunchUrl()`](#getlaunchurl) * [`minimizeApp()`](#minimizeapp) * [`addListener('appStateChange', ...)`](#addlistenerappstatechange) +* [`addListener('pause', ...)`](#addlistenerpause) +* [`addListener('resume', ...)`](#addlistenerresume) * [`addListener('appUrlOpen', ...)`](#addlistenerappurlopen) * [`addListener('appRestoredResult', ...)`](#addlistenerapprestoredresult) * [`addListener('backButton', ...)`](#addlistenerbackbutton) @@ -92,7 +94,7 @@ const checkAppLaunchUrl = async () => { ### exitApp() ```typescript -exitApp() => never +exitApp() => Promise ``` Force exit the app. This should only be used in conjunction with the `backButton` handler for Android to @@ -100,8 +102,6 @@ exit the app when navigation is complete. Ionic handles this itself so you shouldn't need to call this if using Ionic. -**Returns:** never - **Since:** 1.0.0 -------------------- @@ -173,7 +173,12 @@ Only available for Android. addListener(eventName: 'appStateChange', listenerFunc: StateChangeListener) => Promise & PluginListenerHandle ``` -Listen for changes in the App's active state (whether the app is in the foreground or background) +Listen for changes in the app or the activity states. + +On iOS it's fired when the native [UIApplication.willResignActiveNotification](https://developer.apple.com/documentation/uikit/uiapplication/1622973-willresignactivenotification) and +[UIApplication.didBecomeActiveNotification](https://developer.apple.com/documentation/uikit/uiapplication/1622953-didbecomeactivenotification) events get fired. +On Android it's fired when the Capacitor's Activity [onResume](https://developer.android.com/reference/android/app/Activity#onResume()) and [onStop](https://developer.android.com/reference/android/app/Activity#onStop()) methods gets called. +On Web it's fired when the document's visibilitychange gets fired. | Param | Type | | ------------------ | ------------------------------------------------------------------- | @@ -187,6 +192,55 @@ Listen for changes in the App's active state (whether the app is in the foregrou -------------------- +### addListener('pause', ...) + +```typescript +addListener(eventName: 'pause', listenerFunc: () => void) => Promise & PluginListenerHandle +``` + +Listen for when the app or the activity are paused. + +On iOS it's fired when the native [UIApplication.didEnterBackgroundNotification](https://developer.apple.com/documentation/uikit/uiapplication/1623071-didenterbackgroundnotification) event gets fired. +On Android it's fired when the Capacitor's Activity [onPause](https://developer.android.com/reference/android/app/Activity#onPause()) method gets called. +On Web it's fired when the document's visibilitychange gets fired and document.hidden is true. + +| Param | Type | +| ------------------ | -------------------------- | +| **`eventName`** | 'pause' | +| **`listenerFunc`** | () => void | + +**Returns:** Promise<PluginListenerHandle> & PluginListenerHandle + +**Since:** 4.1.0 + +-------------------- + + +### addListener('resume', ...) + +```typescript +addListener(eventName: 'resume', listenerFunc: () => void) => Promise & PluginListenerHandle +``` + +Listen for when the app or activity are resumed. + +On iOS it's fired when the native [UIApplication.willEnterForegroundNotification](https://developer.apple.com/documentation/uikit/uiapplication/1622944-willenterforegroundnotification) event gets fired. +On Android it's fired when the Capacitor's Activity [onResume](https://developer.android.com/reference/android/app/Activity#onResume()) method gets called, +but only after resume has fired first. +On Web it's fired when the document's visibilitychange gets fired and document.hidden is false. + +| Param | Type | +| ------------------ | -------------------------- | +| **`eventName`** | 'resume' | +| **`listenerFunc`** | () => void | + +**Returns:** Promise<PluginListenerHandle> & PluginListenerHandle + +**Since:** 4.1.0 + +-------------------- + + ### addListener('appUrlOpen', ...) ```typescript diff --git a/app/android/build.gradle b/app/android/build.gradle index 56ee0b28b..43252f49c 100644 --- a/app/android/build.gradle +++ b/app/android/build.gradle @@ -1,27 +1,39 @@ ext { - junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.1' - androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.2.0' - androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.1.2' - androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.3.0' + capacitorVersion = System.getenv('CAPACITOR_VERSION') + junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.2' + androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.4.2' + androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.1.3' + androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.4.0' } buildscript { repositories { google() mavenCentral() + maven { + url "https://plugins.gradle.org/m2/" + } } dependencies { - classpath 'com.android.tools.build:gradle:4.2.1' + classpath 'com.android.tools.build:gradle:7.2.1' + if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + classpath 'io.github.gradle-nexus:publish-plugin:1.1.0' + } } } apply plugin: 'com.android.library' +if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + apply plugin: 'io.github.gradle-nexus.publish-plugin' + apply from: file('../../scripts/android/publish-root.gradle') + apply from: file('../../scripts/android/publish-module.gradle') +} android { - compileSdkVersion project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 30 + compileSdkVersion project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 32 defaultConfig { - minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 21 - targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 30 + minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 22 + targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 32 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" @@ -36,21 +48,26 @@ android { abortOnError false } compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility JavaVersion.VERSION_11 + targetCompatibility JavaVersion.VERSION_11 } } repositories { google() mavenCentral() - jcenter() } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation project(':capacitor-android') + + if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + implementation "com.capacitorjs:core:$capacitorVersion" + } else { + implementation project(':capacitor-android') + } + implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion" testImplementation "junit:junit:$junitVersion" androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion" diff --git a/app/android/gradle/wrapper/gradle-wrapper.jar b/app/android/gradle/wrapper/gradle-wrapper.jar index e708b1c02..41d9927a4 100644 Binary files a/app/android/gradle/wrapper/gradle-wrapper.jar and b/app/android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/app/android/gradle/wrapper/gradle-wrapper.properties b/app/android/gradle/wrapper/gradle-wrapper.properties index 3c4101c3e..92f06b50f 100644 --- a/app/android/gradle/wrapper/gradle-wrapper.properties +++ b/app/android/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/app/android/gradlew b/app/android/gradlew index 4f906e0c8..1b6c78733 100755 --- a/app/android/gradlew +++ b/app/android/gradlew @@ -1,7 +1,7 @@ -#!/usr/bin/env sh +#!/bin/sh # -# Copyright 2015 the original author or authors. +# Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,67 +17,101 @@ # ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` +APP_BASE_NAME=${0##*/} # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar @@ -87,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -98,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" + JAVACMD=java which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the @@ -106,80 +140,95 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=`expr $i + 1` + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" diff --git a/app/android/src/main/java/com/capacitorjs/plugins/app/AppPlugin.java b/app/android/src/main/java/com/capacitorjs/plugins/app/AppPlugin.java index 673edc674..e09c362ea 100644 --- a/app/android/src/main/java/com/capacitorjs/plugins/app/AppPlugin.java +++ b/app/android/src/main/java/com/capacitorjs/plugins/app/AppPlugin.java @@ -6,6 +6,7 @@ import android.net.Uri; import android.os.Build; import androidx.activity.OnBackPressedCallback; +import androidx.core.content.pm.PackageInfoCompat; import com.getcapacitor.JSObject; import com.getcapacitor.Logger; import com.getcapacitor.Plugin; @@ -20,6 +21,9 @@ public class AppPlugin extends Plugin { private static final String EVENT_URL_OPEN = "appUrlOpen"; private static final String EVENT_STATE_CHANGE = "appStateChange"; private static final String EVENT_RESTORED_RESULT = "appRestoredResult"; + private static final String EVENT_PAUSE = "pause"; + private static final String EVENT_RESUME = "resume"; + private boolean hasPausedEver = false; public void load() { bridge @@ -61,6 +65,7 @@ public void handleOnBackPressed() { @PluginMethod public void exitApp(PluginCall call) { unsetAppListeners(); + call.resolve(); getBridge().getActivity().finish(); } @@ -74,11 +79,7 @@ public void getInfo(PluginCall call) { String appName = stringId == 0 ? applicationInfo.nonLocalizedLabel.toString() : getContext().getString(stringId); data.put("name", appName); data.put("id", pinfo.packageName); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { - data.put("build", Long.toString(pinfo.getLongVersionCode())); - } else { - data.put("build", Integer.toString(pinfo.versionCode)); - } + data.put("build", Integer.toString((int) PackageInfoCompat.getLongVersionCode(pinfo))); data.put("version", pinfo.versionName); call.resolve(data); } catch (Exception ex) { @@ -134,6 +135,21 @@ protected void handleOnNewIntent(Intent intent) { notifyListeners(EVENT_URL_OPEN, ret, true); } + @Override + protected void handleOnPause() { + super.handleOnPause(); + hasPausedEver = true; + notifyListeners(EVENT_PAUSE, null); + } + + @Override + protected void handleOnResume() { + super.handleOnResume(); + if (hasPausedEver) { + notifyListeners(EVENT_RESUME, null); + } + } + @Override protected void handleOnDestroy() { unsetAppListeners(); diff --git a/app/ios/Plugin.xcodeproj/project.pbxproj b/app/ios/Plugin.xcodeproj/project.pbxproj index e33a41ec3..6be1cfd8c 100644 --- a/app/ios/Plugin.xcodeproj/project.pbxproj +++ b/app/ios/Plugin.xcodeproj/project.pbxproj @@ -382,7 +382,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -442,7 +442,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; @@ -465,12 +465,13 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Plugin/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks $(FRAMEWORK_SEARCH_PATHS)\n$(FRAMEWORK_SEARCH_PATHS)\n$(FRAMEWORK_SEARCH_PATHS)"; ONLY_ACTIVE_ARCH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.getcapacitor.Plugin; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; + SUPPORTS_MACCATALYST = NO; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -490,12 +491,13 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Plugin/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks $(FRAMEWORK_SEARCH_PATHS)"; ONLY_ACTIVE_ARCH = NO; PRODUCT_BUNDLE_IDENTIFIER = com.getcapacitor.Plugin; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; + SUPPORTS_MACCATALYST = NO; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; diff --git a/app/ios/Plugin/AppPlugin.m b/app/ios/Plugin/AppPlugin.m index 189b151bd..e18f8ee39 100644 --- a/app/ios/Plugin/AppPlugin.m +++ b/app/ios/Plugin/AppPlugin.m @@ -4,10 +4,10 @@ // Define the plugin using the CAP_PLUGIN Macro, and // each method the plugin supports using the CAP_PLUGIN_METHOD macro. CAP_PLUGIN(AppPlugin, "App", - CAP_PLUGIN_METHOD(exitApp, CAPPluginReturnNone); + CAP_PLUGIN_METHOD(exitApp, CAPPluginReturnPromise); CAP_PLUGIN_METHOD(getInfo, CAPPluginReturnPromise); CAP_PLUGIN_METHOD(getLaunchUrl, CAPPluginReturnPromise); CAP_PLUGIN_METHOD(getState, CAPPluginReturnPromise); CAP_PLUGIN_METHOD(minimizeApp, CAPPluginReturnPromise); - CAP_PLUGIN_METHOD(removeAllListeners, CAPPluginReturnNone); + CAP_PLUGIN_METHOD(removeAllListeners, CAPPluginReturnPromise); ) diff --git a/app/ios/Plugin/AppPlugin.swift b/app/ios/Plugin/AppPlugin.swift index 361232e72..e97412711 100644 --- a/app/ios/Plugin/AppPlugin.swift +++ b/app/ios/Plugin/AppPlugin.swift @@ -19,6 +19,14 @@ public class AppPlugin: CAPPlugin { ]) }) + observers.append(NotificationCenter.default.addObserver(forName: UIApplication.didEnterBackgroundNotification, object: nil, queue: OperationQueue.main) { [weak self] (_) in + self?.notifyListeners("pause", data: nil) + }) + + observers.append(NotificationCenter.default.addObserver(forName: UIApplication.willEnterForegroundNotification, object: nil, queue: OperationQueue.main) { [weak self] (_) in + self?.notifyListeners("resume", data: nil) + }) + } deinit { diff --git a/app/ios/Podfile b/app/ios/Podfile index 54a00c161..dee40960f 100644 --- a/app/ios/Podfile +++ b/app/ios/Podfile @@ -1,4 +1,4 @@ -platform :ios, '12.0' +platform :ios, '13.0' def capacitor_pods # Comment the next line if you're not using Swift and don't want to use dynamic frameworks diff --git a/app/package.json b/app/package.json index 292715de3..f4add9c42 100644 --- a/app/package.json +++ b/app/package.json @@ -1,6 +1,6 @@ { "name": "@capacitor/app", - "version": "1.1.0", + "version": "4.1.1", "description": "The App API handles high level App state and events.For example, this API emits events when the app enters and leaves the foreground, handles deeplinks, opens other apps, and manages persisted plugin state.", "main": "dist/plugin.cjs.js", "module": "dist/esm/index.js", @@ -29,7 +29,7 @@ ], "scripts": { "verify": "npm run verify:ios && npm run verify:android && npm run verify:web", - "verify:ios": "cd ios && pod install && xcodebuild -workspace Plugin.xcworkspace -scheme Plugin && cd ..", + "verify:ios": "cd ios && pod install && xcodebuild -workspace Plugin.xcworkspace -scheme Plugin -destination generic/platform=iOS && cd ..", "verify:android": "cd android && ./gradlew clean build test && cd ..", "verify:web": "npm run build", "lint": "npm run eslint && npm run prettier -- --check && npm run swiftlint -- lint", @@ -45,10 +45,10 @@ "publish:cocoapod": "pod trunk push ./CapacitorApp.podspec --allow-warnings" }, "devDependencies": { - "@capacitor/android": "^3.0.0", - "@capacitor/core": "^3.0.0", - "@capacitor/docgen": "0.0.18", - "@capacitor/ios": "^3.0.0", + "@capacitor/android": "^4.0.0", + "@capacitor/core": "^4.0.0", + "@capacitor/docgen": "0.2.0", + "@capacitor/ios": "^4.0.0", "@ionic/eslint-config": "^0.3.0", "@ionic/prettier-config": "~1.0.1", "@ionic/swiftlint-config": "^1.1.2", @@ -61,7 +61,7 @@ "typescript": "~4.1.5" }, "peerDependencies": { - "@capacitor/core": "^3.0.0" + "@capacitor/core": "^4.0.0" }, "prettier": "@ionic/prettier-config", "swiftlint": "@ionic/swiftlint-config", diff --git a/app/src/definitions.ts b/app/src/definitions.ts index c2a64ab0f..33f7583ab 100644 --- a/app/src/definitions.ts +++ b/app/src/definitions.ts @@ -139,7 +139,7 @@ export interface AppPlugin { * * @since 1.0.0 */ - exitApp(): never; + exitApp(): Promise; /** * Return information about the app. @@ -172,7 +172,12 @@ export interface AppPlugin { minimizeApp(): Promise; /** - * Listen for changes in the App's active state (whether the app is in the foreground or background) + * Listen for changes in the app or the activity states. + * + * On iOS it's fired when the native [UIApplication.willResignActiveNotification](https://developer.apple.com/documentation/uikit/uiapplication/1622973-willresignactivenotification) and + * [UIApplication.didBecomeActiveNotification](https://developer.apple.com/documentation/uikit/uiapplication/1622953-didbecomeactivenotification) events get fired. + * On Android it's fired when the Capacitor's Activity [onResume](https://developer.android.com/reference/android/app/Activity#onResume()) and [onStop](https://developer.android.com/reference/android/app/Activity#onStop()) methods gets called. + * On Web it's fired when the document's visibilitychange gets fired. * * @since 1.0.0 */ @@ -181,6 +186,35 @@ export interface AppPlugin { listenerFunc: StateChangeListener, ): Promise & PluginListenerHandle; + /** + * Listen for when the app or the activity are paused. + * + * On iOS it's fired when the native [UIApplication.didEnterBackgroundNotification](https://developer.apple.com/documentation/uikit/uiapplication/1623071-didenterbackgroundnotification) event gets fired. + * On Android it's fired when the Capacitor's Activity [onPause](https://developer.android.com/reference/android/app/Activity#onPause()) method gets called. + * On Web it's fired when the document's visibilitychange gets fired and document.hidden is true. + * + * @since 4.1.0 + */ + addListener( + eventName: 'pause', + listenerFunc: () => void, + ): Promise & PluginListenerHandle; + + /** + * Listen for when the app or activity are resumed. + * + * On iOS it's fired when the native [UIApplication.willEnterForegroundNotification](https://developer.apple.com/documentation/uikit/uiapplication/1622944-willenterforegroundnotification) event gets fired. + * On Android it's fired when the Capacitor's Activity [onResume](https://developer.android.com/reference/android/app/Activity#onResume()) method gets called, + * but only after resume has fired first. + * On Web it's fired when the document's visibilitychange gets fired and document.hidden is false. + * + * @since 4.1.0 + */ + addListener( + eventName: 'resume', + listenerFunc: () => void, + ): Promise & PluginListenerHandle; + /** * Listen for url open events for the app. This handles both custom URL scheme links as well * as URLs your app handles (Universal Links on iOS and App Links on Android) diff --git a/app/src/web.ts b/app/src/web.ts index 5f2678252..1db1ff356 100644 --- a/app/src/web.ts +++ b/app/src/web.ts @@ -12,7 +12,7 @@ export class AppWeb extends WebPlugin implements AppPlugin { ); } - exitApp(): never { + exitApp(): Promise { throw this.unimplemented('Not implemented on web.'); } @@ -38,5 +38,10 @@ export class AppWeb extends WebPlugin implements AppPlugin { }; this.notifyListeners('appStateChange', data); + if (document.hidden) { + this.notifyListeners('pause', null); + } else { + this.notifyListeners('resume', null); + } }; } diff --git a/browser/CHANGELOG.md b/browser/CHANGELOG.md index 95915903e..593acfbe2 100644 --- a/browser/CHANGELOG.md +++ b/browser/CHANGELOG.md @@ -3,6 +3,104 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.1.0](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/browser@1.0.7...@capacitor/browser@4.1.0) (2022-11-16) + + + +## 4.0.1 (2022-07-28) + + + +# 4.0.0 (2022-07-27) + + + +# 4.0.0-beta.2 (2022-07-08) + + +### Features + +* **browser:** Allow to configure popover size ([#1056](https://github.com/ionic-team/capacitor-plugins/issues/1056)) ([90eb1e5](https://github.com/ionic-team/capacitor-plugins/commit/90eb1e5356aab11103f9b1f56808102ee42f2f1b)) + + + +# 4.0.0-beta.0 (2022-06-27) + + +### Bug Fixes + +* Make removeAllListeners return a promise ([#895](https://github.com/ionic-team/capacitor-plugins/issues/895)) ([e5c49d6](https://github.com/ionic-team/capacitor-plugins/commit/e5c49d64445dca70286334e6a0441d8021197b13)) + + +### Features + +* set targetSDK default value to 31 ([#824](https://github.com/ionic-team/capacitor-plugins/issues/824)) ([3ee10de](https://github.com/ionic-team/capacitor-plugins/commit/3ee10de98067984c1a4e75295d001c5a895c47f4)) +* set targetSDK default value to 32 ([#970](https://github.com/ionic-team/capacitor-plugins/issues/970)) ([fa70d96](https://github.com/ionic-team/capacitor-plugins/commit/fa70d96f141af751aae53ceb5642c46b204f5958)) +* Upgrade gradle to 7.4 ([#826](https://github.com/ionic-team/capacitor-plugins/issues/826)) ([5db0906](https://github.com/ionic-team/capacitor-plugins/commit/5db0906f6264287c4f8e69dbaecf19d4d387824b)) +* Use java 11 ([#910](https://github.com/ionic-team/capacitor-plugins/issues/910)) ([5acb2a2](https://github.com/ionic-team/capacitor-plugins/commit/5acb2a288a413492b163e4e97da46a085d9e4be0)) + + + + + +## [4.0.1](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0...4.0.1) (2022-07-28) + +**Note:** Version bump only for package @capacitor/browser + + + + + +# [4.0.0](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0-beta.2...4.0.0) (2022-07-27) + +**Note:** Version bump only for package @capacitor/browser + + + + + +# [4.0.0-beta.2](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0-beta.0...4.0.0-beta.2) (2022-07-08) + + +### Features + +* **browser:** Allow to configure popover size ([#1056](https://github.com/ionic-team/capacitor-plugins/issues/1056)) ([90eb1e5](https://github.com/ionic-team/capacitor-plugins/commit/90eb1e5356aab11103f9b1f56808102ee42f2f1b)) + + + + + +# 4.0.0-beta.0 (2022-06-27) + + +### Bug Fixes + +* add es2017 lib to tsconfig ([#180](https://github.com/ionic-team/capacitor-plugins/issues/180)) ([2c3776c](https://github.com/ionic-team/capacitor-plugins/commit/2c3776c38ca025c5ee965dec10ccf1cdb6c02e2f)) +* correct addListeners links ([#655](https://github.com/ionic-team/capacitor-plugins/issues/655)) ([f9871e7](https://github.com/ionic-team/capacitor-plugins/commit/f9871e7bd53478addb21155e148829f550c0e457)) +* Correct missing source_files path ([#590](https://github.com/ionic-team/capacitor-plugins/issues/590)) ([24e0fc2](https://github.com/ionic-team/capacitor-plugins/commit/24e0fc27cc314049012ab9915fa5e7bfb03313e1)) +* inline source code in esm map files ([#760](https://github.com/ionic-team/capacitor-plugins/issues/760)) ([a960489](https://github.com/ionic-team/capacitor-plugins/commit/a960489a19db0182b90d187a50deff9dfbe51038)) +* Make removeAllListeners return a promise ([#895](https://github.com/ionic-team/capacitor-plugins/issues/895)) ([e5c49d6](https://github.com/ionic-team/capacitor-plugins/commit/e5c49d64445dca70286334e6a0441d8021197b13)) +* remove postpublish scripts ([#656](https://github.com/ionic-team/capacitor-plugins/issues/656)) ([ed6ac49](https://github.com/ionic-team/capacitor-plugins/commit/ed6ac499ebf4a47525071ccbfc36c27503e11f60)) +* **browser:** browserFinished does not fire when closing popovers ([#483](https://github.com/ionic-team/capacitor-plugins/issues/483)) ([fb8dbb8](https://github.com/ionic-team/capacitor-plugins/commit/fb8dbb8dc69d67e2aab72ea3cd5389dc91f9bace)) +* **browser:** prevent crash on popover presentation ([#369](https://github.com/ionic-team/capacitor-plugins/issues/369)) ([a9d4380](https://github.com/ionic-team/capacitor-plugins/commit/a9d43805f35ebaeaaed3285adc2e1f7e1062e009)) +* Migrate plugins from Color.parseColor() to WebColor.parseColor() ([#140](https://github.com/ionic-team/capacitor-plugins/issues/140)) ([26625cf](https://github.com/ionic-team/capacitor-plugins/commit/26625cfefe45b8d1f17ce27efbc8b04f23e99d93)) +* support deprecated types from Capacitor 2 ([#139](https://github.com/ionic-team/capacitor-plugins/issues/139)) ([2d7127a](https://github.com/ionic-team/capacitor-plugins/commit/2d7127a488e26f0287951921a6db47c49d817336)) +* **browser:** don't expose load method ([#128](https://github.com/ionic-team/capacitor-plugins/issues/128)) ([945e59b](https://github.com/ionic-team/capacitor-plugins/commit/945e59b622bad42d33804d0ffb4ca9afcb7f9b07)) + + +### Features + +* add commonjs output format ([#179](https://github.com/ionic-team/capacitor-plugins/issues/179)) ([8e9e098](https://github.com/ionic-team/capacitor-plugins/commit/8e9e09862064b3f6771d7facbc4008e995d9b463)) +* Browser plugin ([#16](https://github.com/ionic-team/capacitor-plugins/issues/16)) ([6ad5597](https://github.com/ionic-team/capacitor-plugins/commit/6ad559768ad853ac11d94e39bac34a4515362735)) +* set targetSDK default value to 31 ([#824](https://github.com/ionic-team/capacitor-plugins/issues/824)) ([3ee10de](https://github.com/ionic-team/capacitor-plugins/commit/3ee10de98067984c1a4e75295d001c5a895c47f4)) +* set targetSDK default value to 32 ([#970](https://github.com/ionic-team/capacitor-plugins/issues/970)) ([fa70d96](https://github.com/ionic-team/capacitor-plugins/commit/fa70d96f141af751aae53ceb5642c46b204f5958)) +* Upgrade gradle to 7.4 ([#826](https://github.com/ionic-team/capacitor-plugins/issues/826)) ([5db0906](https://github.com/ionic-team/capacitor-plugins/commit/5db0906f6264287c4f8e69dbaecf19d4d387824b)) +* Use java 11 ([#910](https://github.com/ionic-team/capacitor-plugins/issues/910)) ([5acb2a2](https://github.com/ionic-team/capacitor-plugins/commit/5acb2a288a413492b163e4e97da46a085d9e4be0)) + + + + + ## [1.0.7](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/browser@1.0.6...@capacitor/browser@1.0.7) (2022-01-19) diff --git a/browser/CapacitorBrowser.podspec b/browser/CapacitorBrowser.podspec index b8cb7fa99..646854907 100644 --- a/browser/CapacitorBrowser.podspec +++ b/browser/CapacitorBrowser.podspec @@ -11,7 +11,7 @@ Pod::Spec.new do |s| s.author = package['author'] s.source = { :git => 'https://github.com/ionic-team/capacitor-plugins.git', :tag => package['name'] + '@' + package['version'] } s.source_files = 'ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}', 'browser/ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}' - s.ios.deployment_target = '12.0' + s.ios.deployment_target = '13.0' s.dependency 'Capacitor' s.swift_version = '5.1' end diff --git a/browser/README.md b/browser/README.md index 724d6a2f6..fecabf19e 100644 --- a/browser/README.md +++ b/browser/README.md @@ -17,7 +17,7 @@ npx cap sync This plugin will use the following project variables (defined in your app's `variables.gradle` file): -- `$androidxBrowserVersion`: version of `androidx.browser:browser` (default: `1.3.0`) +- `$androidxBrowserVersion`: version of `androidx.browser:browser` (default: `1.4.0`) ## Example @@ -146,6 +146,8 @@ Represents the options passed to `open`. | **`windowName`** | string | Web only: Optional target for browser open. Follows the `target` property for window.open. Defaults to _blank. Ignored on other platforms. | 1.0.0 | | **`toolbarColor`** | string | A hex color to which the toolbar color is set. | 1.0.0 | | **`presentationStyle`** | 'fullscreen' \| 'popover' | iOS only: The presentation style of the browser. Defaults to fullscreen. Ignored on other platforms. | 1.0.0 | +| **`width`** | number | iOS only: The width the browser when using presentationStyle 'popover' on iPads. Ignored on other platforms. | 4.0.0 | +| **`height`** | number | iOS only: The height the browser when using presentationStyle 'popover' on iPads. Ignored on other platforms. | 4.0.0 | #### PluginListenerHandle diff --git a/browser/android/build.gradle b/browser/android/build.gradle index 06d4b8324..435a81e41 100644 --- a/browser/android/build.gradle +++ b/browser/android/build.gradle @@ -1,28 +1,40 @@ ext { - junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.1' - androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.2.0' - androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.1.2' - androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.3.0' - androidxBrowserVersion = project.hasProperty('androidxBrowserVersion') ? rootProject.ext.androidxBrowserVersion : '1.3.0' + capacitorVersion = System.getenv('CAPACITOR_VERSION') + junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.2' + androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.4.2' + androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.1.3' + androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.4.0' + androidxBrowserVersion = project.hasProperty('androidxBrowserVersion') ? rootProject.ext.androidxBrowserVersion : '1.4.0' } buildscript { repositories { google() mavenCentral() + maven { + url "https://plugins.gradle.org/m2/" + } } dependencies { - classpath 'com.android.tools.build:gradle:4.2.1' + classpath 'com.android.tools.build:gradle:7.2.1' + if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + classpath 'io.github.gradle-nexus:publish-plugin:1.1.0' + } } } apply plugin: 'com.android.library' +if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + apply plugin: 'io.github.gradle-nexus.publish-plugin' + apply from: file('../../scripts/android/publish-root.gradle') + apply from: file('../../scripts/android/publish-module.gradle') +} android { - compileSdkVersion project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 30 + compileSdkVersion project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 32 defaultConfig { - minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 21 - targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 30 + minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 22 + targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 32 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" @@ -37,21 +49,26 @@ android { abortOnError false } compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility JavaVersion.VERSION_11 + targetCompatibility JavaVersion.VERSION_11 } } repositories { google() mavenCentral() - jcenter() } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation project(':capacitor-android') + + if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + implementation "com.capacitorjs:core:$capacitorVersion" + } else { + implementation project(':capacitor-android') + } + implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion" implementation "androidx.browser:browser:$androidxBrowserVersion" testImplementation "junit:junit:$junitVersion" diff --git a/browser/android/gradle/wrapper/gradle-wrapper.jar b/browser/android/gradle/wrapper/gradle-wrapper.jar index e708b1c02..41d9927a4 100644 Binary files a/browser/android/gradle/wrapper/gradle-wrapper.jar and b/browser/android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/browser/android/gradle/wrapper/gradle-wrapper.properties b/browser/android/gradle/wrapper/gradle-wrapper.properties index 3c4101c3e..92f06b50f 100644 --- a/browser/android/gradle/wrapper/gradle-wrapper.properties +++ b/browser/android/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/browser/android/gradlew b/browser/android/gradlew index 4f906e0c8..1b6c78733 100755 --- a/browser/android/gradlew +++ b/browser/android/gradlew @@ -1,7 +1,7 @@ -#!/usr/bin/env sh +#!/bin/sh # -# Copyright 2015 the original author or authors. +# Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,67 +17,101 @@ # ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` +APP_BASE_NAME=${0##*/} # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar @@ -87,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -98,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" + JAVACMD=java which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the @@ -106,80 +140,95 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=`expr $i + 1` + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" diff --git a/browser/android/src/main/java/com/capacitorjs/plugins/browser/Browser.java b/browser/android/src/main/java/com/capacitorjs/plugins/browser/Browser.java index c439d6630..07cbdab03 100644 --- a/browser/android/src/main/java/com/capacitorjs/plugins/browser/Browser.java +++ b/browser/android/src/main/java/com/capacitorjs/plugins/browser/Browser.java @@ -1,5 +1,7 @@ package com.capacitorjs.plugins.browser; +import static androidx.browser.customtabs.CustomTabsIntent.SHARE_STATE_ON; + import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -7,11 +9,7 @@ import android.os.Bundle; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import androidx.browser.customtabs.CustomTabsCallback; -import androidx.browser.customtabs.CustomTabsClient; -import androidx.browser.customtabs.CustomTabsIntent; -import androidx.browser.customtabs.CustomTabsServiceConnection; -import androidx.browser.customtabs.CustomTabsSession; +import androidx.browser.customtabs.*; /** * The Browser class implements Custom Chrome Tabs. See @@ -99,10 +97,11 @@ public void open(Uri url) { public void open(Uri url, @Nullable Integer toolbarColor) { CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder(getCustomTabsSession()); - builder.addDefaultShareMenuItem(); + builder.setShareState(SHARE_STATE_ON); if (toolbarColor != null) { - builder.setToolbarColor(toolbarColor.intValue()); + CustomTabColorSchemeParams params = new CustomTabColorSchemeParams.Builder().setToolbarColor(toolbarColor.intValue()).build(); + builder.setDefaultColorSchemeParams(params); } CustomTabsIntent tabsIntent = builder.build(); diff --git a/browser/ios/Plugin.xcodeproj/project.pbxproj b/browser/ios/Plugin.xcodeproj/project.pbxproj index d1ea18bf5..d4c8959b0 100644 --- a/browser/ios/Plugin.xcodeproj/project.pbxproj +++ b/browser/ios/Plugin.xcodeproj/project.pbxproj @@ -386,7 +386,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -446,7 +446,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; @@ -469,12 +469,13 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Plugin/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks $(FRAMEWORK_SEARCH_PATHS)\n$(FRAMEWORK_SEARCH_PATHS)\n$(FRAMEWORK_SEARCH_PATHS)"; ONLY_ACTIVE_ARCH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.getcapacitor.Plugin; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; + SUPPORTS_MACCATALYST = NO; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -494,12 +495,13 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Plugin/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks $(FRAMEWORK_SEARCH_PATHS)"; ONLY_ACTIVE_ARCH = NO; PRODUCT_BUNDLE_IDENTIFIER = com.getcapacitor.Plugin; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; + SUPPORTS_MACCATALYST = NO; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; diff --git a/browser/ios/Plugin/BrowserPlugin.m b/browser/ios/Plugin/BrowserPlugin.m index 14bc85030..701ca7966 100644 --- a/browser/ios/Plugin/BrowserPlugin.m +++ b/browser/ios/Plugin/BrowserPlugin.m @@ -4,5 +4,5 @@ CAP_PLUGIN(CAPBrowserPlugin, "Browser", CAP_PLUGIN_METHOD(open, CAPPluginReturnPromise); CAP_PLUGIN_METHOD(close, CAPPluginReturnPromise); - CAP_PLUGIN_METHOD(removeAllListeners, CAPPluginReturnNone); + CAP_PLUGIN_METHOD(removeAllListeners, CAPPluginReturnPromise); ) diff --git a/browser/ios/Plugin/BrowserPlugin.swift b/browser/ios/Plugin/BrowserPlugin.swift index 063f5a545..f6be40dd7 100644 --- a/browser/ios/Plugin/BrowserPlugin.swift +++ b/browser/ios/Plugin/BrowserPlugin.swift @@ -28,7 +28,11 @@ public class CAPBrowserPlugin: CAPPlugin { // display DispatchQueue.main.async { [weak self] in if style == .popover { - self?.setCenteredPopover(viewController) + if let width = call.getInt("width"), let height = call.getInt("height") { + self?.setCenteredPopover(viewController, size: CGSize.init(width: width, height: height)) + } else { + self?.setCenteredPopover(viewController) + } } self?.bridge?.presentVC(viewController, animated: true, completion: { call.resolve() @@ -50,7 +54,7 @@ public class CAPBrowserPlugin: CAPPlugin { } private func presentationStyle(for style: String?) -> UIModalPresentationStyle { - if let style = style, style == "popover", supportsPopover() { + if let style = style, style == "popover" { return .popover } return .fullScreen diff --git a/browser/ios/Podfile b/browser/ios/Podfile index 54a00c161..dee40960f 100644 --- a/browser/ios/Podfile +++ b/browser/ios/Podfile @@ -1,4 +1,4 @@ -platform :ios, '12.0' +platform :ios, '13.0' def capacitor_pods # Comment the next line if you're not using Swift and don't want to use dynamic frameworks diff --git a/browser/package.json b/browser/package.json index 3ca31e762..471619ba1 100644 --- a/browser/package.json +++ b/browser/package.json @@ -1,6 +1,6 @@ { "name": "@capacitor/browser", - "version": "1.0.7", + "version": "4.1.0", "description": "The Browser API provides the ability to open an in-app browser and subscribe to browser events.", "main": "dist/plugin.cjs.js", "module": "dist/esm/index.js", @@ -29,7 +29,7 @@ ], "scripts": { "verify": "npm run verify:ios && npm run verify:android && npm run verify:web", - "verify:ios": "cd ios && pod install && xcodebuild -workspace Plugin.xcworkspace -scheme Plugin && cd ..", + "verify:ios": "cd ios && pod install && xcodebuild -workspace Plugin.xcworkspace -scheme Plugin -destination generic/platform=iOS && cd ..", "verify:android": "cd android && ./gradlew clean build test && cd ..", "verify:web": "npm run build", "lint": "npm run eslint && npm run prettier -- --check && npm run swiftlint -- lint", @@ -45,10 +45,10 @@ "publish:cocoapod": "pod trunk push ./CapacitorBrowser.podspec --allow-warnings" }, "devDependencies": { - "@capacitor/android": "^3.0.0", - "@capacitor/core": "^3.0.0", - "@capacitor/docgen": "0.0.18", - "@capacitor/ios": "^3.0.0", + "@capacitor/android": "^4.0.0", + "@capacitor/core": "^4.0.0", + "@capacitor/docgen": "0.2.0", + "@capacitor/ios": "^4.0.0", "@ionic/eslint-config": "^0.3.0", "@ionic/prettier-config": "~1.0.1", "@ionic/swiftlint-config": "^1.1.2", @@ -61,7 +61,7 @@ "typescript": "~4.1.5" }, "peerDependencies": { - "@capacitor/core": "^3.0.0" + "@capacitor/core": "^4.0.0" }, "prettier": "@ionic/prettier-config", "swiftlint": "@ionic/swiftlint-config", diff --git a/browser/src/definitions.ts b/browser/src/definitions.ts index 78ba1b481..6946e5e7f 100644 --- a/browser/src/definitions.ts +++ b/browser/src/definitions.ts @@ -87,6 +87,24 @@ export interface OpenOptions { * @since 1.0.0 */ presentationStyle?: 'fullscreen' | 'popover'; + + /** + * iOS only: The width the browser when using presentationStyle 'popover' on iPads. + * + * Ignored on other platforms. + * + * @since 4.0.0 + */ + width?: number; + + /** + * iOS only: The height the browser when using presentationStyle 'popover' on iPads. + * + * Ignored on other platforms. + * + * @since 4.0.0 + */ + height?: number; } /** diff --git a/camera/CHANGELOG.md b/camera/CHANGELOG.md index c980349cb..73c709d46 100644 --- a/camera/CHANGELOG.md +++ b/camera/CHANGELOG.md @@ -3,6 +3,165 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [4.1.4](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/camera@4.1.3...@capacitor/camera@4.1.4) (2022-11-16) + +**Note:** Version bump only for package @capacitor/camera + + + + + +## [4.1.3](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/camera@4.1.2...@capacitor/camera@4.1.3) (2022-10-21) + +**Note:** Version bump only for package @capacitor/camera + + + + + +## [4.1.2](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/camera@4.1.1...@capacitor/camera@4.1.2) (2022-09-29) + + +### Bug Fixes + +* **camera:** make pickLimitedLibraryPhotos return photos on iOS 15+ ([#1191](https://github.com/ionic-team/capacitor-plugins/issues/1191)) ([a65c8ca](https://github.com/ionic-team/capacitor-plugins/commit/a65c8ca8582c15e16ece369b77d1eac5df43e60e)) + + + + + +## [4.1.1](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/camera@4.1.0...@capacitor/camera@4.1.1) (2022-09-12) + +**Note:** Version bump only for package @capacitor/camera + + + + + +# [4.1.0](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/camera@1.3.1...@capacitor/camera@4.1.0) (2022-08-24) + + +### Features + +* **camera:** Add support for iOS limited photo library mode ([#1125](https://github.com/ionic-team/capacitor-plugins/issues/1125)) ([cc5e4e6](https://github.com/ionic-team/capacitor-plugins/commit/cc5e4e683a2b9a9d216fac9ee88e8653a7ca68c6)) + + + + +## [4.0.1](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0...4.0.1) (2022-07-28) + +**Note:** Version bump only for package @capacitor/camera + + + + + +# [4.0.0](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0-beta.2...4.0.0) (2022-07-27) + +**Note:** Version bump only for package @capacitor/camera + + + + + +# [4.0.0-beta.2](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0-beta.0...4.0.0-beta.2) (2022-07-08) + +**Note:** Version bump only for package @capacitor/camera + + + + + +# 4.0.0-beta.0 (2022-06-27) + + +### Bug Fixes + +* **camera:** Append change listener only once ([#486](https://github.com/ionic-team/capacitor-plugins/issues/486)) ([5b7021e](https://github.com/ionic-team/capacitor-plugins/commit/5b7021e210649f8501a20ba6549903ecb6d42dcd)) +* **camera:** Append exif to android images ([#480](https://github.com/ionic-team/capacitor-plugins/issues/480)) ([cad8a30](https://github.com/ionic-team/capacitor-plugins/commit/cad8a30c562202fb819a4d260d5307f1b6b8fa44)) +* **camera:** avoid error if image has no orientation ([#554](https://github.com/ionic-team/capacitor-plugins/issues/554)) ([dc8a55a](https://github.com/ionic-team/capacitor-plugins/commit/dc8a55a71cdaaf7ad86aee8470a0c7b8284653c4)) +* **camera:** cleanup camera images if not needed ([#563](https://github.com/ionic-team/capacitor-plugins/issues/563)) ([a2e4f43](https://github.com/ionic-team/capacitor-plugins/commit/a2e4f4339119698e8dd066a5f2f8f065ab2e4727)) +* **camera:** correct photo resizing on iOS ([#460](https://github.com/ionic-team/capacitor-plugins/issues/460)) ([bc56e03](https://github.com/ionic-team/capacitor-plugins/commit/bc56e034c711b172a7ff503cabd2970adbc14b86)) +* **camera:** decode content uri when retrieving image from gallery ([#277](https://github.com/ionic-team/capacitor-plugins/issues/277)) ([a6cd1ad](https://github.com/ionic-team/capacitor-plugins/commit/a6cd1adc241bf21e4f7f06d24c0db4a4d7382dbc)) +* **camera:** Don't save gallery images on iOS 14+ ([#696](https://github.com/ionic-team/capacitor-plugins/issues/696)) ([7b2cc88](https://github.com/ionic-team/capacitor-plugins/commit/7b2cc88f6e83265c991ae9f81cfc3f6bed346250)) +* **camera:** fix camera source on Android ([#164](https://github.com/ionic-team/capacitor-plugins/issues/164)) ([e67f7c6](https://github.com/ionic-team/capacitor-plugins/commit/e67f7c6b06b20d7c3e8f0925c40fd75d23d9d717)) +* **camera:** Make allowEdit work on all devices ([#552](https://github.com/ionic-team/capacitor-plugins/issues/552)) ([5224177](https://github.com/ionic-team/capacitor-plugins/commit/5224177f77bdce1c8f028e2cef41614fa687502f)) +* **camera:** Make input file hidden ([#484](https://github.com/ionic-team/capacitor-plugins/issues/484)) ([cdc1835](https://github.com/ionic-team/capacitor-plugins/commit/cdc1835f3bbfb8db8e18fccace6103d83dd9edaa)) +* **camera:** Make web use source options ([#487](https://github.com/ionic-team/capacitor-plugins/issues/487)) ([7870e6b](https://github.com/ionic-team/capacitor-plugins/commit/7870e6b6ca196265640fc0ba3c1f52ddca075607)) +* **camera:** process picked image only once ([#782](https://github.com/ionic-team/capacitor-plugins/issues/782)) ([897dcaf](https://github.com/ionic-team/capacitor-plugins/commit/897dcaf839a6cb83256485c32df2ca0e7b439124)) +* **camera:** Properly reset orientation exif if corrected ([#545](https://github.com/ionic-team/capacitor-plugins/issues/545)) ([ad8c325](https://github.com/ionic-team/capacitor-plugins/commit/ad8c325af0a2459f5a7788be08a8da4118717671)) +* **camera:** query IMAGE_CAPTURE intent required by SDK 30 ([#160](https://github.com/ionic-team/capacitor-plugins/issues/160)) ([6484991](https://github.com/ionic-team/capacitor-plugins/commit/6484991d76d57bac0cbc82b9f050e146ec4732da)) +* **camera:** Remove capture attribute from multiple photo picker ([#687](https://github.com/ionic-team/capacitor-plugins/issues/687)) ([e551ef7](https://github.com/ionic-team/capacitor-plugins/commit/e551ef77eebe331cc7bf13c9c0eab5a0bd2da0d1)) +* **camera:** Remove unused saveCall ([#401](https://github.com/ionic-team/capacitor-plugins/issues/401)) ([95920da](https://github.com/ionic-team/capacitor-plugins/commit/95920da4d1844ed76a162651d5492a22a4038d26)) +* **camera:** Reset exif orientation if corrected ([#510](https://github.com/ionic-team/capacitor-plugins/issues/510)) ([a65c05e](https://github.com/ionic-team/capacitor-plugins/commit/a65c05e0de8f53e7371c194047a75797d53879b5)) +* **camera:** Resize not respecting aspect ratio on iOS ([#568](https://github.com/ionic-team/capacitor-plugins/issues/568)) ([ea2b801](https://github.com/ionic-team/capacitor-plugins/commit/ea2b8012aab7e5ea34cfa34735f7f55ba76a3882)) +* **camera:** return original image if editing is cancelled ([#566](https://github.com/ionic-team/capacitor-plugins/issues/566)) ([4786841](https://github.com/ionic-team/capacitor-plugins/commit/4786841099403a4d3d59aaf9103e8fa02aa8e4e2)) +* **camera:** Return proper exif when picking multiple images ([#712](https://github.com/ionic-team/capacitor-plugins/issues/712)) ([8451237](https://github.com/ionic-team/capacitor-plugins/commit/8451237e46f24c59e74e350eaa9b31e6d99a68a0)) +* **camera:** return single picture on pickImages ([#783](https://github.com/ionic-team/capacitor-plugins/issues/783)) ([9d65db1](https://github.com/ionic-team/capacitor-plugins/commit/9d65db1e74117fd1c1e7cd9bbba7efaeb4c13e0c)) +* **camera:** saveToGallery for edited images ([#602](https://github.com/ionic-team/capacitor-plugins/issues/602)) ([b5ac27d](https://github.com/ionic-team/capacitor-plugins/commit/b5ac27d59181ec3acc2909b2569d8ab45a829b1c)) +* **camera:** set camera direction for web ([#665](https://github.com/ionic-team/capacitor-plugins/issues/665)) ([4afedb9](https://github.com/ionic-team/capacitor-plugins/commit/4afedb96f3b745a86d9cacd33ca71c42ae3fb8d4)) +* **camera:** Use Locale.ROOT on toUpperCase ([#812](https://github.com/ionic-team/capacitor-plugins/issues/812)) ([6d689ac](https://github.com/ionic-team/capacitor-plugins/commit/6d689acc48e3746ddd35bd5e1e8d7f239cb7f8df)) +* add es2017 lib to tsconfig ([#180](https://github.com/ionic-team/capacitor-plugins/issues/180)) ([2c3776c](https://github.com/ionic-team/capacitor-plugins/commit/2c3776c38ca025c5ee965dec10ccf1cdb6c02e2f)) +* correct addListeners links ([#655](https://github.com/ionic-team/capacitor-plugins/issues/655)) ([f9871e7](https://github.com/ionic-team/capacitor-plugins/commit/f9871e7bd53478addb21155e148829f550c0e457)) +* Correct missing source_files path ([#590](https://github.com/ionic-team/capacitor-plugins/issues/590)) ([24e0fc2](https://github.com/ionic-team/capacitor-plugins/commit/24e0fc27cc314049012ab9915fa5e7bfb03313e1)) +* inline source code in esm map files ([#760](https://github.com/ionic-team/capacitor-plugins/issues/760)) ([a960489](https://github.com/ionic-team/capacitor-plugins/commit/a960489a19db0182b90d187a50deff9dfbe51038)) +* remove postpublish scripts ([#656](https://github.com/ionic-team/capacitor-plugins/issues/656)) ([ed6ac49](https://github.com/ionic-team/capacitor-plugins/commit/ed6ac499ebf4a47525071ccbfc36c27503e11f60)) +* **camera:** return file URL for path, not system path ([#170](https://github.com/ionic-team/capacitor-plugins/issues/170)) ([8a9e5c3](https://github.com/ionic-team/capacitor-plugins/commit/8a9e5c3dba3b232a1cca9f9a1e9b4520022abc09)) +* **camera:** Return the full webPath ([#502](https://github.com/ionic-team/capacitor-plugins/issues/502)) ([e849732](https://github.com/ionic-team/capacitor-plugins/commit/e849732dbcf5e85d1df09835c53ff5738fbb4ded)) +* **camera:** set settings again on callbacks ([#595](https://github.com/ionic-team/capacitor-plugins/issues/595)) ([908bd68](https://github.com/ionic-team/capacitor-plugins/commit/908bd688767e374cf8e96b3def08bd33dcdfd2aa)) +* support deprecated types from Capacitor 2 ([#139](https://github.com/ionic-team/capacitor-plugins/issues/139)) ([2d7127a](https://github.com/ionic-team/capacitor-plugins/commit/2d7127a488e26f0287951921a6db47c49d817336)) + + +### Features + +* set targetSDK default value to 31 ([#824](https://github.com/ionic-team/capacitor-plugins/issues/824)) ([3ee10de](https://github.com/ionic-team/capacitor-plugins/commit/3ee10de98067984c1a4e75295d001c5a895c47f4)) +* set targetSDK default value to 32 ([#970](https://github.com/ionic-team/capacitor-plugins/issues/970)) ([fa70d96](https://github.com/ionic-team/capacitor-plugins/commit/fa70d96f141af751aae53ceb5642c46b204f5958)) +* Upgrade gradle to 7.4 ([#826](https://github.com/ionic-team/capacitor-plugins/issues/826)) ([5db0906](https://github.com/ionic-team/capacitor-plugins/commit/5db0906f6264287c4f8e69dbaecf19d4d387824b)) +* Use java 11 ([#910](https://github.com/ionic-team/capacitor-plugins/issues/910)) ([5acb2a2](https://github.com/ionic-team/capacitor-plugins/commit/5acb2a288a413492b163e4e97da46a085d9e4be0)) +* **android:** implements Activity Result API changes for permissions and activity results ([#222](https://github.com/ionic-team/capacitor-plugins/issues/222)) ([f671b9f](https://github.com/ionic-team/capacitor-plugins/commit/f671b9f4b472806ef43db6dcf302d4503cf1828c)) +* **camera:** Add new method for multiple image picking from gallery ([#671](https://github.com/ionic-team/capacitor-plugins/issues/671)) ([a49c590](https://github.com/ionic-team/capacitor-plugins/commit/a49c5901683da12438fbafbd1bf6ae91133d18ed)) +* **camera:** Return if image was saved to gallery ([#599](https://github.com/ionic-team/capacitor-plugins/issues/599)) ([594af3b](https://github.com/ionic-team/capacitor-plugins/commit/594af3be0982371e6c61e4bdb830c6bbb3963913)) +* **camera:** Support for 1 Gallery app ([#791](https://github.com/ionic-team/capacitor-plugins/issues/791)) ([77e8c97](https://github.com/ionic-team/capacitor-plugins/commit/77e8c979394d5fb1804fc097ecaeee46a973e640)) +* **camera:** Support for Samsung Gallery app on pickImages ([#706](https://github.com/ionic-team/capacitor-plugins/issues/706)) ([fd059fc](https://github.com/ionic-team/capacitor-plugins/commit/fd059fcd2e53661e95e230f684a6d32408db6787)) +* **camera:** use a distinguishable permission denied string for camera and photos ([#379](https://github.com/ionic-team/capacitor-plugins/issues/379)) ([c71657f](https://github.com/ionic-team/capacitor-plugins/commit/c71657f7e14eae4efd4d2c7d00d77a7b329a7920)) +* **camera:** Use same error messages for permission deny ([#404](https://github.com/ionic-team/capacitor-plugins/issues/404)) ([fffcd47](https://github.com/ionic-team/capacitor-plugins/commit/fffcd47f0237b6997bfa4ce430ef29392047ea0e)) +* add commonjs output format ([#179](https://github.com/ionic-team/capacitor-plugins/issues/179)) ([8e9e098](https://github.com/ionic-team/capacitor-plugins/commit/8e9e09862064b3f6771d7facbc4008e995d9b463)) +* Camera plugin ([#33](https://github.com/ionic-team/capacitor-plugins/issues/33)) ([4864928](https://github.com/ionic-team/capacitor-plugins/commit/48649288b1ba45e1901ad077b3b7b7314de04d4a)) + + + + + +## [1.3.1](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/camera@1.3.0...@capacitor/camera@1.3.1) (2022-03-03) + + +### Bug Fixes + +* **camera:** Return the image on dismiss completion ([#849](https://github.com/ionic-team/capacitor-plugins/issues/849)) ([f083841](https://github.com/ionic-team/capacitor-plugins/commit/f0838416c6cf731aaae83fcb4986568357878b41)) + + + + + +# [1.3.0](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/camera@1.2.4...@capacitor/camera@1.3.0) (2022-02-10) + + +### Bug Fixes + +* **camera:** process picked image only once ([#782](https://github.com/ionic-team/capacitor-plugins/issues/782)) ([897dcaf](https://github.com/ionic-team/capacitor-plugins/commit/897dcaf839a6cb83256485c32df2ca0e7b439124)) +* **camera:** return single picture on pickImages ([#783](https://github.com/ionic-team/capacitor-plugins/issues/783)) ([9d65db1](https://github.com/ionic-team/capacitor-plugins/commit/9d65db1e74117fd1c1e7cd9bbba7efaeb4c13e0c)) +* **camera:** Use Locale.ROOT on toUpperCase ([#812](https://github.com/ionic-team/capacitor-plugins/issues/812)) ([6d689ac](https://github.com/ionic-team/capacitor-plugins/commit/6d689acc48e3746ddd35bd5e1e8d7f239cb7f8df)) + + +### Features + +* **camera:** Support for 1 Gallery app ([#791](https://github.com/ionic-team/capacitor-plugins/issues/791)) ([77e8c97](https://github.com/ionic-team/capacitor-plugins/commit/77e8c979394d5fb1804fc097ecaeee46a973e640)) +* **camera:** Support for Samsung Gallery app on pickImages ([#706](https://github.com/ionic-team/capacitor-plugins/issues/706)) ([fd059fc](https://github.com/ionic-team/capacitor-plugins/commit/fd059fcd2e53661e95e230f684a6d32408db6787)) + + + + + ## [1.2.4](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/camera@1.2.3...@capacitor/camera@1.2.4) (2022-01-19) diff --git a/camera/CapacitorCamera.podspec b/camera/CapacitorCamera.podspec index f915839d0..a47e55d7c 100644 --- a/camera/CapacitorCamera.podspec +++ b/camera/CapacitorCamera.podspec @@ -11,7 +11,7 @@ Pod::Spec.new do |s| s.author = package['author'] s.source = { :git => 'https://github.com/ionic-team/capacitor-plugins.git', :tag => package['name'] + '@' + package['version'] } s.source_files = 'ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}', 'camera/ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}' - s.ios.deployment_target = '12.0' + s.ios.deployment_target = '13.0' s.dependency 'Capacitor' s.swift_version = '5.1' end diff --git a/camera/README.md b/camera/README.md index 861a25f90..09851033f 100644 --- a/camera/README.md +++ b/camera/README.md @@ -38,8 +38,8 @@ Additionally, because the Camera API launches a separate Activity to handle taki This plugin will use the following project variables (defined in your app's `variables.gradle` file): -- `$androidxExifInterfaceVersion`: version of `androidx.exifinterface:exifinterface` (default: `1.3.2`) -- `$androidxMaterialVersion`: version of `com.google.android.material:material` (default: `1.3.0`) +- `$androidxExifInterfaceVersion`: version of `androidx.exifinterface:exifinterface` (default: `1.3.3`) +- `$androidxMaterialVersion`: version of `com.google.android.material:material` (default: `1.6.1`) ## PWA Notes @@ -74,6 +74,8 @@ const takePicture = async () => { * [`getPhoto(...)`](#getphoto) * [`pickImages(...)`](#pickimages) +* [`pickLimitedLibraryPhotos()`](#picklimitedlibraryphotos) +* [`getLimitedLibraryPhotos()`](#getlimitedlibraryphotos) * [`checkPermissions()`](#checkpermissions) * [`requestPermissions(...)`](#requestpermissions) * [Interfaces](#interfaces) @@ -125,6 +127,38 @@ On iOS 13 and older it only allows to pick one picture. -------------------- +### pickLimitedLibraryPhotos() + +```typescript +pickLimitedLibraryPhotos() => Promise +``` + +iOS 14+ Only: Allows the user to update their limited photo library selection. +On iOS 15+ returns all the limited photos after the picker dismissal. +On iOS 14 or if the user gave full access to the photos it returns an empty array. + +**Returns:** Promise<GalleryPhotos> + +**Since:** 4.1.0 + +-------------------- + + +### getLimitedLibraryPhotos() + +```typescript +getLimitedLibraryPhotos() => Promise +``` + +iOS 14+ Only: Return an array of photos selected from the limited photo library. + +**Returns:** Promise<GalleryPhotos> + +**Since:** 4.1.0 + +-------------------- + + ### checkPermissions() ```typescript @@ -168,7 +202,7 @@ Request camera and photo album permissions | ------------------ | -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----- | | **`base64String`** | string | The base64 encoded string representation of the image, if using CameraResultType.Base64. | 1.0.0 | | **`dataUrl`** | string | The url starting with 'data:image/jpeg;base64,' and the base64 encoded string representation of the image, if using CameraResultType.DataUrl. | 1.0.0 | -| **`path`** | string | If using CameraResultType.Uri, the path will contain a full, platform-specific file URL that can be read later using the Filsystem API. | 1.0.0 | +| **`path`** | string | If using CameraResultType.Uri, the path will contain a full, platform-specific file URL that can be read later using the Filesystem API. | 1.0.0 | | **`webPath`** | string | webPath returns a path that can be used to set the src attribute of an image for efficient loading and rendering. | 1.0.0 | | **`exif`** | any | Exif data, if any, retrieved from the image | 1.0.0 | | **`format`** | string | The format of the image, ex: jpeg, png, gif. iOS and Android only support jpeg. Web supports jpeg and png. gif is only supported if using file input. | 1.0.0 | @@ -177,24 +211,23 @@ Request camera and photo album permissions #### ImageOptions -| Prop | Type | Description | Default | Since | -| ------------------------- | ------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------- | ----- | -| **`quality`** | number | The quality of image to return as JPEG, from 0-100 | | 1.0.0 | -| **`allowEditing`** | boolean | Whether to allow the user to crop or make small edits (platform specific). On iOS 14+ it's only supported for CameraSource.Camera, but not for CameraSource.Photos. | | 1.0.0 | -| **`resultType`** | CameraResultType | How the data should be returned. Currently, only 'Base64', 'DataUrl' or 'Uri' is supported | | 1.0.0 | -| **`saveToGallery`** | boolean | Whether to save the photo to the gallery. If the photo was picked from the gallery, it will only be saved if edited. | : false | 1.0.0 | -| **`width`** | number | The width of the saved image | | 1.0.0 | -| **`height`** | number | The height of the saved image | | 1.0.0 | -| **`preserveAspectRatio`** | boolean | This setting has no effect. Picture resizing always preserve aspect ratio. | | 1.0.0 | -| **`correctOrientation`** | boolean | Whether to automatically rotate the image "up" to correct for orientation in portrait mode | : true | 1.0.0 | -| **`source`** | CameraSource | The source to get the photo from. By default this prompts the user to select either the photo album or take a photo. | : CameraSource.Prompt | 1.0.0 | -| **`direction`** | CameraDirection | iOS and Web only: The camera direction. | : CameraDirection.Rear | 1.0.0 | -| **`presentationStyle`** | 'fullscreen' \| 'popover' | iOS only: The presentation style of the Camera. | : 'fullscreen' | 1.0.0 | -| **`webUseInput`** | boolean | Web only: Whether to use the PWA Element experience or file input. The default is to use PWA Elements if installed and fall back to file input. To always use file input, set this to `true`. Learn more about PWA Elements: https://capacitorjs.com/docs/pwa-elements | | 1.0.0 | -| **`promptLabelHeader`** | string | Text value to use when displaying the prompt. | : 'Photo' | 1.0.0 | -| **`promptLabelCancel`** | string | Text value to use when displaying the prompt. iOS only: The label of the 'cancel' button. | : 'Cancel' | 1.0.0 | -| **`promptLabelPhoto`** | string | Text value to use when displaying the prompt. The label of the button to select a saved image. | : 'From Photos' | 1.0.0 | -| **`promptLabelPicture`** | string | Text value to use when displaying the prompt. The label of the button to open the camera. | : 'Take Picture' | 1.0.0 | +| Prop | Type | Description | Default | Since | +| ------------------------ | ------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------- | ----- | +| **`quality`** | number | The quality of image to return as JPEG, from 0-100 | | 1.0.0 | +| **`allowEditing`** | boolean | Whether to allow the user to crop or make small edits (platform specific). On iOS 14+ it's only supported for CameraSource.Camera, but not for CameraSource.Photos. | | 1.0.0 | +| **`resultType`** | CameraResultType | How the data should be returned. Currently, only 'Base64', 'DataUrl' or 'Uri' is supported | | 1.0.0 | +| **`saveToGallery`** | boolean | Whether to save the photo to the gallery. If the photo was picked from the gallery, it will only be saved if edited. | : false | 1.0.0 | +| **`width`** | number | The desired maximum width of the saved image. The aspect ratio is respected. | | 1.0.0 | +| **`height`** | number | The desired maximum height of the saved image. The aspect ratio is respected. | | 1.0.0 | +| **`correctOrientation`** | boolean | Whether to automatically rotate the image "up" to correct for orientation in portrait mode | : true | 1.0.0 | +| **`source`** | CameraSource | The source to get the photo from. By default this prompts the user to select either the photo album or take a photo. | : CameraSource.Prompt | 1.0.0 | +| **`direction`** | CameraDirection | iOS and Web only: The camera direction. | : CameraDirection.Rear | 1.0.0 | +| **`presentationStyle`** | 'fullscreen' \| 'popover' | iOS only: The presentation style of the Camera. | : 'fullscreen' | 1.0.0 | +| **`webUseInput`** | boolean | Web only: Whether to use the PWA Element experience or file input. The default is to use PWA Elements if installed and fall back to file input. To always use file input, set this to `true`. Learn more about PWA Elements: https://capacitorjs.com/docs/web/pwa-elements | | 1.0.0 | +| **`promptLabelHeader`** | string | Text value to use when displaying the prompt. | : 'Photo' | 1.0.0 | +| **`promptLabelCancel`** | string | Text value to use when displaying the prompt. iOS only: The label of the 'cancel' button. | : 'Cancel' | 1.0.0 | +| **`promptLabelPhoto`** | string | Text value to use when displaying the prompt. The label of the button to select a saved image. | : 'From Photos' | 1.0.0 | +| **`promptLabelPicture`** | string | Text value to use when displaying the prompt. The label of the button to open the camera. | : 'Take Picture' | 1.0.0 | #### GalleryPhotos @@ -208,7 +241,7 @@ Request camera and photo album permissions | Prop | Type | Description | Since | | ------------- | ------------------- | ----------------------------------------------------------------------------------------------------------------- | ----- | -| **`path`** | string | Full, platform-specific file URL that can be read later using the Filsystem API. | 1.2.0 | +| **`path`** | string | Full, platform-specific file URL that can be read later using the Filesystem API. | 1.2.0 | | **`webPath`** | string | webPath returns a path that can be used to set the src attribute of an image for efficient loading and rendering. | 1.2.0 | | **`exif`** | any | Exif data, if any, retrieved from the image | 1.2.0 | | **`format`** | string | The format of the image, ex: jpeg, png, gif. iOS and Android only support jpeg. Web supports jpeg, png and gif. | 1.2.0 | @@ -219,8 +252,8 @@ Request camera and photo album permissions | Prop | Type | Description | Default | Since | | ------------------------ | -------------------------------------- | ------------------------------------------------------------------------------------------ | --------------------------- | ----- | | **`quality`** | number | The quality of image to return as JPEG, from 0-100 | | 1.2.0 | -| **`width`** | number | The width of the saved image | | 1.2.0 | -| **`height`** | number | The height of the saved image | | 1.2.0 | +| **`width`** | number | The desired maximum width of the saved image. The aspect ratio is respected. | | 1.2.0 | +| **`height`** | number | The desired maximum height of the saved image. The aspect ratio is respected. | | 1.2.0 | | **`correctOrientation`** | boolean | Whether to automatically rotate the image "up" to correct for orientation in portrait mode | : true | 1.2.0 | | **`presentationStyle`** | 'fullscreen' \| 'popover' | iOS only: The presentation style of the Camera. | : 'fullscreen' | 1.2.0 | | **`limit`** | number | iOS only: Maximum number of pictures the user will be able to choose. | 0 (unlimited) | 1.2.0 | @@ -277,7 +310,7 @@ Request camera and photo album permissions | ------------ | --------------------- | ------------------------------------------------------------------ | | **`Prompt`** | 'PROMPT' | Prompts the user to select either the photo album or take a photo. | | **`Camera`** | 'CAMERA' | Take a new photo using the camera. | -| **`Photos`** | 'PHOTOS' | Pick an existing photo fron the gallery or photo album. | +| **`Photos`** | 'PHOTOS' | Pick an existing photo from the gallery or photo album. | #### CameraDirection diff --git a/camera/android/build.gradle b/camera/android/build.gradle index 8ce7f737e..e7a8ef72b 100644 --- a/camera/android/build.gradle +++ b/camera/android/build.gradle @@ -1,29 +1,41 @@ ext { - junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.1' - androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.2.0' - androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.3.0' - androidxExifInterfaceVersion = project.hasProperty('androidxExifInterfaceVersion') ? rootProject.ext.androidxExifInterfaceVersion : '1.3.2' - androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.1.2' - androidxMaterialVersion = project.hasProperty('androidxMaterialVersion') ? rootProject.ext.androidxMaterialVersion : '1.3.0' + capacitorVersion = System.getenv('CAPACITOR_VERSION') + junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.2' + androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.4.2' + androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.4.0' + androidxExifInterfaceVersion = project.hasProperty('androidxExifInterfaceVersion') ? rootProject.ext.androidxExifInterfaceVersion : '1.3.3' + androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.1.3' + androidxMaterialVersion = project.hasProperty('androidxMaterialVersion') ? rootProject.ext.androidxMaterialVersion : '1.6.1' } buildscript { repositories { google() mavenCentral() + maven { + url "https://plugins.gradle.org/m2/" + } } dependencies { - classpath 'com.android.tools.build:gradle:4.2.1' + classpath 'com.android.tools.build:gradle:7.2.1' + if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + classpath 'io.github.gradle-nexus:publish-plugin:1.1.0' + } } } apply plugin: 'com.android.library' +if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + apply plugin: 'io.github.gradle-nexus.publish-plugin' + apply from: file('../../scripts/android/publish-root.gradle') + apply from: file('../../scripts/android/publish-module.gradle') +} android { - compileSdkVersion project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 30 + compileSdkVersion project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 32 defaultConfig { - minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 21 - targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 30 + minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 22 + targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 32 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" @@ -38,21 +50,26 @@ android { abortOnError false } compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility JavaVersion.VERSION_11 + targetCompatibility JavaVersion.VERSION_11 } } repositories { google() mavenCentral() - jcenter() } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation project(':capacitor-android') + + if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + implementation "com.capacitorjs:core:$capacitorVersion" + } else { + implementation project(':capacitor-android') + } + implementation "androidx.exifinterface:exifinterface:$androidxExifInterfaceVersion" implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion" implementation "com.google.android.material:material:$androidxMaterialVersion" diff --git a/camera/android/gradle/wrapper/gradle-wrapper.jar b/camera/android/gradle/wrapper/gradle-wrapper.jar index e708b1c02..41d9927a4 100644 Binary files a/camera/android/gradle/wrapper/gradle-wrapper.jar and b/camera/android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/camera/android/gradle/wrapper/gradle-wrapper.properties b/camera/android/gradle/wrapper/gradle-wrapper.properties index 3c4101c3e..92f06b50f 100644 --- a/camera/android/gradle/wrapper/gradle-wrapper.properties +++ b/camera/android/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/camera/android/gradlew b/camera/android/gradlew index 4f906e0c8..1b6c78733 100755 --- a/camera/android/gradlew +++ b/camera/android/gradlew @@ -1,7 +1,7 @@ -#!/usr/bin/env sh +#!/bin/sh # -# Copyright 2015 the original author or authors. +# Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,67 +17,101 @@ # ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` +APP_BASE_NAME=${0##*/} # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar @@ -87,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -98,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" + JAVACMD=java which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the @@ -106,80 +140,95 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=`expr $i + 1` + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" diff --git a/camera/android/src/main/java/com/capacitorjs/plugins/camera/CameraPlugin.java b/camera/android/src/main/java/com/capacitorjs/plugins/camera/CameraPlugin.java index b69f6a3e8..7e2869d99 100644 --- a/camera/android/src/main/java/com/capacitorjs/plugins/camera/CameraPlugin.java +++ b/camera/android/src/main/java/com/capacitorjs/plugins/camera/CameraPlugin.java @@ -3,13 +3,18 @@ import android.Manifest; import android.app.Activity; import android.content.ActivityNotFoundException; +import android.content.ContentResolver; +import android.content.ContentValues; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.net.Uri; +import android.os.Build; import android.os.Bundle; +import android.os.Environment; +import android.os.Parcelable; import android.provider.MediaStore; import android.util.Base64; import androidx.activity.result.ActivityResult; @@ -33,8 +38,10 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; +import java.io.OutputStream; import java.util.ArrayList; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.concurrent.Executor; import java.util.concurrent.Executors; @@ -97,7 +104,17 @@ public void getPhoto(PluginCall call) { @PluginMethod public void pickImages(PluginCall call) { settings = getSettings(call); - openPhotos(call, true); + openPhotos(call, true, false); + } + + @PluginMethod + public void pickLimitedLibraryPhotos(PluginCall call) { + call.unimplemented("not supported on android"); + } + + @PluginMethod + public void getLimitedLibraryPhotos(PluginCall call) { + call.unimplemented("not supported on android"); } private void doShow(PluginCall call) { @@ -192,17 +209,20 @@ private boolean checkPhotosPermissions(PluginCall call) { */ @PermissionCallback private void cameraPermissionsCallback(PluginCall call) { - if (settings.getSource() == CameraSource.CAMERA && getPermissionState(CAMERA) != PermissionState.GRANTED) { - Logger.debug(getLogTag(), "User denied camera permission: " + getPermissionState(CAMERA).toString()); - call.reject(PERMISSION_DENIED_ERROR_CAMERA); - return; - } else if (settings.getSource() == CameraSource.PHOTOS && getPermissionState(PHOTOS) != PermissionState.GRANTED) { - Logger.debug(getLogTag(), "User denied photos permission: " + getPermissionState(PHOTOS).toString()); - call.reject(PERMISSION_DENIED_ERROR_PHOTOS); - return; + if (call.getMethodName().equals("pickImages")) { + openPhotos(call, true, true); + } else { + if (settings.getSource() == CameraSource.CAMERA && getPermissionState(CAMERA) != PermissionState.GRANTED) { + Logger.debug(getLogTag(), "User denied camera permission: " + getPermissionState(CAMERA).toString()); + call.reject(PERMISSION_DENIED_ERROR_CAMERA); + return; + } else if (settings.getSource() == CameraSource.PHOTOS && getPermissionState(PHOTOS) != PermissionState.GRANTED) { + Logger.debug(getLogTag(), "User denied photos permission: " + getPermissionState(PHOTOS).toString()); + call.reject(PERMISSION_DENIED_ERROR_PHOTOS); + return; + } + doShow(call); } - - doShow(call); } private CameraSettings getSettings(PluginCall call) { @@ -228,7 +248,7 @@ private CameraResultType getResultType(String resultType) { return null; } try { - return CameraResultType.valueOf(resultType.toUpperCase()); + return CameraResultType.valueOf(resultType.toUpperCase(Locale.ROOT)); } catch (IllegalArgumentException ex) { Logger.debug(getLogTag(), "Invalid result type \"" + resultType + "\", defaulting to base64"); return CameraResultType.BASE64; @@ -260,16 +280,18 @@ public void openCamera(final PluginCall call) { } public void openPhotos(final PluginCall call) { - openPhotos(call, false); + openPhotos(call, false, false); } - private void openPhotos(final PluginCall call, boolean multiple) { - if (multiple || checkPhotosPermissions(call)) { + private void openPhotos(final PluginCall call, boolean multiple, boolean skipPermission) { + if (skipPermission || checkPhotosPermissions(call)) { Intent intent = new Intent(Intent.ACTION_PICK); intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, multiple); intent.setType("image/*"); try { if (multiple) { + intent.putExtra("multi-pick", multiple); + intent.putExtra(Intent.EXTRA_MIME_TYPES, new String[] { "image/*" }); startActivityForResult(call, intent, "processPickedImages"); } else { startActivityForResult(call, intent, "processPickedImage"); @@ -320,21 +342,55 @@ public void processPickedImage(PluginCall call, ActivityResult result) { @ActivityCallback public void processPickedImages(PluginCall call, ActivityResult result) { Intent data = result.getData(); - if (data != null && data.getClipData() != null) { + if (data != null) { Executor executor = Executors.newSingleThreadExecutor(); executor.execute( () -> { JSObject ret = new JSObject(); JSArray photos = new JSArray(); - int count = data.getClipData().getItemCount(); - for (int i = 0; i < count; i++) { - Uri imageUri = data.getClipData().getItemAt(i).getUri(); + if (data.getClipData() != null) { + int count = data.getClipData().getItemCount(); + for (int i = 0; i < count; i++) { + Uri imageUri = data.getClipData().getItemAt(i).getUri(); + JSObject processResult = processPickedImages(imageUri); + if (processResult.getString("error") != null && !processResult.getString("error").isEmpty()) { + call.reject(processResult.getString("error")); + return; + } else { + photos.put(processResult); + } + } + } else if (data.getData() != null) { + Uri imageUri = data.getData(); JSObject processResult = processPickedImages(imageUri); if (processResult.getString("error") != null && !processResult.getString("error").isEmpty()) { call.reject(processResult.getString("error")); return; } else { - photos.put(processPickedImages(imageUri)); + photos.put(processResult); + } + } else if (data.getExtras() != null) { + Bundle bundle = data.getExtras(); + if (bundle.keySet().contains("selectedItems")) { + ArrayList fileUris = bundle.getParcelableArrayList("selectedItems"); + if (fileUris != null) { + for (Parcelable fileUri : fileUris) { + if (fileUri instanceof Uri) { + Uri imageUri = (Uri) fileUri; + try { + JSObject processResult = processPickedImages(imageUri); + if (processResult.getString("error") != null && !processResult.getString("error").isEmpty()) { + call.reject(processResult.getString("error")); + return; + } else { + photos.put(processResult); + } + } catch (SecurityException ex) { + call.reject("SecurityException"); + } + } + } + } } } ret.put("photos", photos); @@ -453,15 +509,21 @@ private void processEditedImage(PluginCall call, ActivityResult result) { private Uri saveImage(Uri uri, InputStream is) throws IOException { File outFile = null; if (uri.getScheme().equals("content")) { - String filename = Uri.parse(Uri.decode(uri.toString())).getLastPathSegment(); - if (!filename.contains(".jpg") && !filename.contains(".jpeg")) { - filename += "." + (new java.util.Date()).getTime() + ".jpeg"; - } - File cacheDir = getContext().getCacheDir(); - outFile = new File(cacheDir, filename); + outFile = getTempFile(uri); } else { outFile = new File(uri.getPath()); } + try { + writePhoto(outFile, is); + } catch (FileNotFoundException ex) { + // Some gallery apps return read only file url, create a temporary file for modifications + outFile = getTempFile(uri); + writePhoto(outFile, is); + } + return Uri.fromFile(outFile); + } + + private void writePhoto(File outFile, InputStream is) throws IOException { FileOutputStream fos = new FileOutputStream(outFile); byte[] buffer = new byte[1024]; int len; @@ -469,7 +531,15 @@ private Uri saveImage(Uri uri, InputStream is) throws IOException { fos.write(buffer, 0, len); } fos.close(); - return Uri.fromFile(outFile); + } + + private File getTempFile(Uri uri) { + String filename = Uri.parse(Uri.decode(uri.toString())).getLastPathSegment(); + if (!filename.contains(".jpg") && !filename.contains(".jpeg")) { + filename += "." + (new java.util.Date()).getTime() + ".jpeg"; + } + File cacheDir = getContext().getCacheDir(); + return new File(cacheDir, filename); } /** @@ -478,6 +548,7 @@ private Uri saveImage(Uri uri, InputStream is) throws IOException { * @param bitmap * @param u */ + @SuppressWarnings("deprecation") private void returnResult(PluginCall call, Bitmap bitmap, Uri u) { ExifWrapper exif = ImageUtils.getExifData(getContext(), bitmap, u); try { @@ -501,18 +572,49 @@ private void returnResult(PluginCall call, Bitmap bitmap, Uri u) { try { String fileToSavePath = imageEditedFileSavePath != null ? imageEditedFileSavePath : imageFileSavePath; File fileToSave = new File(fileToSavePath); - String inserted = MediaStore.Images.Media.insertImage( - getContext().getContentResolver(), - fileToSavePath, - fileToSave.getName(), - "" - ); - if (inserted == null) { - isSaved = false; + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + ContentResolver resolver = getContext().getContentResolver(); + ContentValues values = new ContentValues(); + values.put(MediaStore.MediaColumns.DISPLAY_NAME, fileToSave.getName()); + values.put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg"); + values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DCIM); + + final Uri contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; + Uri uri = resolver.insert(contentUri, values); + + if (uri == null) { + throw new IOException("Failed to create new MediaStore record."); + } + + OutputStream stream = resolver.openOutputStream(uri); + if (stream == null) { + throw new IOException("Failed to open output stream."); + } + + Boolean inserted = bitmap.compress(Bitmap.CompressFormat.JPEG, settings.getQuality(), stream); + + if (!inserted) { + isSaved = false; + } + } else { + String inserted = MediaStore.Images.Media.insertImage( + getContext().getContentResolver(), + fileToSavePath, + fileToSave.getName(), + "" + ); + + if (inserted == null) { + isSaved = false; + } } } catch (FileNotFoundException e) { isSaved = false; Logger.error(getLogTag(), IMAGE_GALLERY_SAVE_ERROR, e); + } catch (IOException e) { + isSaved = false; + Logger.error(getLogTag(), IMAGE_GALLERY_SAVE_ERROR, e); } } diff --git a/camera/android/src/main/java/com/capacitorjs/plugins/camera/ImageUtils.java b/camera/android/src/main/java/com/capacitorjs/plugins/camera/ImageUtils.java index f54e25149..82d82aad0 100644 --- a/camera/android/src/main/java/com/capacitorjs/plugins/camera/ImageUtils.java +++ b/camera/android/src/main/java/com/capacitorjs/plugins/camera/ImageUtils.java @@ -15,14 +15,15 @@ public class ImageUtils { /** - * Resize an image to the given width and height considering the preserveAspectRatio flag. + * Resize an image to the given max width and max height. Constraint can be put + * on one dimension, or both. Resize will always preserve aspect ratio. * @param bitmap - * @param width - * @param height + * @param desiredMaxWidth + * @param desiredMaxHeight * @return a new, scaled Bitmap */ - public static Bitmap resize(Bitmap bitmap, final int width, final int height) { - return ImageUtils.resizePreservingAspectRatio(bitmap, width, height); + public static Bitmap resize(Bitmap bitmap, final int desiredMaxWidth, final int desiredMaxHeight) { + return ImageUtils.resizePreservingAspectRatio(bitmap, desiredMaxWidth, desiredMaxHeight); } /** diff --git a/camera/ios/Plugin.xcodeproj/project.pbxproj b/camera/ios/Plugin.xcodeproj/project.pbxproj index f8b8ed64f..8840c25ad 100644 --- a/camera/ios/Plugin.xcodeproj/project.pbxproj +++ b/camera/ios/Plugin.xcodeproj/project.pbxproj @@ -394,7 +394,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -454,7 +454,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; @@ -477,12 +477,13 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Plugin/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks $(FRAMEWORK_SEARCH_PATHS)\n$(FRAMEWORK_SEARCH_PATHS)\n$(FRAMEWORK_SEARCH_PATHS)"; ONLY_ACTIVE_ARCH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.getcapacitor.Plugin; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; + SUPPORTS_MACCATALYST = NO; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -502,12 +503,13 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Plugin/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks $(FRAMEWORK_SEARCH_PATHS)"; ONLY_ACTIVE_ARCH = NO; PRODUCT_BUNDLE_IDENTIFIER = com.getcapacitor.Plugin; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; + SUPPORTS_MACCATALYST = NO; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; diff --git a/camera/ios/Plugin/CameraExtensions.swift b/camera/ios/Plugin/CameraExtensions.swift index 3ba08569c..c4d19a6ce 100644 --- a/camera/ios/Plugin/CameraExtensions.swift +++ b/camera/ios/Plugin/CameraExtensions.swift @@ -52,7 +52,7 @@ internal extension PHAsset { options.version = .current var result: [String: Any] = [:] - _ = PHCachingImageManager().requestImageData(for: self, options: options) { (data, _, _, _) in + _ = PHCachingImageManager().requestImageDataAndOrientation(for: self, options: options) { (data, _, _, _) in if let data = data as NSData? { let options = [kCGImageSourceShouldCache as String: kCFBooleanFalse] as CFDictionary if let imgSrc = CGImageSourceCreateWithData(data, options), diff --git a/camera/ios/Plugin/CameraPlugin.m b/camera/ios/Plugin/CameraPlugin.m index 1de37c36f..2edbf0673 100644 --- a/camera/ios/Plugin/CameraPlugin.m +++ b/camera/ios/Plugin/CameraPlugin.m @@ -6,4 +6,6 @@ CAP_PLUGIN_METHOD(pickImages, CAPPluginReturnPromise); CAP_PLUGIN_METHOD(checkPermissions, CAPPluginReturnPromise); CAP_PLUGIN_METHOD(requestPermissions, CAPPluginReturnPromise); + CAP_PLUGIN_METHOD(pickLimitedLibraryPhotos, CAPPluginReturnPromise); + CAP_PLUGIN_METHOD(getLimitedLibraryPhotos, CAPPluginReturnPromise); ) diff --git a/camera/ios/Plugin/CameraPlugin.swift b/camera/ios/Plugin/CameraPlugin.swift index 1dd8a1c69..c5985d96f 100644 --- a/camera/ios/Plugin/CameraPlugin.swift +++ b/camera/ios/Plugin/CameraPlugin.swift @@ -66,6 +66,80 @@ public class CameraPlugin: CAPPlugin { } } + @objc func pickLimitedLibraryPhotos(_ call: CAPPluginCall) { + if #available(iOS 14, *) { + PHPhotoLibrary.requestAuthorization(for: .readWrite) { (granted) in + if granted == .limited { + if let viewController = self.bridge?.viewController { + if #available(iOS 15, *) { + PHPhotoLibrary.shared().presentLimitedLibraryPicker(from: viewController) { _ in + self.getLimitedLibraryPhotos(call) + } + } else { + PHPhotoLibrary.shared().presentLimitedLibraryPicker(from: viewController) + call.resolve([ + "photos": [] + ]) + } + } + } else { + call.resolve([ + "photos": [] + ]) + } + } + } else { + call.unavailable("Not available on iOS 13") + } + } + + @objc func getLimitedLibraryPhotos(_ call: CAPPluginCall) { + if #available(iOS 14, *) { + PHPhotoLibrary.requestAuthorization(for: .readWrite) { (granted) in + if granted == .limited { + + self.call = call + + DispatchQueue.global(qos: .utility).async { + let assets = PHAsset.fetchAssets(with: .image, options: nil) + var processedImages: [ProcessedImage] = [] + + let imageManager = PHImageManager.default() + let options = PHImageRequestOptions() + options.deliveryMode = .highQualityFormat + + let group = DispatchGroup() + + for index in 0...(assets.count - 1) { + let asset = assets.object(at: index) + let fullSize = CGSize(width: asset.pixelWidth, height: asset.pixelHeight) + + group.enter() + imageManager.requestImage(for: asset, targetSize: fullSize, contentMode: .default, options: options) { image, _ in + guard let image = image else { + group.leave() + return + } + processedImages.append(self.processedImage(from: image, with: asset.imageData)) + group.leave() + } + } + + group.notify(queue: .global(qos: .utility)) { [weak self] in + self?.returnImages(processedImages) + } + } + } else { + call.resolve([ + "photos": [] + ]) + } + } + } else { + call.unavailable("Not available on iOS 13") + } + } + @objc func getPhoto(_ call: CAPPluginCall) { self.multiple = false self.call = call @@ -75,7 +149,6 @@ public class CameraPlugin: CAPPlugin { if let missingUsageDescription = checkUsageDescriptions() { CAPLog.print("⚡️ ", self.pluginId, "-", missingUsageDescription) call.reject(missingUsageDescription) - bridge?.alert("Camera Error", "Missing required usage description. See console for more information") return } @@ -158,11 +231,12 @@ extension CameraPlugin: UIImagePickerControllerDelegate, UINavigationControllerD } public func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) { - picker.dismiss(animated: true, completion: nil) - if let processedImage = processImage(from: info) { - returnProcessedImage(processedImage) - } else { - self.call?.reject("Error processing image") + picker.dismiss(animated: true) { + if let processedImage = self.processImage(from: info) { + self.returnProcessedImage(processedImage) + } else { + self.call?.reject("Error processing image") + } } } } @@ -224,7 +298,6 @@ extension CameraPlugin: PHPickerViewControllerDelegate { self?.call?.reject("Error loading image") } } - } } @@ -339,7 +412,6 @@ private extension CameraPlugin { // check if we have a camera if (bridge?.isSimEnvironment ?? false) || !UIImagePickerController.isSourceTypeAvailable(UIImagePickerController.SourceType.camera) { CAPLog.print("⚡️ ", self.pluginId, "-", "Camera not available in simulator") - bridge?.alert("Camera Error", "Camera not available in Simulator") call?.reject("Camera not available while running in Simulator") return } diff --git a/camera/ios/Podfile b/camera/ios/Podfile index 54a00c161..dee40960f 100644 --- a/camera/ios/Podfile +++ b/camera/ios/Podfile @@ -1,4 +1,4 @@ -platform :ios, '12.0' +platform :ios, '13.0' def capacitor_pods # Comment the next line if you're not using Swift and don't want to use dynamic frameworks diff --git a/camera/package.json b/camera/package.json index 4ed3c7a65..ebf2730ff 100644 --- a/camera/package.json +++ b/camera/package.json @@ -1,6 +1,6 @@ { "name": "@capacitor/camera", - "version": "1.2.4", + "version": "4.1.4", "description": "The Camera API provides the ability to take a photo with the camera or choose an existing one from the photo album.", "main": "dist/plugin.cjs.js", "module": "dist/esm/index.js", @@ -29,7 +29,7 @@ ], "scripts": { "verify": "npm run verify:ios && npm run verify:android && npm run verify:web", - "verify:ios": "cd ios && pod install && xcodebuild -workspace Plugin.xcworkspace -scheme Plugin && cd ..", + "verify:ios": "cd ios && pod install && xcodebuild -workspace Plugin.xcworkspace -scheme Plugin -destination generic/platform=iOS && cd ..", "verify:android": "cd android && ./gradlew clean build test && cd ..", "verify:web": "npm run build", "lint": "npm run eslint && npm run prettier -- --check && npm run swiftlint -- lint", @@ -45,10 +45,10 @@ "publish:cocoapod": "pod trunk push ./CapacitorCamera.podspec --allow-warnings" }, "devDependencies": { - "@capacitor/android": "^3.0.0", - "@capacitor/core": "^3.0.0", - "@capacitor/docgen": "0.0.18", - "@capacitor/ios": "^3.0.0", + "@capacitor/android": "^4.0.0", + "@capacitor/core": "^4.0.0", + "@capacitor/docgen": "0.2.0", + "@capacitor/ios": "^4.0.0", "@ionic/eslint-config": "^0.3.0", "@ionic/prettier-config": "~1.0.1", "@ionic/swiftlint-config": "^1.1.2", @@ -61,7 +61,7 @@ "typescript": "~4.1.5" }, "peerDependencies": { - "@capacitor/core": "^3.0.0" + "@capacitor/core": "^4.0.0" }, "prettier": "@ionic/prettier-config", "swiftlint": "@ionic/swiftlint-config", diff --git a/camera/src/definitions.ts b/camera/src/definitions.ts index 02b0d3b7f..be10deca8 100644 --- a/camera/src/definitions.ts +++ b/camera/src/definitions.ts @@ -30,6 +30,21 @@ export interface CameraPlugin { */ pickImages(options: GalleryImageOptions): Promise; + /** + * iOS 14+ Only: Allows the user to update their limited photo library selection. + * On iOS 15+ returns all the limited photos after the picker dismissal. + * On iOS 14 or if the user gave full access to the photos it returns an empty array. + * + * @since 4.1.0 + */ + pickLimitedLibraryPhotos(): Promise; + /** + * iOS 14+ Only: Return an array of photos selected from the limited photo library. + * + * @since 4.1.0 + */ + getLimitedLibraryPhotos(): Promise; + /** * Check camera and photo album permissions * @@ -76,25 +91,17 @@ export interface ImageOptions { */ saveToGallery?: boolean; /** - * The width of the saved image + * The desired maximum width of the saved image. The aspect ratio is respected. * * @since 1.0.0 */ width?: number; /** - * The height of the saved image + * The desired maximum height of the saved image. The aspect ratio is respected. * * @since 1.0.0 */ height?: number; - /** - * This setting has no effect. - * Picture resizing always preserve aspect ratio. - * - * @deprecated will be removed in next major version. - * @since 1.0.0 - */ - preserveAspectRatio?: boolean; /** * Whether to automatically rotate the image "up" to correct for orientation * in portrait mode @@ -132,7 +139,7 @@ export interface ImageOptions { * default is to use PWA Elements if installed and fall back to file input. * To always use file input, set this to `true`. * - * Learn more about PWA Elements: https://capacitorjs.com/docs/pwa-elements + * Learn more about PWA Elements: https://capacitorjs.com/docs/web/pwa-elements * * @since 1.0.0 */ @@ -190,7 +197,7 @@ export interface Photo { dataUrl?: string; /** * If using CameraResultType.Uri, the path will contain a full, - * platform-specific file URL that can be read later using the Filsystem API. + * platform-specific file URL that can be read later using the Filesystem API. * * @since 1.0.0 */ @@ -240,7 +247,7 @@ export interface GalleryPhotos { export interface GalleryPhoto { /** - * Full, platform-specific file URL that can be read later using the Filsystem API. + * Full, platform-specific file URL that can be read later using the Filesystem API. * * @since 1.2.0 */ @@ -276,13 +283,13 @@ export interface GalleryImageOptions { */ quality?: number; /** - * The width of the saved image + * The desired maximum width of the saved image. The aspect ratio is respected. * * @since 1.2.0 */ width?: number; /** - * The height of the saved image + * The desired maximum height of the saved image. The aspect ratio is respected. * * @since 1.2.0 */ @@ -323,7 +330,7 @@ export enum CameraSource { */ Camera = 'CAMERA', /** - * Pick an existing photo fron the gallery or photo album. + * Pick an existing photo from the gallery or photo album. */ Photos = 'PHOTOS', } diff --git a/camera/src/web.ts b/camera/src/web.ts index 9c6293056..f1fa00e01 100644 --- a/camera/src/web.ts +++ b/camera/src/web.ts @@ -82,7 +82,7 @@ export class CameraWeb extends WebPlugin implements CameraPlugin { } } else { console.error( - `Unable to load PWA Element 'pwa-camera-modal'. See the docs: https://capacitorjs.com/docs/pwa-elements.`, + `Unable to load PWA Element 'pwa-camera-modal'. See the docs: https://capacitorjs.com/docs/web/pwa-elements.`, ); this.fileInputExperience(options, resolve); } @@ -268,6 +268,14 @@ export class CameraWeb extends WebPlugin implements CameraPlugin { async requestPermissions(): Promise { throw this.unimplemented('Not implemented on web.'); } + + async pickLimitedLibraryPhotos(): Promise { + throw this.unavailable('Not implemented on web.'); + } + + async getLimitedLibraryPhotos(): Promise { + throw this.unavailable('Not implemented on web.'); + } } const Camera = new CameraWeb(); diff --git a/clipboard/CHANGELOG.md b/clipboard/CHANGELOG.md index 934c4e414..a787ba8db 100644 --- a/clipboard/CHANGELOG.md +++ b/clipboard/CHANGELOG.md @@ -3,6 +3,94 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.1.0](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/clipboard@1.0.8...@capacitor/clipboard@4.1.0) (2022-11-16) + + + +## 4.0.1 (2022-07-28) + + + +# 4.0.0 (2022-07-27) + + + +# 4.0.0-beta.2 (2022-07-08) + + + +# 4.0.0-beta.0 (2022-06-27) + + +### Features + +* set targetSDK default value to 31 ([#824](https://github.com/ionic-team/capacitor-plugins/issues/824)) ([3ee10de](https://github.com/ionic-team/capacitor-plugins/commit/3ee10de98067984c1a4e75295d001c5a895c47f4)) +* set targetSDK default value to 32 ([#970](https://github.com/ionic-team/capacitor-plugins/issues/970)) ([fa70d96](https://github.com/ionic-team/capacitor-plugins/commit/fa70d96f141af751aae53ceb5642c46b204f5958)) +* Upgrade gradle to 7.4 ([#826](https://github.com/ionic-team/capacitor-plugins/issues/826)) ([5db0906](https://github.com/ionic-team/capacitor-plugins/commit/5db0906f6264287c4f8e69dbaecf19d4d387824b)) +* Use java 11 ([#910](https://github.com/ionic-team/capacitor-plugins/issues/910)) ([5acb2a2](https://github.com/ionic-team/capacitor-plugins/commit/5acb2a288a413492b163e4e97da46a085d9e4be0)) + + + + + +## [4.0.1](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0...4.0.1) (2022-07-28) + +**Note:** Version bump only for package @capacitor/clipboard + + + + + +# [4.0.0](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0-beta.2...4.0.0) (2022-07-27) + +**Note:** Version bump only for package @capacitor/clipboard + + + + + +# [4.0.0-beta.2](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0-beta.0...4.0.0-beta.2) (2022-07-08) + +**Note:** Version bump only for package @capacitor/clipboard + + + + + +# 4.0.0-beta.0 (2022-06-27) + + +### Bug Fixes + +* add es2017 lib to tsconfig ([#180](https://github.com/ionic-team/capacitor-plugins/issues/180)) ([2c3776c](https://github.com/ionic-team/capacitor-plugins/commit/2c3776c38ca025c5ee965dec10ccf1cdb6c02e2f)) +* correct addListeners links ([#655](https://github.com/ionic-team/capacitor-plugins/issues/655)) ([f9871e7](https://github.com/ionic-team/capacitor-plugins/commit/f9871e7bd53478addb21155e148829f550c0e457)) +* inline source code in esm map files ([#760](https://github.com/ionic-team/capacitor-plugins/issues/760)) ([a960489](https://github.com/ionic-team/capacitor-plugins/commit/a960489a19db0182b90d187a50deff9dfbe51038)) +* remove postpublish scripts ([#656](https://github.com/ionic-team/capacitor-plugins/issues/656)) ([ed6ac49](https://github.com/ionic-team/capacitor-plugins/commit/ed6ac499ebf4a47525071ccbfc36c27503e11f60)) +* **clipboard:** prevent NotAllowedError on first method invocation ([#342](https://github.com/ionic-team/capacitor-plugins/issues/342)) ([ab8eecb](https://github.com/ionic-team/capacitor-plugins/commit/ab8eecb873999d6f4321218c60b45335998189eb)) +* support deprecated types from Capacitor 2 ([#139](https://github.com/ionic-team/capacitor-plugins/issues/139)) ([2d7127a](https://github.com/ionic-team/capacitor-plugins/commit/2d7127a488e26f0287951921a6db47c49d817336)) + + +### Features + +* add commonjs output format ([#179](https://github.com/ionic-team/capacitor-plugins/issues/179)) ([8e9e098](https://github.com/ionic-team/capacitor-plugins/commit/8e9e09862064b3f6771d7facbc4008e995d9b463)) +* Clipboard plugin ([fd89544](https://github.com/ionic-team/capacitor-plugins/commit/fd895448fd7c6d105716b31eb4fe42762328513a)) +* set targetSDK default value to 31 ([#824](https://github.com/ionic-team/capacitor-plugins/issues/824)) ([3ee10de](https://github.com/ionic-team/capacitor-plugins/commit/3ee10de98067984c1a4e75295d001c5a895c47f4)) +* set targetSDK default value to 32 ([#970](https://github.com/ionic-team/capacitor-plugins/issues/970)) ([fa70d96](https://github.com/ionic-team/capacitor-plugins/commit/fa70d96f141af751aae53ceb5642c46b204f5958)) +* Upgrade gradle to 7.4 ([#826](https://github.com/ionic-team/capacitor-plugins/issues/826)) ([5db0906](https://github.com/ionic-team/capacitor-plugins/commit/5db0906f6264287c4f8e69dbaecf19d4d387824b)) +* Use java 11 ([#910](https://github.com/ionic-team/capacitor-plugins/issues/910)) ([5acb2a2](https://github.com/ionic-team/capacitor-plugins/commit/5acb2a288a413492b163e4e97da46a085d9e4be0)) + + + + + +## [1.0.8](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/clipboard@1.0.7...@capacitor/clipboard@1.0.8) (2022-03-03) + +**Note:** Version bump only for package @capacitor/clipboard + + + + + ## [1.0.7](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/clipboard@1.0.6...@capacitor/clipboard@1.0.7) (2022-01-19) diff --git a/clipboard/CapacitorClipboard.podspec b/clipboard/CapacitorClipboard.podspec index 8f3602214..13f5be54a 100644 --- a/clipboard/CapacitorClipboard.podspec +++ b/clipboard/CapacitorClipboard.podspec @@ -11,7 +11,7 @@ Pod::Spec.new do |s| s.author = package['author'] s.source = { :git => 'https://github.com/ionic-team/capacitor-plugins.git', :tag => package['name'] + '@' + package['version'] } s.source_files = 'ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}', 'clipboard/ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}' - s.ios.deployment_target = '12.0' + s.ios.deployment_target = '13.0' s.dependency 'Capacitor' s.swift_version = '5.1' end diff --git a/clipboard/README.md b/clipboard/README.md index 216a678c6..136ffda24 100644 --- a/clipboard/README.md +++ b/clipboard/README.md @@ -23,7 +23,7 @@ const writeToClipboard = async () => { const checkClipboard = async () => { const { type, value } = await Clipboard.read(); - alert(`Got ${type} from clipboard: ${value}`); + console.log(`Got ${type} from clipboard: ${value}`); }; ``` diff --git a/clipboard/android/build.gradle b/clipboard/android/build.gradle index 56ee0b28b..43252f49c 100644 --- a/clipboard/android/build.gradle +++ b/clipboard/android/build.gradle @@ -1,27 +1,39 @@ ext { - junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.1' - androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.2.0' - androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.1.2' - androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.3.0' + capacitorVersion = System.getenv('CAPACITOR_VERSION') + junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.2' + androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.4.2' + androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.1.3' + androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.4.0' } buildscript { repositories { google() mavenCentral() + maven { + url "https://plugins.gradle.org/m2/" + } } dependencies { - classpath 'com.android.tools.build:gradle:4.2.1' + classpath 'com.android.tools.build:gradle:7.2.1' + if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + classpath 'io.github.gradle-nexus:publish-plugin:1.1.0' + } } } apply plugin: 'com.android.library' +if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + apply plugin: 'io.github.gradle-nexus.publish-plugin' + apply from: file('../../scripts/android/publish-root.gradle') + apply from: file('../../scripts/android/publish-module.gradle') +} android { - compileSdkVersion project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 30 + compileSdkVersion project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 32 defaultConfig { - minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 21 - targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 30 + minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 22 + targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 32 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" @@ -36,21 +48,26 @@ android { abortOnError false } compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility JavaVersion.VERSION_11 + targetCompatibility JavaVersion.VERSION_11 } } repositories { google() mavenCentral() - jcenter() } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation project(':capacitor-android') + + if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + implementation "com.capacitorjs:core:$capacitorVersion" + } else { + implementation project(':capacitor-android') + } + implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion" testImplementation "junit:junit:$junitVersion" androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion" diff --git a/clipboard/android/gradle/wrapper/gradle-wrapper.jar b/clipboard/android/gradle/wrapper/gradle-wrapper.jar index e708b1c02..41d9927a4 100644 Binary files a/clipboard/android/gradle/wrapper/gradle-wrapper.jar and b/clipboard/android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/clipboard/android/gradle/wrapper/gradle-wrapper.properties b/clipboard/android/gradle/wrapper/gradle-wrapper.properties index 3c4101c3e..92f06b50f 100644 --- a/clipboard/android/gradle/wrapper/gradle-wrapper.properties +++ b/clipboard/android/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/clipboard/android/gradlew b/clipboard/android/gradlew index 4f906e0c8..1b6c78733 100755 --- a/clipboard/android/gradlew +++ b/clipboard/android/gradlew @@ -1,7 +1,7 @@ -#!/usr/bin/env sh +#!/bin/sh # -# Copyright 2015 the original author or authors. +# Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,67 +17,101 @@ # ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` +APP_BASE_NAME=${0##*/} # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar @@ -87,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -98,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" + JAVACMD=java which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the @@ -106,80 +140,95 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=`expr $i + 1` + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" diff --git a/clipboard/ios/Plugin.xcodeproj/project.pbxproj b/clipboard/ios/Plugin.xcodeproj/project.pbxproj index 8e4c1753c..0702e3921 100644 --- a/clipboard/ios/Plugin.xcodeproj/project.pbxproj +++ b/clipboard/ios/Plugin.xcodeproj/project.pbxproj @@ -379,7 +379,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -433,7 +433,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; @@ -456,12 +456,13 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Plugin/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks $(FRAMEWORK_SEARCH_PATHS)\n$(FRAMEWORK_SEARCH_PATHS)\n$(FRAMEWORK_SEARCH_PATHS)"; ONLY_ACTIVE_ARCH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.getcapacitor.Plugin; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; + SUPPORTS_MACCATALYST = NO; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -481,12 +482,13 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Plugin/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks $(FRAMEWORK_SEARCH_PATHS)"; ONLY_ACTIVE_ARCH = NO; PRODUCT_BUNDLE_IDENTIFIER = com.getcapacitor.Plugin; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; + SUPPORTS_MACCATALYST = NO; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; diff --git a/clipboard/ios/Podfile b/clipboard/ios/Podfile index 54a00c161..dee40960f 100644 --- a/clipboard/ios/Podfile +++ b/clipboard/ios/Podfile @@ -1,4 +1,4 @@ -platform :ios, '12.0' +platform :ios, '13.0' def capacitor_pods # Comment the next line if you're not using Swift and don't want to use dynamic frameworks diff --git a/clipboard/package.json b/clipboard/package.json index 7f8717ed2..184b5c0c5 100644 --- a/clipboard/package.json +++ b/clipboard/package.json @@ -1,6 +1,6 @@ { "name": "@capacitor/clipboard", - "version": "1.0.7", + "version": "4.1.0", "description": "The Clipboard API enables copy and pasting to/from the system clipboard.", "main": "dist/plugin.cjs.js", "module": "dist/esm/index.js", @@ -29,7 +29,7 @@ ], "scripts": { "verify": "npm run verify:ios && npm run verify:android && npm run verify:web", - "verify:ios": "cd ios && pod install && xcodebuild -workspace Plugin.xcworkspace -scheme Plugin && cd ..", + "verify:ios": "cd ios && pod install && xcodebuild -workspace Plugin.xcworkspace -scheme Plugin -destination generic/platform=iOS && cd ..", "verify:android": "cd android && ./gradlew clean build test && cd ..", "verify:web": "npm run build", "lint": "npm run eslint && npm run prettier -- --check && npm run swiftlint -- lint", @@ -45,10 +45,10 @@ "publish:cocoapod": "pod trunk push ./CapacitorClipboard.podspec --allow-warnings" }, "devDependencies": { - "@capacitor/android": "^3.0.0", - "@capacitor/core": "^3.0.0", - "@capacitor/docgen": "0.0.18", - "@capacitor/ios": "^3.0.0", + "@capacitor/android": "^4.0.0", + "@capacitor/core": "^4.0.0", + "@capacitor/docgen": "0.2.0", + "@capacitor/ios": "^4.0.0", "@ionic/eslint-config": "^0.3.0", "@ionic/prettier-config": "~1.0.1", "@ionic/swiftlint-config": "^1.1.2", @@ -61,7 +61,7 @@ "typescript": "~4.1.5" }, "peerDependencies": { - "@capacitor/core": "^3.0.0" + "@capacitor/core": "^4.0.0" }, "prettier": "@ionic/prettier-config", "swiftlint": "@ionic/swiftlint-config", diff --git a/device/CHANGELOG.md b/device/CHANGELOG.md index 625603ea6..1b02dafd1 100644 --- a/device/CHANGELOG.md +++ b/device/CHANGELOG.md @@ -3,6 +3,102 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.1.0](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/device@1.1.2...@capacitor/device@4.1.0) (2022-11-16) + + + +## 4.0.1 (2022-07-28) + + + +# 4.0.0 (2022-07-27) + + + +# 4.0.0-beta.2 (2022-07-08) + + + +# 4.0.0-beta.0 (2022-06-27) + + +### Bug Fixes + +* **device:** handle case of no localStorage for getId ([#1059](https://github.com/ionic-team/capacitor-plugins/issues/1059)) ([5f77a7d](https://github.com/ionic-team/capacitor-plugins/commit/5f77a7da48fc7f0ce5250e7cba621731ac6b210a)) +* **device:** return short language code in web ([#893](https://github.com/ionic-team/capacitor-plugins/issues/893)) ([07f0887](https://github.com/ionic-team/capacitor-plugins/commit/07f0887f4f0c9a883e55fb24b506a47dc61f13f7)) + + +### Features + +* set targetSDK default value to 32 ([#970](https://github.com/ionic-team/capacitor-plugins/issues/970)) ([fa70d96](https://github.com/ionic-team/capacitor-plugins/commit/fa70d96f141af751aae53ceb5642c46b204f5958)) +* **device:** Add getLanguageTag function ([#939](https://github.com/ionic-team/capacitor-plugins/issues/939)) ([d268e4a](https://github.com/ionic-team/capacitor-plugins/commit/d268e4a3d5a0a0279bae6a971b0d6e65481f1899)) +* **device:** model now reflects exact model on iOS ([#929](https://github.com/ionic-team/capacitor-plugins/issues/929)) ([302d813](https://github.com/ionic-team/capacitor-plugins/commit/302d813991a755c89fbf57a6f5b2c3a2e1cd79aa)) +* set targetSDK default value to 31 ([#824](https://github.com/ionic-team/capacitor-plugins/issues/824)) ([3ee10de](https://github.com/ionic-team/capacitor-plugins/commit/3ee10de98067984c1a4e75295d001c5a895c47f4)) +* Upgrade gradle to 7.4 ([#826](https://github.com/ionic-team/capacitor-plugins/issues/826)) ([5db0906](https://github.com/ionic-team/capacitor-plugins/commit/5db0906f6264287c4f8e69dbaecf19d4d387824b)) +* Use java 11 ([#910](https://github.com/ionic-team/capacitor-plugins/issues/910)) ([5acb2a2](https://github.com/ionic-team/capacitor-plugins/commit/5acb2a288a413492b163e4e97da46a085d9e4be0)) + + + + + +## [4.0.1](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0...4.0.1) (2022-07-28) + +**Note:** Version bump only for package @capacitor/device + + + + + +# [4.0.0](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0-beta.2...4.0.0) (2022-07-27) + +**Note:** Version bump only for package @capacitor/device + + + + + +# [4.0.0-beta.2](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0-beta.0...4.0.0-beta.2) (2022-07-08) + +**Note:** Version bump only for package @capacitor/device + + + + + +# 4.0.0-beta.0 (2022-06-27) + + +### Bug Fixes + +* **device:** handle case of no localStorage for getId ([#1059](https://github.com/ionic-team/capacitor-plugins/issues/1059)) ([5f77a7d](https://github.com/ionic-team/capacitor-plugins/commit/5f77a7da48fc7f0ce5250e7cba621731ac6b210a)) +* **device:** return short language code in web ([#893](https://github.com/ionic-team/capacitor-plugins/issues/893)) ([07f0887](https://github.com/ionic-team/capacitor-plugins/commit/07f0887f4f0c9a883e55fb24b506a47dc61f13f7)) +* add es2017 lib to tsconfig ([#180](https://github.com/ionic-team/capacitor-plugins/issues/180)) ([2c3776c](https://github.com/ionic-team/capacitor-plugins/commit/2c3776c38ca025c5ee965dec10ccf1cdb6c02e2f)) +* correct addListeners links ([#655](https://github.com/ionic-team/capacitor-plugins/issues/655)) ([f9871e7](https://github.com/ionic-team/capacitor-plugins/commit/f9871e7bd53478addb21155e148829f550c0e457)) +* inline source code in esm map files ([#760](https://github.com/ionic-team/capacitor-plugins/issues/760)) ([a960489](https://github.com/ionic-team/capacitor-plugins/commit/a960489a19db0182b90d187a50deff9dfbe51038)) +* **device:** isVirtual is false on M1 simulators ([#726](https://github.com/ionic-team/capacitor-plugins/issues/726)) ([5377586](https://github.com/ionic-team/capacitor-plugins/commit/53775863df624531e8ffa4b18852b408e1bd2cbd)) +* remove postpublish scripts ([#656](https://github.com/ionic-team/capacitor-plugins/issues/656)) ([ed6ac49](https://github.com/ionic-team/capacitor-plugins/commit/ed6ac499ebf4a47525071ccbfc36c27503e11f60)) +* support deprecated types from Capacitor 2 ([#139](https://github.com/ionic-team/capacitor-plugins/issues/139)) ([2d7127a](https://github.com/ionic-team/capacitor-plugins/commit/2d7127a488e26f0287951921a6db47c49d817336)) + + +### Features + +* set targetSDK default value to 32 ([#970](https://github.com/ionic-team/capacitor-plugins/issues/970)) ([fa70d96](https://github.com/ionic-team/capacitor-plugins/commit/fa70d96f141af751aae53ceb5642c46b204f5958)) +* **device:** Add getLanguageTag function ([#939](https://github.com/ionic-team/capacitor-plugins/issues/939)) ([d268e4a](https://github.com/ionic-team/capacitor-plugins/commit/d268e4a3d5a0a0279bae6a971b0d6e65481f1899)) +* **device:** model now reflects exact model on iOS ([#929](https://github.com/ionic-team/capacitor-plugins/issues/929)) ([302d813](https://github.com/ionic-team/capacitor-plugins/commit/302d813991a755c89fbf57a6f5b2c3a2e1cd79aa)) +* add commonjs output format ([#179](https://github.com/ionic-team/capacitor-plugins/issues/179)) ([8e9e098](https://github.com/ionic-team/capacitor-plugins/commit/8e9e09862064b3f6771d7facbc4008e995d9b463)) +* Device plugin ([#47](https://github.com/ionic-team/capacitor-plugins/issues/47)) ([9870e30](https://github.com/ionic-team/capacitor-plugins/commit/9870e3006094062d7b10df6ab59aa9da35f6c34b)) +* set targetSDK default value to 31 ([#824](https://github.com/ionic-team/capacitor-plugins/issues/824)) ([3ee10de](https://github.com/ionic-team/capacitor-plugins/commit/3ee10de98067984c1a4e75295d001c5a895c47f4)) +* Upgrade gradle to 7.4 ([#826](https://github.com/ionic-team/capacitor-plugins/issues/826)) ([5db0906](https://github.com/ionic-team/capacitor-plugins/commit/5db0906f6264287c4f8e69dbaecf19d4d387824b)) +* Use java 11 ([#910](https://github.com/ionic-team/capacitor-plugins/issues/910)) ([5acb2a2](https://github.com/ionic-team/capacitor-plugins/commit/5acb2a288a413492b163e4e97da46a085d9e4be0)) +* **device:** add browser/webview version to getInfo() ([#109](https://github.com/ionic-team/capacitor-plugins/issues/109)) ([48c49c1](https://github.com/ionic-team/capacitor-plugins/commit/48c49c1cd1ffc86b40b02dd3778c0a3079cdc00c)) +* **device:** Add deviceInfo.name implementation for Android ([#88](https://github.com/ionic-team/capacitor-plugins/issues/88)) ([bdc3b38](https://github.com/ionic-team/capacitor-plugins/commit/bdc3b38f70ecc7898e2bb23c1cceaea8903f26d9)) +* **device:** Add getId function ([#370](https://github.com/ionic-team/capacitor-plugins/issues/370)) ([96664c6](https://github.com/ionic-team/capacitor-plugins/commit/96664c630140112af7e50569b98b00f774480949)) +* **device:** Add realDiskTotal and realDiskFree properties ([#694](https://github.com/ionic-team/capacitor-plugins/issues/694)) ([3f67643](https://github.com/ionic-team/capacitor-plugins/commit/3f67643edf4cfd90a84d4606c4c6349b72531b92)) + + + + + ## [1.1.2](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/device@1.1.1...@capacitor/device@1.1.2) (2022-01-19) diff --git a/device/CapacitorDevice.podspec b/device/CapacitorDevice.podspec index 79f70bed8..9a7f65ee7 100644 --- a/device/CapacitorDevice.podspec +++ b/device/CapacitorDevice.podspec @@ -11,7 +11,7 @@ Pod::Spec.new do |s| s.author = package['author'] s.source = { :git => 'https://github.com/ionic-team/capacitor-plugins.git', :tag => package['name'] + '@' + package['version'] } s.source_files = 'ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}', 'device/ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}' - s.ios.deployment_target = '12.0' + s.ios.deployment_target = '13.0' s.dependency 'Capacitor' s.swift_version = '5.1' end diff --git a/device/README.md b/device/README.md index 2b917ecae..ede7bdb09 100644 --- a/device/README.md +++ b/device/README.md @@ -35,6 +35,7 @@ const logBatteryInfo = async () => { * [`getInfo()`](#getinfo) * [`getBatteryInfo()`](#getbatteryinfo) * [`getLanguageCode()`](#getlanguagecode) +* [`getLanguageTag()`](#getlanguagetag) * [Interfaces](#interfaces) * [Type Aliases](#type-aliases) @@ -103,33 +104,48 @@ Get the device's current language locale code. -------------------- +### getLanguageTag() + +```typescript +getLanguageTag() => Promise +``` + +Get the device's current language locale tag. + +**Returns:** Promise<LanguageTag> + +**Since:** 4.0.0 + +-------------------- + + ### Interfaces #### DeviceId -| Prop | Type | Description | Since | -| ---------- | ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----- | -| **`uuid`** | string | The UUID of the device as available to the app. This identifier may change on modern mobile platforms that only allow per-app install UUIDs. On web, a random identifier is generated and stored on localStorage for subsequent calls. | 1.0.0 | +| Prop | Type | Description | Since | +| ---------- | ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----- | +| **`uuid`** | string | The UUID of the device as available to the app. This identifier may change on modern mobile platforms that only allow per-app install UUIDs. On web, a random identifier is generated and stored on localStorage for subsequent calls. If localStorage is not available a new random identifier will be generated on every call. | 1.0.0 | #### DeviceInfo -| Prop | Type | Description | Since | -| --------------------- | ----------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----- | -| **`name`** | string | The name of the device. For example, "John's iPhone". This is only supported on iOS and Android 7.1 or above. | 1.0.0 | -| **`model`** | string | The device model. For example, "iPhone". | 1.0.0 | -| **`platform`** | 'ios' \| 'android' \| 'web' | The device platform (lowercase). | 1.0.0 | -| **`operatingSystem`** | OperatingSystem | The operating system of the device. | 1.0.0 | -| **`osVersion`** | string | The version of the device OS. | 1.0.0 | -| **`manufacturer`** | string | The manufacturer of the device. | 1.0.0 | -| **`isVirtual`** | boolean | Whether the app is running in a simulator/emulator. | 1.0.0 | -| **`memUsed`** | number | Approximate memory used by the current app, in bytes. Divide by 1048576 to get the number of MBs used. | 1.0.0 | -| **`diskFree`** | number | How much free disk space is available on the the normal data storage path for the os, in bytes. On Android it returns the free disk space on the "system" partition holding the core Android OS. On iOS this value is not accurate. | 1.0.0 | -| **`diskTotal`** | number | The total size of the normal data storage path for the OS, in bytes. On Android it returns the disk space on the "system" partition holding the core Android OS. | 1.0.0 | -| **`realDiskFree`** | number | How much free disk space is available on the the normal data storage, in bytes. | 1.1.0 | -| **`realDiskTotal`** | number | The total size of the normal data storage path, in bytes. | 1.1.0 | -| **`webViewVersion`** | string | The web view browser version | 1.0.0 | +| Prop | Type | Description | Since | +| --------------------- | ----------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----- | +| **`name`** | string | The name of the device. For example, "John's iPhone". This is only supported on iOS and Android 7.1 or above. | 1.0.0 | +| **`model`** | string | The device model. For example, "iPhone13,4". | 1.0.0 | +| **`platform`** | 'ios' \| 'android' \| 'web' | The device platform (lowercase). | 1.0.0 | +| **`operatingSystem`** | OperatingSystem | The operating system of the device. | 1.0.0 | +| **`osVersion`** | string | The version of the device OS. | 1.0.0 | +| **`manufacturer`** | string | The manufacturer of the device. | 1.0.0 | +| **`isVirtual`** | boolean | Whether the app is running in a simulator/emulator. | 1.0.0 | +| **`memUsed`** | number | Approximate memory used by the current app, in bytes. Divide by 1048576 to get the number of MBs used. | 1.0.0 | +| **`diskFree`** | number | How much free disk space is available on the normal data storage path for the os, in bytes. On Android it returns the free disk space on the "system" partition holding the core Android OS. On iOS this value is not accurate. | 1.0.0 | +| **`diskTotal`** | number | The total size of the normal data storage path for the OS, in bytes. On Android it returns the disk space on the "system" partition holding the core Android OS. | 1.0.0 | +| **`realDiskFree`** | number | How much free disk space is available on the normal data storage, in bytes. | 1.1.0 | +| **`realDiskTotal`** | number | The total size of the normal data storage path, in bytes. | 1.1.0 | +| **`webViewVersion`** | string | The web view browser version | 1.0.0 | #### BatteryInfo @@ -147,6 +163,13 @@ Get the device's current language locale code. | **`value`** | string | Two character language code. | 1.0.0 | +#### LanguageTag + +| Prop | Type | Description | Since | +| ----------- | ------------------- | ----------------------------------------------- | ----- | +| **`value`** | string | Returns a well-formed IETF BCP 47 language tag. | 4.0.0 | + + ### Type Aliases diff --git a/device/android/build.gradle b/device/android/build.gradle index 56ee0b28b..43252f49c 100644 --- a/device/android/build.gradle +++ b/device/android/build.gradle @@ -1,27 +1,39 @@ ext { - junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.1' - androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.2.0' - androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.1.2' - androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.3.0' + capacitorVersion = System.getenv('CAPACITOR_VERSION') + junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.2' + androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.4.2' + androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.1.3' + androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.4.0' } buildscript { repositories { google() mavenCentral() + maven { + url "https://plugins.gradle.org/m2/" + } } dependencies { - classpath 'com.android.tools.build:gradle:4.2.1' + classpath 'com.android.tools.build:gradle:7.2.1' + if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + classpath 'io.github.gradle-nexus:publish-plugin:1.1.0' + } } } apply plugin: 'com.android.library' +if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + apply plugin: 'io.github.gradle-nexus.publish-plugin' + apply from: file('../../scripts/android/publish-root.gradle') + apply from: file('../../scripts/android/publish-module.gradle') +} android { - compileSdkVersion project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 30 + compileSdkVersion project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 32 defaultConfig { - minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 21 - targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 30 + minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 22 + targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 32 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" @@ -36,21 +48,26 @@ android { abortOnError false } compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility JavaVersion.VERSION_11 + targetCompatibility JavaVersion.VERSION_11 } } repositories { google() mavenCentral() - jcenter() } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation project(':capacitor-android') + + if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + implementation "com.capacitorjs:core:$capacitorVersion" + } else { + implementation project(':capacitor-android') + } + implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion" testImplementation "junit:junit:$junitVersion" androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion" diff --git a/device/android/gradle/wrapper/gradle-wrapper.jar b/device/android/gradle/wrapper/gradle-wrapper.jar index e708b1c02..41d9927a4 100644 Binary files a/device/android/gradle/wrapper/gradle-wrapper.jar and b/device/android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/device/android/gradle/wrapper/gradle-wrapper.properties b/device/android/gradle/wrapper/gradle-wrapper.properties index 3c4101c3e..92f06b50f 100644 --- a/device/android/gradle/wrapper/gradle-wrapper.properties +++ b/device/android/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/device/android/gradlew b/device/android/gradlew index 4f906e0c8..1b6c78733 100755 --- a/device/android/gradlew +++ b/device/android/gradlew @@ -1,7 +1,7 @@ -#!/usr/bin/env sh +#!/bin/sh # -# Copyright 2015 the original author or authors. +# Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,67 +17,101 @@ # ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` +APP_BASE_NAME=${0##*/} # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar @@ -87,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -98,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" + JAVACMD=java which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the @@ -106,80 +140,95 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=`expr $i + 1` + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" diff --git a/device/android/src/main/java/com/capacitorjs/plugins/device/DevicePlugin.java b/device/android/src/main/java/com/capacitorjs/plugins/device/DevicePlugin.java index 731c515c4..342835399 100644 --- a/device/android/src/main/java/com/capacitorjs/plugins/device/DevicePlugin.java +++ b/device/android/src/main/java/com/capacitorjs/plugins/device/DevicePlugin.java @@ -63,4 +63,11 @@ public void getLanguageCode(PluginCall call) { ret.put("value", Locale.getDefault().getLanguage()); call.resolve(ret); } + + @PluginMethod + public void getLanguageTag(PluginCall call) { + JSObject ret = new JSObject(); + ret.put("value", Locale.getDefault().toLanguageTag()); + call.resolve(ret); + } } diff --git a/device/ios/Plugin.xcodeproj/project.pbxproj b/device/ios/Plugin.xcodeproj/project.pbxproj index 949f91296..195f83143 100644 --- a/device/ios/Plugin.xcodeproj/project.pbxproj +++ b/device/ios/Plugin.xcodeproj/project.pbxproj @@ -386,7 +386,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -446,7 +446,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; @@ -469,12 +469,13 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Plugin/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks $(FRAMEWORK_SEARCH_PATHS)\n$(FRAMEWORK_SEARCH_PATHS)\n$(FRAMEWORK_SEARCH_PATHS)"; ONLY_ACTIVE_ARCH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.getcapacitor.Plugin; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; + SUPPORTS_MACCATALYST = NO; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -494,12 +495,13 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Plugin/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks $(FRAMEWORK_SEARCH_PATHS)"; ONLY_ACTIVE_ARCH = NO; PRODUCT_BUNDLE_IDENTIFIER = com.getcapacitor.Plugin; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; + SUPPORTS_MACCATALYST = NO; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; diff --git a/device/ios/Plugin/Device.swift b/device/ios/Plugin/Device.swift index ce39854a1..1922eb7e6 100644 --- a/device/ios/Plugin/Device.swift +++ b/device/ios/Plugin/Device.swift @@ -65,4 +65,16 @@ import Foundation public func getLanguageCode() -> String { return String(Locale.preferredLanguages[0].prefix(2)) } + + public func getLanguageTag() -> String { + return String(Locale.preferredLanguages[0]) + } + + public func getModelName() -> String { + var size = 0 + sysctlbyname("hw.machine", nil, &size, nil, 0) + var machine = [CChar](repeating: 0, count: size) + sysctlbyname("hw.machine", &machine, &size, nil, 0) + return String(cString: machine) + } } diff --git a/device/ios/Plugin/DevicePlugin.m b/device/ios/Plugin/DevicePlugin.m index 8ae49ea15..0c25f907a 100644 --- a/device/ios/Plugin/DevicePlugin.m +++ b/device/ios/Plugin/DevicePlugin.m @@ -8,4 +8,5 @@ CAP_PLUGIN_METHOD(getInfo, CAPPluginReturnPromise); CAP_PLUGIN_METHOD(getBatteryInfo, CAPPluginReturnPromise); CAP_PLUGIN_METHOD(getLanguageCode, CAPPluginReturnPromise); + CAP_PLUGIN_METHOD(getLanguageTag, CAPPluginReturnPromise); ) diff --git a/device/ios/Plugin/DevicePlugin.swift b/device/ios/Plugin/DevicePlugin.swift index 00ccf2eca..b5dc66905 100644 --- a/device/ios/Plugin/DevicePlugin.swift +++ b/device/ios/Plugin/DevicePlugin.swift @@ -16,8 +16,12 @@ public class DevicePlugin: CAPPlugin { } @objc func getInfo(_ call: CAPPluginCall) { var isSimulator = false + var modelName = "" #if targetEnvironment(simulator) isSimulator = true + modelName = ProcessInfo().environment["SIMULATOR_MODEL_IDENTIFIER"] ?? "Simulator" + #else + modelName = implementation.getModelName() #endif let memUsed = implementation.getMemoryUsage() @@ -32,7 +36,7 @@ public class DevicePlugin: CAPPlugin { "realDiskFree": realDiskFree, "realDiskTotal": diskTotal, "name": UIDevice.current.name, - "model": UIDevice.current.model, + "model": modelName, "operatingSystem": "ios", "osVersion": UIDevice.current.systemVersion, "platform": "ios", @@ -60,4 +64,11 @@ public class DevicePlugin: CAPPlugin { ]) } + @objc func getLanguageTag(_ call: CAPPluginCall) { + let tag = implementation.getLanguageTag() + call.resolve([ + "value": tag + ]) + } + } diff --git a/device/ios/Podfile b/device/ios/Podfile index 54a00c161..dee40960f 100644 --- a/device/ios/Podfile +++ b/device/ios/Podfile @@ -1,4 +1,4 @@ -platform :ios, '12.0' +platform :ios, '13.0' def capacitor_pods # Comment the next line if you're not using Swift and don't want to use dynamic frameworks diff --git a/device/package.json b/device/package.json index 5338c0b0a..1348b3569 100644 --- a/device/package.json +++ b/device/package.json @@ -1,6 +1,6 @@ { "name": "@capacitor/device", - "version": "1.1.2", + "version": "4.1.0", "description": "The Device API exposes internal information about the device, such as the model and operating system version, along with user information such as unique ids.", "main": "dist/plugin.cjs.js", "module": "dist/esm/index.js", @@ -30,7 +30,7 @@ "scripts": { "test": "uvu -r esm -r ts-node/register src/__tests__", "verify": "npm run verify:ios && npm run verify:android && npm run verify:web", - "verify:ios": "cd ios && pod install && xcodebuild -workspace Plugin.xcworkspace -scheme Plugin && cd ..", + "verify:ios": "cd ios && pod install && xcodebuild -workspace Plugin.xcworkspace -scheme Plugin -destination generic/platform=iOS && cd ..", "verify:android": "cd android && ./gradlew clean build test && cd ..", "verify:web": "npm run build && npm test", "lint": "npm run eslint && npm run prettier -- --check && npm run swiftlint -- lint", @@ -46,10 +46,10 @@ "publish:cocoapod": "pod trunk push ./CapacitorDevice.podspec --allow-warnings" }, "devDependencies": { - "@capacitor/android": "^3.0.0", - "@capacitor/core": "^3.0.0", - "@capacitor/docgen": "0.0.18", - "@capacitor/ios": "^3.0.0", + "@capacitor/android": "^4.0.0", + "@capacitor/core": "^4.0.0", + "@capacitor/docgen": "0.2.0", + "@capacitor/ios": "^4.0.0", "@ionic/eslint-config": "^0.3.0", "@ionic/prettier-config": "~1.0.1", "@ionic/swiftlint-config": "^1.1.2", @@ -65,7 +65,7 @@ "uvu": "^0.5.1" }, "peerDependencies": { - "@capacitor/core": "^3.0.0" + "@capacitor/core": "^4.0.0" }, "prettier": "@ionic/prettier-config", "swiftlint": "@ionic/swiftlint-config", diff --git a/device/src/definitions.ts b/device/src/definitions.ts index 6ac726809..093528efb 100644 --- a/device/src/definitions.ts +++ b/device/src/definitions.ts @@ -6,6 +6,7 @@ export interface DeviceId { * on modern mobile platforms that only allow per-app install UUIDs. * * On web, a random identifier is generated and stored on localStorage for subsequent calls. + * If localStorage is not available a new random identifier will be generated on every call. * * @since 1.0.0 */ @@ -23,7 +24,7 @@ export interface DeviceInfo { name?: string; /** - * The device model. For example, "iPhone". + * The device model. For example, "iPhone13,4". * * @since 1.0.0 */ @@ -73,7 +74,7 @@ export interface DeviceInfo { memUsed?: number; /** - * How much free disk space is available on the the normal data storage + * How much free disk space is available on the normal data storage * path for the os, in bytes. * * On Android it returns the free disk space on the "system" @@ -97,7 +98,7 @@ export interface DeviceInfo { diskTotal?: number; /** - * How much free disk space is available on the the normal data storage, in bytes. + * How much free disk space is available on the normal data storage, in bytes. * * @since 1.1.0 */ @@ -143,6 +144,15 @@ export interface GetLanguageCodeResult { value: string; } +export interface LanguageTag { + /** + * Returns a well-formed IETF BCP 47 language tag. + * + * @since 4.0.0 + */ + value: string; +} + export interface DevicePlugin { /** * Return an unique identifier for the device. @@ -171,6 +181,13 @@ export interface DevicePlugin { * @since 1.0.0 */ getLanguageCode(): Promise; + + /** + * Get the device's current language locale tag. + * + * @since 4.0.0 + */ + getLanguageTag(): Promise; } /** diff --git a/device/src/web.ts b/device/src/web.ts index b42185c4d..ecc88e7b5 100644 --- a/device/src/web.ts +++ b/device/src/web.ts @@ -6,6 +6,7 @@ import type { DeviceInfo, DevicePlugin, GetLanguageCodeResult, + LanguageTag, } from './definitions'; declare global { @@ -66,6 +67,12 @@ export class DeviceWeb extends WebPlugin implements DevicePlugin { } async getLanguageCode(): Promise { + return { + value: navigator.language.split('-')[0].toLowerCase(), + }; + } + + async getLanguageTag(): Promise { return { value: navigator.language, }; @@ -171,7 +178,7 @@ export class DeviceWeb extends WebPlugin implements DevicePlugin { } getUid(): string { - if (typeof window !== 'undefined') { + if (typeof window !== 'undefined' && window.localStorage) { let uid = window.localStorage.getItem('_capuid'); if (uid) { return uid; diff --git a/dialog/CHANGELOG.md b/dialog/CHANGELOG.md index b9443607a..d955cc967 100644 --- a/dialog/CHANGELOG.md +++ b/dialog/CHANGELOG.md @@ -3,6 +3,88 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.1.0](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/dialog@1.0.7...@capacitor/dialog@4.1.0) (2022-11-16) + + + +## 4.0.1 (2022-07-28) + + + +# 4.0.0 (2022-07-27) + + + +# 4.0.0-beta.2 (2022-07-08) + + + +# 4.0.0-beta.0 (2022-06-27) + + +### Features + +* set targetSDK default value to 32 ([#970](https://github.com/ionic-team/capacitor-plugins/issues/970)) ([fa70d96](https://github.com/ionic-team/capacitor-plugins/commit/fa70d96f141af751aae53ceb5642c46b204f5958)) +* **dialog:** Make title optional ([#940](https://github.com/ionic-team/capacitor-plugins/issues/940)) ([497f627](https://github.com/ionic-team/capacitor-plugins/commit/497f6275ee6bc71295403e2cdc5a74b9cc31a310)) +* set targetSDK default value to 31 ([#824](https://github.com/ionic-team/capacitor-plugins/issues/824)) ([3ee10de](https://github.com/ionic-team/capacitor-plugins/commit/3ee10de98067984c1a4e75295d001c5a895c47f4)) +* Upgrade gradle to 7.4 ([#826](https://github.com/ionic-team/capacitor-plugins/issues/826)) ([5db0906](https://github.com/ionic-team/capacitor-plugins/commit/5db0906f6264287c4f8e69dbaecf19d4d387824b)) +* Use java 11 ([#910](https://github.com/ionic-team/capacitor-plugins/issues/910)) ([5acb2a2](https://github.com/ionic-team/capacitor-plugins/commit/5acb2a288a413492b163e4e97da46a085d9e4be0)) + + + + + +## [4.0.1](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0...4.0.1) (2022-07-28) + +**Note:** Version bump only for package @capacitor/dialog + + + + + +# [4.0.0](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0-beta.2...4.0.0) (2022-07-27) + +**Note:** Version bump only for package @capacitor/dialog + + + + + +# [4.0.0-beta.2](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0-beta.0...4.0.0-beta.2) (2022-07-08) + +**Note:** Version bump only for package @capacitor/dialog + + + + + +# 4.0.0-beta.0 (2022-06-27) + + +### Bug Fixes + +* add es2017 lib to tsconfig ([#180](https://github.com/ionic-team/capacitor-plugins/issues/180)) ([2c3776c](https://github.com/ionic-team/capacitor-plugins/commit/2c3776c38ca025c5ee965dec10ccf1cdb6c02e2f)) +* correct addListeners links ([#655](https://github.com/ionic-team/capacitor-plugins/issues/655)) ([f9871e7](https://github.com/ionic-team/capacitor-plugins/commit/f9871e7bd53478addb21155e148829f550c0e457)) +* inline source code in esm map files ([#760](https://github.com/ionic-team/capacitor-plugins/issues/760)) ([a960489](https://github.com/ionic-team/capacitor-plugins/commit/a960489a19db0182b90d187a50deff9dfbe51038)) +* remove postpublish scripts ([#656](https://github.com/ionic-team/capacitor-plugins/issues/656)) ([ed6ac49](https://github.com/ionic-team/capacitor-plugins/commit/ed6ac499ebf4a47525071ccbfc36c27503e11f60)) +* **dialogs:** put cancel button of confirm/prompt on the left ([#346](https://github.com/ionic-team/capacitor-plugins/issues/346)) ([1ac23db](https://github.com/ionic-team/capacitor-plugins/commit/1ac23db5162fa94742f18f00daf87a62a63f8dca)) +* support deprecated types from Capacitor 2 ([#139](https://github.com/ionic-team/capacitor-plugins/issues/139)) ([2d7127a](https://github.com/ionic-team/capacitor-plugins/commit/2d7127a488e26f0287951921a6db47c49d817336)) + + +### Features + +* set targetSDK default value to 32 ([#970](https://github.com/ionic-team/capacitor-plugins/issues/970)) ([fa70d96](https://github.com/ionic-team/capacitor-plugins/commit/fa70d96f141af751aae53ceb5642c46b204f5958)) +* **dialog:** Make title optional ([#940](https://github.com/ionic-team/capacitor-plugins/issues/940)) ([497f627](https://github.com/ionic-team/capacitor-plugins/commit/497f6275ee6bc71295403e2cdc5a74b9cc31a310)) +* add commonjs output format ([#179](https://github.com/ionic-team/capacitor-plugins/issues/179)) ([8e9e098](https://github.com/ionic-team/capacitor-plugins/commit/8e9e09862064b3f6771d7facbc4008e995d9b463)) +* Dialog plugin ([#44](https://github.com/ionic-team/capacitor-plugins/issues/44)) ([d7f0dd5](https://github.com/ionic-team/capacitor-plugins/commit/d7f0dd547699734aa44528d01662e6f984668121)) +* set targetSDK default value to 31 ([#824](https://github.com/ionic-team/capacitor-plugins/issues/824)) ([3ee10de](https://github.com/ionic-team/capacitor-plugins/commit/3ee10de98067984c1a4e75295d001c5a895c47f4)) +* Upgrade gradle to 7.4 ([#826](https://github.com/ionic-team/capacitor-plugins/issues/826)) ([5db0906](https://github.com/ionic-team/capacitor-plugins/commit/5db0906f6264287c4f8e69dbaecf19d4d387824b)) +* Use java 11 ([#910](https://github.com/ionic-team/capacitor-plugins/issues/910)) ([5acb2a2](https://github.com/ionic-team/capacitor-plugins/commit/5acb2a288a413492b163e4e97da46a085d9e4be0)) + + + + + ## [1.0.7](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/dialog@1.0.6...@capacitor/dialog@1.0.7) (2022-01-19) diff --git a/dialog/CapacitorDialog.podspec b/dialog/CapacitorDialog.podspec index d0d26084f..0932039d2 100644 --- a/dialog/CapacitorDialog.podspec +++ b/dialog/CapacitorDialog.podspec @@ -11,7 +11,7 @@ Pod::Spec.new do |s| s.author = package['author'] s.source = { :git => 'https://github.com/ionic-team/capacitor-plugins.git', :tag => package['name'] + '@' + package['version'] } s.source_files = 'ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}', 'dialog/ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}' - s.ios.deployment_target = '12.0' + s.ios.deployment_target = '13.0' s.dependency 'Capacitor' s.swift_version = '5.1' end diff --git a/dialog/android/build.gradle b/dialog/android/build.gradle index 56ee0b28b..43252f49c 100644 --- a/dialog/android/build.gradle +++ b/dialog/android/build.gradle @@ -1,27 +1,39 @@ ext { - junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.1' - androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.2.0' - androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.1.2' - androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.3.0' + capacitorVersion = System.getenv('CAPACITOR_VERSION') + junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.2' + androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.4.2' + androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.1.3' + androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.4.0' } buildscript { repositories { google() mavenCentral() + maven { + url "https://plugins.gradle.org/m2/" + } } dependencies { - classpath 'com.android.tools.build:gradle:4.2.1' + classpath 'com.android.tools.build:gradle:7.2.1' + if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + classpath 'io.github.gradle-nexus:publish-plugin:1.1.0' + } } } apply plugin: 'com.android.library' +if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + apply plugin: 'io.github.gradle-nexus.publish-plugin' + apply from: file('../../scripts/android/publish-root.gradle') + apply from: file('../../scripts/android/publish-module.gradle') +} android { - compileSdkVersion project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 30 + compileSdkVersion project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 32 defaultConfig { - minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 21 - targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 30 + minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 22 + targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 32 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" @@ -36,21 +48,26 @@ android { abortOnError false } compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility JavaVersion.VERSION_11 + targetCompatibility JavaVersion.VERSION_11 } } repositories { google() mavenCentral() - jcenter() } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation project(':capacitor-android') + + if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + implementation "com.capacitorjs:core:$capacitorVersion" + } else { + implementation project(':capacitor-android') + } + implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion" testImplementation "junit:junit:$junitVersion" androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion" diff --git a/dialog/android/gradle/wrapper/gradle-wrapper.jar b/dialog/android/gradle/wrapper/gradle-wrapper.jar index e708b1c02..41d9927a4 100644 Binary files a/dialog/android/gradle/wrapper/gradle-wrapper.jar and b/dialog/android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/dialog/android/gradle/wrapper/gradle-wrapper.properties b/dialog/android/gradle/wrapper/gradle-wrapper.properties index 3c4101c3e..92f06b50f 100644 --- a/dialog/android/gradle/wrapper/gradle-wrapper.properties +++ b/dialog/android/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/dialog/android/gradlew b/dialog/android/gradlew index 4f906e0c8..1b6c78733 100755 --- a/dialog/android/gradlew +++ b/dialog/android/gradlew @@ -1,7 +1,7 @@ -#!/usr/bin/env sh +#!/bin/sh # -# Copyright 2015 the original author or authors. +# Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,67 +17,101 @@ # ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` +APP_BASE_NAME=${0##*/} # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar @@ -87,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -98,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" + JAVACMD=java which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the @@ -106,80 +140,95 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=`expr $i + 1` + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" diff --git a/dialog/android/src/main/java/com/capacitorjs/plugins/dialog/Dialog.java b/dialog/android/src/main/java/com/capacitorjs/plugins/dialog/Dialog.java index e89f881aa..7ded29e18 100644 --- a/dialog/android/src/main/java/com/capacitorjs/plugins/dialog/Dialog.java +++ b/dialog/android/src/main/java/com/capacitorjs/plugins/dialog/Dialog.java @@ -40,7 +40,6 @@ public static void alert( final String okButtonTitle, final Dialog.OnResultListener listener ) { - final String alertTitle = title == null ? "Alert" : title; final String alertOkButtonTitle = okButtonTitle == null ? "OK" : okButtonTitle; new Handler(Looper.getMainLooper()) @@ -48,9 +47,11 @@ public static void alert( () -> { AlertDialog.Builder builder = new AlertDialog.Builder(context); + if (title != null) { + builder.setTitle(title); + } builder .setMessage(message) - .setTitle(alertTitle) .setPositiveButton( alertOkButtonTitle, (dialog, buttonIndex) -> { @@ -84,7 +85,6 @@ public static void confirm( final String cancelButtonTitle, final Dialog.OnResultListener listener ) { - final String confirmTitle = title == null ? "Confirm" : title; final String confirmOkButtonTitle = okButtonTitle == null ? "OK" : okButtonTitle; final String confirmCancelButtonTitle = cancelButtonTitle == null ? "Cancel" : cancelButtonTitle; @@ -92,10 +92,11 @@ public static void confirm( .post( () -> { final AlertDialog.Builder builder = new AlertDialog.Builder(context); - + if (title != null) { + builder.setTitle(title); + } builder .setMessage(message) - .setTitle(confirmTitle) .setPositiveButton( confirmOkButtonTitle, (dialog, buttonIndex) -> { @@ -138,7 +139,6 @@ public static void prompt( final String inputText, final Dialog.OnResultListener listener ) { - final String promptTitle = title == null ? "Prompt" : title; final String promptOkButtonTitle = okButtonTitle == null ? "OK" : okButtonTitle; final String promptCancelButtonTitle = cancelButtonTitle == null ? "Cancel" : cancelButtonTitle; final String promptInputPlaceholder = inputPlaceholder == null ? "" : inputPlaceholder; @@ -152,10 +152,11 @@ public static void prompt( input.setHint(promptInputPlaceholder); input.setText(promptInputText); - + if (title != null) { + builder.setTitle(title); + } builder .setMessage(message) - .setTitle(promptTitle) .setView(input) .setPositiveButton( promptOkButtonTitle, diff --git a/dialog/android/src/main/java/com/capacitorjs/plugins/dialog/DialogPlugin.java b/dialog/android/src/main/java/com/capacitorjs/plugins/dialog/DialogPlugin.java index abe147415..369e78539 100644 --- a/dialog/android/src/main/java/com/capacitorjs/plugins/dialog/DialogPlugin.java +++ b/dialog/android/src/main/java/com/capacitorjs/plugins/dialog/DialogPlugin.java @@ -17,8 +17,8 @@ public void alert(final PluginCall call) { final String message = call.getString("message"); final String buttonTitle = call.getString("buttonTitle", "OK"); - if (title == null || message == null) { - call.reject("Please provide a title or message for the alert"); + if (message == null) { + call.reject("Please provide a message for the dialog"); return; } @@ -38,8 +38,8 @@ public void confirm(final PluginCall call) { final String okButtonTitle = call.getString("okButtonTitle", "OK"); final String cancelButtonTitle = call.getString("cancelButtonTitle", "Cancel"); - if (title == null || message == null) { - call.reject("Please provide a title or message for the alert"); + if (message == null) { + call.reject("Please provide a message for the dialog"); return; } @@ -72,8 +72,8 @@ public void prompt(final PluginCall call) { final String inputPlaceholder = call.getString("inputPlaceholder", ""); final String inputText = call.getString("inputText", ""); - if (title == null || message == null) { - call.reject("Please provide a title or message for the alert"); + if (message == null) { + call.reject("Please provide a message for the dialog"); return; } diff --git a/dialog/ios/Plugin.xcodeproj/project.pbxproj b/dialog/ios/Plugin.xcodeproj/project.pbxproj index caa599bef..1fcdf8123 100644 --- a/dialog/ios/Plugin.xcodeproj/project.pbxproj +++ b/dialog/ios/Plugin.xcodeproj/project.pbxproj @@ -382,7 +382,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -442,7 +442,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; @@ -465,12 +465,13 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Plugin/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks $(FRAMEWORK_SEARCH_PATHS)\n$(FRAMEWORK_SEARCH_PATHS)\n$(FRAMEWORK_SEARCH_PATHS)"; ONLY_ACTIVE_ARCH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.getcapacitor.Plugin; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; + SUPPORTS_MACCATALYST = NO; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -490,12 +491,13 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Plugin/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks $(FRAMEWORK_SEARCH_PATHS)"; ONLY_ACTIVE_ARCH = NO; PRODUCT_BUNDLE_IDENTIFIER = com.getcapacitor.Plugin; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; + SUPPORTS_MACCATALYST = NO; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; diff --git a/dialog/ios/Plugin/DialogPlugin.swift b/dialog/ios/Plugin/DialogPlugin.swift index b226ef639..74adb2a16 100644 --- a/dialog/ios/Plugin/DialogPlugin.swift +++ b/dialog/ios/Plugin/DialogPlugin.swift @@ -8,11 +8,11 @@ import Capacitor public class DialogPlugin: CAPPlugin { @objc public func alert(_ call: CAPPluginCall) { - guard let title = call.options["title"] as? String else { - call.reject("title must be provided") + let title = call.options["title"] as? String + guard let message = call.options["message"] as? String else { + call.reject("Please provide a message for the dialog") return } - let message = call.options["message"] as? String let buttonTitle = call.options["buttonTitle"] as? String ?? "OK" DispatchQueue.main.async { [weak self] in @@ -25,11 +25,11 @@ public class DialogPlugin: CAPPlugin { } @objc public func confirm(_ call: CAPPluginCall) { - guard let title = call.options["title"] as? String else { - call.reject("title must be provided") + let title = call.options["title"] as? String + guard let message = call.options["message"] as? String else { + call.reject("Please provide a message for the dialog") return } - let message = call.options["message"] as? String ?? "" let okButtonTitle = call.options["okButtonTitle"] as? String ?? "OK" let cancelButtonTitle = call.options["cancelButtonTitle"] as? String ?? "Cancel" @@ -50,11 +50,11 @@ public class DialogPlugin: CAPPlugin { } @objc public func prompt (_ call: CAPPluginCall) { - guard let title = call.options["title"] as? String else { - call.reject("title must be provided") + let title = call.options["title"] as? String + guard let message = call.options["message"] as? String else { + call.reject("Please provide a message for the dialog") return } - let message = call.options["message"] as? String ?? "" let okButtonTitle = call.options["okButtonTitle"] as? String ?? "OK" let cancelButtonTitle = call.options["cancelButtonTitle"] as? String ?? "Cancel" let inputPlaceholder = call.options["inputPlaceholder"] as? String ?? "" diff --git a/dialog/ios/Podfile b/dialog/ios/Podfile index 54a00c161..dee40960f 100644 --- a/dialog/ios/Podfile +++ b/dialog/ios/Podfile @@ -1,4 +1,4 @@ -platform :ios, '12.0' +platform :ios, '13.0' def capacitor_pods # Comment the next line if you're not using Swift and don't want to use dynamic frameworks diff --git a/dialog/package.json b/dialog/package.json index f8ac10091..67379bf7b 100644 --- a/dialog/package.json +++ b/dialog/package.json @@ -1,6 +1,6 @@ { "name": "@capacitor/dialog", - "version": "1.0.7", + "version": "4.1.0", "description": "The Dialog API provides methods for triggering native dialog windows for alerts, confirmations, and input prompts", "main": "dist/plugin.cjs.js", "module": "dist/esm/index.js", @@ -29,7 +29,7 @@ ], "scripts": { "verify": "npm run verify:ios && npm run verify:android && npm run verify:web", - "verify:ios": "cd ios && pod install && xcodebuild -workspace Plugin.xcworkspace -scheme Plugin && cd ..", + "verify:ios": "cd ios && pod install && xcodebuild -workspace Plugin.xcworkspace -scheme Plugin -destination generic/platform=iOS && cd ..", "verify:android": "cd android && ./gradlew clean build test && cd ..", "verify:web": "npm run build", "lint": "npm run eslint && npm run prettier -- --check && npm run swiftlint -- lint", @@ -45,10 +45,10 @@ "publish:cocoapod": "pod trunk push ./CapacitorDialog.podspec --allow-warnings" }, "devDependencies": { - "@capacitor/android": "^3.0.0", - "@capacitor/core": "^3.0.0", - "@capacitor/docgen": "0.0.18", - "@capacitor/ios": "^3.0.0", + "@capacitor/android": "^4.0.0", + "@capacitor/core": "^4.0.0", + "@capacitor/docgen": "0.2.0", + "@capacitor/ios": "^4.0.0", "@ionic/eslint-config": "^0.3.0", "@ionic/prettier-config": "~1.0.1", "@ionic/swiftlint-config": "^1.1.2", @@ -61,7 +61,7 @@ "typescript": "~4.1.5" }, "peerDependencies": { - "@capacitor/core": "^3.0.0" + "@capacitor/core": "^4.0.0" }, "prettier": "@ionic/prettier-config", "swiftlint": "@ionic/swiftlint-config", diff --git a/dialog/src/definitions.ts b/dialog/src/definitions.ts index 28805c56a..eb6461de0 100644 --- a/dialog/src/definitions.ts +++ b/dialog/src/definitions.ts @@ -4,7 +4,7 @@ export interface AlertOptions { * * @since 1.0.0 */ - title: string; + title?: string; /** * Message to show on the dialog. @@ -28,7 +28,7 @@ export interface PromptOptions { * * @since 1.0.0 */ - title: string; + title?: string; /** * Message to show on the dialog. @@ -74,7 +74,7 @@ export interface ConfirmOptions { * * @since 1.0.0 */ - title: string; + title?: string; /** * Message to show on the dialog. diff --git a/filesystem/CHANGELOG.md b/filesystem/CHANGELOG.md index 0dce45a50..240262db8 100644 --- a/filesystem/CHANGELOG.md +++ b/filesystem/CHANGELOG.md @@ -3,6 +3,120 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [4.1.4](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/filesystem@4.1.3...@capacitor/filesystem@4.1.4) (2022-11-16) + +**Note:** Version bump only for package @capacitor/filesystem + + + + + +## [4.1.3](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/filesystem@4.1.2...@capacitor/filesystem@4.1.3) (2022-10-21) + +**Note:** Version bump only for package @capacitor/filesystem + + + + + +## [4.1.2](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/filesystem@4.1.1...@capacitor/filesystem@4.1.2) (2022-09-29) + + +### Bug Fixes + +* **filesystem:** Avoid max stack size exceeded on base64 check ([#1202](https://github.com/ionic-team/capacitor-plugins/issues/1202)) ([f4ba421](https://github.com/ionic-team/capacitor-plugins/commit/f4ba421b211e78bd205fa737955780a12e86e24f)) + + + + + +## [4.1.1](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/filesystem@4.1.0...@capacitor/filesystem@4.1.1) (2022-09-12) + +**Note:** Version bump only for package @capacitor/filesystem + + + + + +# [4.1.0](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/filesystem@1.1.0...@capacitor/filesystem@4.1.0) (2022-08-24) + + +### Bug Fixes + +* **filesystem:** failing to remove folder content on rmdir ([#1112](https://github.com/ionic-team/capacitor-plugins/issues/1112)) ([ae451aa](https://github.com/ionic-team/capacitor-plugins/commit/ae451aa08beb2138ecebdfcdd26101660aa00fde)) +* **filesystem:** make iOS return proper url on readdir ([#1142](https://github.com/ionic-team/capacitor-plugins/issues/1142)) ([77dc02f](https://github.com/ionic-team/capacitor-plugins/commit/77dc02fb829ad3479144368da16f9fff324f2706)) + + + + + +## [4.0.1](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0...4.0.1) (2022-07-28) + +**Note:** Version bump only for package @capacitor/filesystem + + + + + +# [4.0.0](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0-beta.2...4.0.0) (2022-07-27) + +**Note:** Version bump only for package @capacitor/filesystem + + + + + +# [4.0.0-beta.2](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0-beta.0...4.0.0-beta.2) (2022-07-08) + +**Note:** Version bump only for package @capacitor/filesystem + + + + + +# 4.0.0-beta.0 (2022-06-27) + + +### Bug Fixes + +* **filesystem:** Prevent android crash on invalid base64 write ([#937](https://github.com/ionic-team/capacitor-plugins/issues/937)) ([1af0bfe](https://github.com/ionic-team/capacitor-plugins/commit/1af0bfe24d2a36bc2949fe52866131c3327b321e)) +* **filesystem:** Throw errors instead of strings ([#746](https://github.com/ionic-team/capacitor-plugins/issues/746)) ([af4b875](https://github.com/ionic-team/capacitor-plugins/commit/af4b8750be512b869af07bcf96c1602eedc6758e)) +* **filesystem:** web appendFile with base64 data ([#928](https://github.com/ionic-team/capacitor-plugins/issues/928)) ([80253cf](https://github.com/ionic-team/capacitor-plugins/commit/80253cf2652bf7fa9c07933989cbdffeadd52a27)) +* correct addListeners links ([#655](https://github.com/ionic-team/capacitor-plugins/issues/655)) ([f9871e7](https://github.com/ionic-team/capacitor-plugins/commit/f9871e7bd53478addb21155e148829f550c0e457)) +* inline source code in esm map files ([#760](https://github.com/ionic-team/capacitor-plugins/issues/760)) ([a960489](https://github.com/ionic-team/capacitor-plugins/commit/a960489a19db0182b90d187a50deff9dfbe51038)) +* remove postpublish scripts ([#656](https://github.com/ionic-team/capacitor-plugins/issues/656)) ([ed6ac49](https://github.com/ionic-team/capacitor-plugins/commit/ed6ac499ebf4a47525071ccbfc36c27503e11f60)) +* **android:** permissions use "publicStorage" as alias ([#202](https://github.com/ionic-team/capacitor-plugins/issues/202)) ([2dfc7a3](https://github.com/ionic-team/capacitor-plugins/commit/2dfc7a3261a4f98871a86fe6d47fab084a2d1deb)) +* **android:** support writing files without scheme ([#241](https://github.com/ionic-team/capacitor-plugins/issues/241)) ([4285cb1](https://github.com/ionic-team/capacitor-plugins/commit/4285cb1d37ec3361e7ec4da4786502693b04d478)) +* **filesystem:** allow copy if from is not parent of to ([#546](https://github.com/ionic-team/capacitor-plugins/issues/546)) ([a70414e](https://github.com/ionic-team/capacitor-plugins/commit/a70414e79189579ff1a0b5c2a90d12491f5c23cf)) +* **filesystem:** Append doesn't resolve on iOS ([#305](https://github.com/ionic-team/capacitor-plugins/issues/305)) ([98e91cd](https://github.com/ionic-team/capacitor-plugins/commit/98e91cd745fb12bf46f99233bb527f147dbba58b)) +* **filesystem:** Convert stat ctime/mtime timestamp to milliseconds ([#321](https://github.com/ionic-team/capacitor-plugins/issues/321)) ([d978986](https://github.com/ionic-team/capacitor-plugins/commit/d97898662d0ba037e5f8448990a91de5ec6a4234)) +* **filesystem:** copy doesn't resolve on Android ([#233](https://github.com/ionic-team/capacitor-plugins/issues/233)) ([17cbf3b](https://github.com/ionic-team/capacitor-plugins/commit/17cbf3b0ada97f1279fba32b551c380c0e669406)) +* **filesystem:** is not requesting permission on public directories ([#246](https://github.com/ionic-team/capacitor-plugins/issues/246)) ([aa897ab](https://github.com/ionic-team/capacitor-plugins/commit/aa897ab4269e34cd5d762ed645030054ddda7dd6)) +* **filesystem:** Make ctime optional ([#373](https://github.com/ionic-team/capacitor-plugins/issues/373)) ([e3c6212](https://github.com/ionic-team/capacitor-plugins/commit/e3c6212b94c75cf747a8768af5056963683953b2)) +* **filesystem:** rmdir doesn't resolve on iOS ([#239](https://github.com/ionic-team/capacitor-plugins/issues/239)) ([7ca538b](https://github.com/ionic-team/capacitor-plugins/commit/7ca538bb47e2e00080eadfe8d875323c1e198cb2)) +* add es2017 lib to tsconfig ([#180](https://github.com/ionic-team/capacitor-plugins/issues/180)) ([2c3776c](https://github.com/ionic-team/capacitor-plugins/commit/2c3776c38ca025c5ee965dec10ccf1cdb6c02e2f)) +* support deprecated types from Capacitor 2 ([#139](https://github.com/ionic-team/capacitor-plugins/issues/139)) ([2d7127a](https://github.com/ionic-team/capacitor-plugins/commit/2d7127a488e26f0287951921a6db47c49d817336)) +* **filesystem:** Use PermissionState from @capacitor/core ([#148](https://github.com/ionic-team/capacitor-plugins/issues/148)) ([5ce3c5d](https://github.com/ionic-team/capacitor-plugins/commit/5ce3c5d491a35b8771661f3e4eb98aac6df15911)) + + +### Features + +* set targetSDK default value to 32 ([#970](https://github.com/ionic-team/capacitor-plugins/issues/970)) ([fa70d96](https://github.com/ionic-team/capacitor-plugins/commit/fa70d96f141af751aae53ceb5642c46b204f5958)) +* **filesystem:** Make readDir return files information ([#949](https://github.com/ionic-team/capacitor-plugins/issues/949)) ([0a9f43d](https://github.com/ionic-team/capacitor-plugins/commit/0a9f43dffd3815f600c35ed4528c017644fdb55e)) +* **filesystem:** Return path of copied file ([#931](https://github.com/ionic-team/capacitor-plugins/issues/931)) ([310f583](https://github.com/ionic-team/capacitor-plugins/commit/310f583ccec58730ab8046a1618782c950c60656)) +* add commonjs output format ([#179](https://github.com/ionic-team/capacitor-plugins/issues/179)) ([8e9e098](https://github.com/ionic-team/capacitor-plugins/commit/8e9e09862064b3f6771d7facbc4008e995d9b463)) +* Filesystem plugin ([#19](https://github.com/ionic-team/capacitor-plugins/issues/19)) ([3b86a4a](https://github.com/ionic-team/capacitor-plugins/commit/3b86a4a972e00eaed1d078bfcc69af6136222dc4)) +* set targetSDK default value to 31 ([#824](https://github.com/ionic-team/capacitor-plugins/issues/824)) ([3ee10de](https://github.com/ionic-team/capacitor-plugins/commit/3ee10de98067984c1a4e75295d001c5a895c47f4)) +* Upgrade gradle to 7.4 ([#826](https://github.com/ionic-team/capacitor-plugins/issues/826)) ([5db0906](https://github.com/ionic-team/capacitor-plugins/commit/5db0906f6264287c4f8e69dbaecf19d4d387824b)) +* Use java 11 ([#910](https://github.com/ionic-team/capacitor-plugins/issues/910)) ([5acb2a2](https://github.com/ionic-team/capacitor-plugins/commit/5acb2a288a413492b163e4e97da46a085d9e4be0)) +* **android:** implements Activity Result API changes for permissions and activity results ([#222](https://github.com/ionic-team/capacitor-plugins/issues/222)) ([f671b9f](https://github.com/ionic-team/capacitor-plugins/commit/f671b9f4b472806ef43db6dcf302d4503cf1828c)) +* **filesystem:** Allow the use of absolute urls on iOS and web ([#250](https://github.com/ionic-team/capacitor-plugins/issues/250)) ([03ad97c](https://github.com/ionic-team/capacitor-plugins/commit/03ad97c1b7450e864504198853aac2b3bdc4b8a4)) +* **filesystem:** support Library directory ([#666](https://github.com/ionic-team/capacitor-plugins/issues/666)) ([ce7ee95](https://github.com/ionic-team/capacitor-plugins/commit/ce7ee958b141f1dd4f86493923455f8264d0b6db)) + + + + + # [1.1.0](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/filesystem@1.0.7...@capacitor/filesystem@1.1.0) (2022-01-19) diff --git a/filesystem/CapacitorFilesystem.podspec b/filesystem/CapacitorFilesystem.podspec index 18388eb47..8ca32198f 100644 --- a/filesystem/CapacitorFilesystem.podspec +++ b/filesystem/CapacitorFilesystem.podspec @@ -11,7 +11,7 @@ Pod::Spec.new do |s| s.author = package['author'] s.source = { :git => 'https://github.com/ionic-team/capacitor-plugins.git', :tag => package['name'] + '@' + package['version'] } s.source_files = 'ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}', 'filesystem/ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}' - s.ios.deployment_target = '12.0' + s.ios.deployment_target = '13.0' s.dependency 'Capacitor' s.swift_version = '5.1' end diff --git a/filesystem/README.md b/filesystem/README.md index cb7dc7597..83278fcb7 100644 --- a/filesystem/README.md +++ b/filesystem/README.md @@ -9,6 +9,15 @@ npm install @capacitor/filesystem npx cap sync ``` +## iOS + +To have files appear in the Files app, you must set the following keys to `YES` in `Info.plist`: + +- `UIFileSharingEnabled` (`Application supports iTunes file sharing`) +- `LSSupportsOpeningDocumentsInPlace` (`Supports opening documents in place`) + +Read about [Configuring iOS](https://capacitorjs.com/docs/ios/configuration) for help. + ## Android If using `Directory.Documents` or @@ -282,7 +291,7 @@ Rename a file or directory ### copy(...) ```typescript -copy(options: CopyOptions) => Promise +copy(options: CopyOptions) => Promise ``` Copy a file or directory @@ -291,6 +300,8 @@ Copy a file or directory | ------------- | --------------------------------------------------- | | **`options`** | CopyOptions | +**Returns:** Promise<CopyResult> + **Since:** 1.0.0 -------------------- @@ -405,9 +416,21 @@ Required on Android, only when using `Directory.Documents`< #### ReaddirResult -| Prop | Type | Description | Since | -| ----------- | --------------------- | -------------------------------------------------- | ----- | -| **`files`** | string[] | List of files and directories inside the directory | 1.0.0 | +| Prop | Type | Description | Since | +| ----------- | ----------------------- | -------------------------------------------------- | ----- | +| **`files`** | FileInfo[] | List of files and directories inside the directory | 1.0.0 | + + +#### FileInfo + +| Prop | Type | Description | Since | +| ----------- | ---------------------------------- | ------------------------------------------------------------------------------------ | ----- | +| **`name`** | string | Name of the file or directory. | | +| **`type`** | 'directory' \| 'file' | Type of the file. | 4.0.0 | +| **`size`** | number | Size of the file in bytes. | 4.0.0 | +| **`ctime`** | number | Time of creation in milliseconds. It's not available on Android 7 and older devices. | 4.0.0 | +| **`mtime`** | number | Time of last modification in milliseconds. | 4.0.0 | +| **`uri`** | string | The uri of the file. | 4.0.0 | #### ReaddirOptions @@ -435,13 +458,13 @@ Required on Android, only when using `Directory.Documents`< #### StatResult -| Prop | Type | Description | Since | -| ----------- | ------------------- | ------------------------------------------------------------------------------------ | ----- | -| **`type`** | string | Type of the file | 1.0.0 | -| **`size`** | number | Size of the file | 1.0.0 | -| **`ctime`** | number | Time of creation in milliseconds. It's not available on Android 7 and older devices. | 1.0.0 | -| **`mtime`** | number | Time of last modification in milliseconds. | 1.0.0 | -| **`uri`** | string | The uri of the file | 1.0.0 | +| Prop | Type | Description | Since | +| ----------- | ---------------------------------- | ------------------------------------------------------------------------------------ | ----- | +| **`type`** | 'directory' \| 'file' | Type of the file. | 1.0.0 | +| **`size`** | number | Size of the file in bytes. | 1.0.0 | +| **`ctime`** | number | Time of creation in milliseconds. It's not available on Android 7 and older devices. | 1.0.0 | +| **`mtime`** | number | Time of last modification in milliseconds. | 1.0.0 | +| **`uri`** | string | The uri of the file | 1.0.0 | #### StatOptions @@ -462,6 +485,13 @@ Required on Android, only when using `Directory.Documents`< | **`toDirectory`** | Directory | The `Directory` containing the destination file or directory. If not supplied will use the 'directory' parameter as the destination | 1.0.0 | +#### CopyResult + +| Prop | Type | Description | Since | +| --------- | ------------------- | -------------------------------------- | ----- | +| **`uri`** | string | The uri where the file was copied into | 4.0.0 | + + #### PermissionStatus | Prop | Type | diff --git a/filesystem/android/build.gradle b/filesystem/android/build.gradle index 7803a755b..378b0365e 100644 --- a/filesystem/android/build.gradle +++ b/filesystem/android/build.gradle @@ -1,26 +1,38 @@ ext { - junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.1' - androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.1.2' - androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.3.0' + capacitorVersion = System.getenv('CAPACITOR_VERSION') + junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.2' + androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.1.3' + androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.4.0' } buildscript { repositories { google() mavenCentral() + maven { + url "https://plugins.gradle.org/m2/" + } } dependencies { - classpath 'com.android.tools.build:gradle:4.2.1' + classpath 'com.android.tools.build:gradle:7.2.1' + if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + classpath 'io.github.gradle-nexus:publish-plugin:1.1.0' + } } } apply plugin: 'com.android.library' +if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + apply plugin: 'io.github.gradle-nexus.publish-plugin' + apply from: file('../../scripts/android/publish-root.gradle') + apply from: file('../../scripts/android/publish-module.gradle') +} android { - compileSdkVersion project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 30 + compileSdkVersion project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 32 defaultConfig { - minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 21 - targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 30 + minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 22 + targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 32 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" @@ -35,21 +47,26 @@ android { abortOnError false } compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility JavaVersion.VERSION_11 + targetCompatibility JavaVersion.VERSION_11 } } repositories { google() mavenCentral() - jcenter() } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation project(':capacitor-android') + + if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + implementation "com.capacitorjs:core:$capacitorVersion" + } else { + implementation project(':capacitor-android') + } + testImplementation "junit:junit:$junitVersion" androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion" androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion" diff --git a/filesystem/android/gradle/wrapper/gradle-wrapper.jar b/filesystem/android/gradle/wrapper/gradle-wrapper.jar index e708b1c02..41d9927a4 100644 Binary files a/filesystem/android/gradle/wrapper/gradle-wrapper.jar and b/filesystem/android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/filesystem/android/gradle/wrapper/gradle-wrapper.properties b/filesystem/android/gradle/wrapper/gradle-wrapper.properties index 3c4101c3e..92f06b50f 100644 --- a/filesystem/android/gradle/wrapper/gradle-wrapper.properties +++ b/filesystem/android/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/filesystem/android/gradlew b/filesystem/android/gradlew index 4f906e0c8..1b6c78733 100755 --- a/filesystem/android/gradlew +++ b/filesystem/android/gradlew @@ -1,7 +1,7 @@ -#!/usr/bin/env sh +#!/bin/sh # -# Copyright 2015 the original author or authors. +# Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,67 +17,101 @@ # ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` +APP_BASE_NAME=${0##*/} # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar @@ -87,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -98,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" + JAVACMD=java which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the @@ -106,80 +140,95 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=`expr $i + 1` + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" diff --git a/filesystem/android/src/main/java/com/capacitorjs/plugins/filesystem/Filesystem.java b/filesystem/android/src/main/java/com/capacitorjs/plugins/filesystem/Filesystem.java index 481a71c9b..6eee93971 100644 --- a/filesystem/android/src/main/java/com/capacitorjs/plugins/filesystem/Filesystem.java +++ b/filesystem/android/src/main/java/com/capacitorjs/plugins/filesystem/Filesystem.java @@ -72,18 +72,18 @@ public boolean mkdir(String path, String directory, Boolean recursive) throws Di return created; } - public String[] readdir(String path, String directory) throws DirectoryNotFoundException { - String[] files = null; + public File[] readdir(String path, String directory) throws DirectoryNotFoundException { + File[] files = null; File fileObject = getFileObject(path, directory); if (fileObject != null && fileObject.exists()) { - files = fileObject.list(); + files = fileObject.listFiles(); } else { throw new DirectoryNotFoundException("Directory does not exist"); } return files; } - public boolean copy(String from, String directory, String to, String toDirectory, boolean doRename) + public File copy(String from, String directory, String to, String toDirectory, boolean doRename) throws IOException, CopyFailedException { if (toDirectory == null) { toDirectory = directory; @@ -100,7 +100,7 @@ public boolean copy(String from, String directory, String to, String toDirectory } if (toObject.equals(fromObject)) { - return true; + return toObject; } if (!fromObject.exists()) { @@ -130,7 +130,7 @@ public boolean copy(String from, String directory, String to, String toDirectory copyRecursively(fromObject, toObject); } - return true; + return toObject; } public InputStream getInputStream(String path, String directory) throws IOException { @@ -180,6 +180,7 @@ public String readFileAsBase64EncodedData(InputStream is) throws IOException { return Base64.encodeToString(byteStream.toByteArray(), Base64.NO_WRAP); } + @SuppressWarnings("deprecation") public File getDirectory(String directory) { Context c = this.context; switch (directory) { diff --git a/filesystem/android/src/main/java/com/capacitorjs/plugins/filesystem/FilesystemPlugin.java b/filesystem/android/src/main/java/com/capacitorjs/plugins/filesystem/FilesystemPlugin.java index eef29742a..33fbea96d 100644 --- a/filesystem/android/src/main/java/com/capacitorjs/plugins/filesystem/FilesystemPlugin.java +++ b/filesystem/android/src/main/java/com/capacitorjs/plugins/filesystem/FilesystemPlugin.java @@ -169,6 +169,8 @@ private void saveFile(PluginCall call, File file, String data) { ex ); call.reject("FILE_NOTCREATED"); + } catch (IllegalArgumentException ex) { + call.reject("The supplied data is not valid base64 content."); } } @@ -267,10 +269,37 @@ public void readdir(PluginCall call) { requestAllPermissions(call, "permissionCallback"); } else { try { - String[] files = implementation.readdir(path, directory); + File[] files = implementation.readdir(path, directory); + JSArray filesArray = new JSArray(); if (files != null) { + for (var i = 0; i < files.length; i++) { + File fileObject = files[i]; + JSObject data = new JSObject(); + data.put("name", fileObject.getName()); + data.put("type", fileObject.isDirectory() ? "directory" : "file"); + data.put("size", fileObject.length()); + data.put("mtime", fileObject.lastModified()); + data.put("uri", Uri.fromFile(fileObject).toString()); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + try { + BasicFileAttributes attr = Files.readAttributes(fileObject.toPath(), BasicFileAttributes.class); + + // use whichever is the oldest between creationTime and lastAccessTime + if (attr.creationTime().toMillis() < attr.lastAccessTime().toMillis()) { + data.put("ctime", attr.creationTime().toMillis()); + } else { + data.put("ctime", attr.lastAccessTime().toMillis()); + } + } catch (Exception ex) {} + } else { + data.put("ctime", null); + } + filesArray.put(data); + } + JSObject ret = new JSObject(); - ret.put("files", JSArray.from(files)); + ret.put("files", filesArray); call.resolve(ret); } else { call.reject("Unable to read directory"); @@ -364,8 +393,14 @@ private void _copy(PluginCall call, Boolean doRename) { } } try { - implementation.copy(from, directory, to, toDirectory, doRename); - call.resolve(); + File file = implementation.copy(from, directory, to, toDirectory, doRename); + if (!doRename) { + JSObject result = new JSObject(); + result.put("uri", Uri.fromFile(file).toString()); + call.resolve(result); + } else { + call.resolve(); + } } catch (CopyFailedException ex) { call.reject(ex.getMessage()); } catch (IOException ex) { diff --git a/filesystem/ios/Plugin.xcodeproj/project.pbxproj b/filesystem/ios/Plugin.xcodeproj/project.pbxproj index c0b54d5e3..5b8653e65 100644 --- a/filesystem/ios/Plugin.xcodeproj/project.pbxproj +++ b/filesystem/ios/Plugin.xcodeproj/project.pbxproj @@ -386,7 +386,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -446,7 +446,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; @@ -469,12 +469,13 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Plugin/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks $(FRAMEWORK_SEARCH_PATHS)\n$(FRAMEWORK_SEARCH_PATHS)\n$(FRAMEWORK_SEARCH_PATHS)"; ONLY_ACTIVE_ARCH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.getcapacitor.Plugin; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; + SUPPORTS_MACCATALYST = NO; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -494,12 +495,13 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Plugin/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks $(FRAMEWORK_SEARCH_PATHS)"; ONLY_ACTIVE_ARCH = NO; PRODUCT_BUNDLE_IDENTIFIER = com.getcapacitor.Plugin; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; + SUPPORTS_MACCATALYST = NO; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; diff --git a/filesystem/ios/Plugin/Filesystem.swift b/filesystem/ios/Plugin/Filesystem.swift index 18f590aee..9adf0766f 100644 --- a/filesystem/ios/Plugin/Filesystem.swift +++ b/filesystem/ios/Plugin/Filesystem.swift @@ -103,6 +103,15 @@ import Foundation return try FileManager.default.attributesOfItem(atPath: fileUrl.path) } + func getType(from attr: [FileAttributeKey: Any]) -> String { + let fileType = attr[.type] as? String ?? "" + if fileType == "NSFileTypeDirectory" { + return "directory" + } else { + return "file" + } + } + @objc public func rename(at srcURL: URL, to dstURL: URL) throws { try _copy(at: srcURL, to: dstURL, doRename: true) } @@ -159,8 +168,10 @@ import Foundation guard let dir = FileManager.default.urls(for: directory, in: .userDomainMask).first else { return nil } - - return dir.appendingPathComponent(path) + if !path.isEmpty { + return dir.appendingPathComponent(path) + } + return dir } else { return URL(string: path) } diff --git a/filesystem/ios/Plugin/FilesystemPlugin.swift b/filesystem/ios/Plugin/FilesystemPlugin.swift index d3147d30d..62975b24e 100644 --- a/filesystem/ios/Plugin/FilesystemPlugin.swift +++ b/filesystem/ios/Plugin/FilesystemPlugin.swift @@ -188,11 +188,29 @@ public class FilesystemPlugin: CAPPlugin { do { let directoryContents = try implementation.readdir(at: fileUrl) - let directoryPathStrings = directoryContents.map {(url: URL) -> String in - return url.lastPathComponent + let directoryContent = try directoryContents.map {(url: URL) -> [String: Any] in + let attr = try implementation.stat(at: url) + var ctime = "" + var mtime = "" + + if let ctimeSeconds = (attr[.creationDate] as? Date)?.timeIntervalSince1970 { + ctime = String(format: "%.0f", ctimeSeconds * 1000) + } + + if let mtimeSeconds = (attr[.modificationDate] as? Date)?.timeIntervalSince1970 { + mtime = String(format: "%.0f", mtimeSeconds * 1000) + } + return [ + "name": url.lastPathComponent, + "type": implementation.getType(from: attr), + "size": attr[.size] as? UInt64 ?? 0, + "ctime": ctime, + "mtime": mtime, + "uri": url.absoluteString + ] } call.resolve([ - "files": directoryPathStrings + "files": directoryContent ]) } catch { handleError(call, error.localizedDescription, error) @@ -226,8 +244,8 @@ public class FilesystemPlugin: CAPPlugin { } call.resolve([ - "type": attr[.type] as? String ?? "", - "size": attr[.size] as? UInt64 ?? "", + "type": implementation.getType(from: attr), + "size": attr[.size] as? UInt64 ?? 0, "ctime": ctime, "mtime": mtime, "uri": fileUrl.absoluteString @@ -307,7 +325,9 @@ public class FilesystemPlugin: CAPPlugin { } do { try implementation.copy(at: fromUrl, to: toUrl) - call.resolve() + call.resolve([ + "uri": toUrl.absoluteString + ]) } catch let error as NSError { handleError(call, error.localizedDescription, error) } diff --git a/filesystem/ios/Podfile b/filesystem/ios/Podfile index 54a00c161..dee40960f 100644 --- a/filesystem/ios/Podfile +++ b/filesystem/ios/Podfile @@ -1,4 +1,4 @@ -platform :ios, '12.0' +platform :ios, '13.0' def capacitor_pods # Comment the next line if you're not using Swift and don't want to use dynamic frameworks diff --git a/filesystem/package.json b/filesystem/package.json index 7addf725a..9aaa48771 100644 --- a/filesystem/package.json +++ b/filesystem/package.json @@ -1,6 +1,6 @@ { "name": "@capacitor/filesystem", - "version": "1.1.0", + "version": "4.1.4", "description": "The Filesystem API provides a NodeJS-like API for working with files on the device.", "main": "dist/plugin.cjs.js", "module": "dist/esm/index.js", @@ -29,7 +29,7 @@ ], "scripts": { "verify": "npm run verify:ios && npm run verify:android && npm run verify:web", - "verify:ios": "cd ios && pod install && xcodebuild -workspace Plugin.xcworkspace -scheme Plugin && cd ..", + "verify:ios": "cd ios && pod install && xcodebuild -workspace Plugin.xcworkspace -scheme Plugin -destination generic/platform=iOS && cd ..", "verify:android": "cd android && ./gradlew clean build test && cd ..", "verify:web": "npm run build", "lint": "npm run eslint && npm run prettier -- --check && npm run swiftlint -- lint", @@ -45,10 +45,10 @@ "publish:cocoapod": "pod trunk push ./CapacitorFilesystem.podspec --allow-warnings" }, "devDependencies": { - "@capacitor/android": "^3.0.0", - "@capacitor/core": "^3.0.0", - "@capacitor/docgen": "0.0.18", - "@capacitor/ios": "^3.0.0", + "@capacitor/android": "^4.0.0", + "@capacitor/core": "^4.0.0", + "@capacitor/docgen": "0.2.0", + "@capacitor/ios": "^4.0.0", "@ionic/eslint-config": "^0.3.0", "@ionic/prettier-config": "~1.0.1", "@ionic/swiftlint-config": "^1.1.2", @@ -61,7 +61,7 @@ "typescript": "~4.1.5" }, "peerDependencies": { - "@capacitor/core": "^3.0.0" + "@capacitor/core": "^4.0.0" }, "prettier": "@ionic/prettier-config", "swiftlint": "@ionic/swiftlint-config", diff --git a/filesystem/src/definitions.ts b/filesystem/src/definitions.ts index e689ef03b..e8c21f8c4 100644 --- a/filesystem/src/definitions.ts +++ b/filesystem/src/definitions.ts @@ -371,7 +371,50 @@ export interface ReaddirResult { * * @since 1.0.0 */ - files: string[]; + files: FileInfo[]; +} + +export interface FileInfo { + /** + * Name of the file or directory. + */ + name: string; + /** + * Type of the file. + * + * @since 4.0.0 + */ + type: 'directory' | 'file'; + + /** + * Size of the file in bytes. + * + * @since 4.0.0 + */ + size: number; + + /** + * Time of creation in milliseconds. + * + * It's not available on Android 7 and older devices. + * + * @since 4.0.0 + */ + ctime?: number; + + /** + * Time of last modification in milliseconds. + * + * @since 4.0.0 + */ + mtime: number; + + /** + * The uri of the file. + * + * @since 4.0.0 + */ + uri: string; } export interface GetUriResult { @@ -385,14 +428,14 @@ export interface GetUriResult { export interface StatResult { /** - * Type of the file + * Type of the file. * * @since 1.0.0 */ - type: string; + type: 'directory' | 'file'; /** - * Size of the file + * Size of the file in bytes. * * @since 1.0.0 */ @@ -422,6 +465,15 @@ export interface StatResult { uri: string; } +export interface CopyResult { + /** + * The uri where the file was copied into + * + * @since 4.0.0 + */ + uri: string; +} + export interface FilesystemPlugin { /** * Read a file from disk @@ -498,7 +550,7 @@ export interface FilesystemPlugin { * * @since 1.0.0 */ - copy(options: CopyOptions): Promise; + copy(options: CopyOptions): Promise; /** * Check read/write permissions. diff --git a/filesystem/src/web.ts b/filesystem/src/web.ts index 355430228..fcdc0d311 100644 --- a/filesystem/src/web.ts +++ b/filesystem/src/web.ts @@ -3,6 +3,7 @@ import { WebPlugin } from '@capacitor/core'; import type { AppendFileOptions, CopyOptions, + CopyResult, DeleteFileOptions, FilesystemPlugin, GetUriOptions, @@ -170,14 +171,14 @@ export class FilesystemWeb extends WebPlugin implements FilesystemPlugin { */ async writeFile(options: WriteFileOptions): Promise { const path: string = this.getPath(options.directory, options.path); - const data = options.data; + let data = options.data; + const encoding = options.encoding; const doRecursive = options.recursive; const occupiedEntry = (await this.dbRequest('get', [path])) as EntryObj; if (occupiedEntry && occupiedEntry.type === 'directory') throw Error('The supplied path is a directory.'); - const encoding = options.encoding; const parentPath = path.substr(0, path.lastIndexOf('/')); const parentEntry = (await this.dbRequest('get', [parentPath])) as EntryObj; @@ -192,6 +193,13 @@ export class FilesystemWeb extends WebPlugin implements FilesystemPlugin { }); } } + + if (!encoding) { + data = data.indexOf(',') >= 0 ? data.split(',')[1] : data; + if (!this.isBase64String(data)) + throw Error('The supplied data is not valid base64 content.'); + } + const now = Date.now(); const pathObj: EntryObj = { path: path, @@ -200,7 +208,7 @@ export class FilesystemWeb extends WebPlugin implements FilesystemPlugin { size: data.length, ctime: now, mtime: now, - content: !encoding && data.indexOf(',') >= 0 ? data.split(',')[1] : data, + content: data, }; await this.dbRequest('put', [pathObj]); return { @@ -216,7 +224,7 @@ export class FilesystemWeb extends WebPlugin implements FilesystemPlugin { async appendFile(options: AppendFileOptions): Promise { const path: string = this.getPath(options.directory, options.path); let data = options.data; - // const encoding = options.encoding; + const encoding = options.encoding; const parentPath = path.substr(0, path.lastIndexOf('/')); const now = Date.now(); @@ -239,8 +247,15 @@ export class FilesystemWeb extends WebPlugin implements FilesystemPlugin { } } + if (!encoding && !this.isBase64String(data)) + throw Error('The supplied data is not valid base64 content.'); + if (occupiedEntry !== undefined) { - data = occupiedEntry.content + data; + if (occupiedEntry.content !== undefined && !encoding) { + data = btoa(atob(occupiedEntry.content) + atob(data)); + } else { + data = occupiedEntry.content + data; + } ctime = occupiedEntry.ctime; } const pathObj: EntryObj = { @@ -333,7 +348,7 @@ export class FilesystemWeb extends WebPlugin implements FilesystemPlugin { throw Error('Folder is not empty'); for (const entry of readDirResult.files) { - const entryPath = `${path}/${entry}`; + const entryPath = `${path}/${entry.name}`; const entryObj = await this.stat({ path: entryPath, directory }); if (entryObj.type === 'file') { await this.deleteFile({ path: entryPath, directory }); @@ -362,10 +377,23 @@ export class FilesystemWeb extends WebPlugin implements FilesystemPlugin { 'getAllKeys', [IDBKeyRange.only(path)], ); - const names = entries.map(e => { - return e.substring(path.length + 1); - }); - return { files: names }; + const files = await Promise.all( + entries.map(async e => { + let subEntry = (await this.dbRequest('get', [e])) as EntryObj; + if (subEntry === undefined) { + subEntry = (await this.dbRequest('get', [e + '/'])) as EntryObj; + } + return { + name: e.substring(path.length + 1), + type: subEntry.type, + size: subEntry.size, + ctime: subEntry.ctime, + mtime: subEntry.mtime, + uri: subEntry.path, + }; + }), + ); + return { files: files }; } /** @@ -414,7 +442,8 @@ export class FilesystemWeb extends WebPlugin implements FilesystemPlugin { * @return a promise that resolves with the rename result */ async rename(options: RenameOptions): Promise { - return this._copy(options, true); + await this._copy(options, true); + return; } /** @@ -422,7 +451,7 @@ export class FilesystemWeb extends WebPlugin implements FilesystemPlugin { * @param options the options for the copy operation * @return a promise that resolves with the copy result */ - async copy(options: CopyOptions): Promise { + async copy(options: CopyOptions): Promise { return this._copy(options, false); } @@ -440,7 +469,10 @@ export class FilesystemWeb extends WebPlugin implements FilesystemPlugin { * @param doRename whether to perform a rename or copy operation * @return a promise that resolves with the result */ - private async _copy(options: CopyOptions, doRename = false): Promise { + private async _copy( + options: CopyOptions, + doRename = false, + ): Promise { let { toDirectory } = options; const { to, from, directory: fromDirectory } = options; @@ -458,7 +490,9 @@ export class FilesystemWeb extends WebPlugin implements FilesystemPlugin { // Test that the "to" and "from" locations are different if (fromPath === toPath) { - return; + return { + uri: toPath, + }; } if (isPathParent(fromPath, toPath)) { @@ -531,7 +565,7 @@ export class FilesystemWeb extends WebPlugin implements FilesystemPlugin { } // Write the file to the new location - await this.writeFile({ + const writeResult = await this.writeFile({ path: to, directory: toDirectory, data: file.data, @@ -543,7 +577,7 @@ export class FilesystemWeb extends WebPlugin implements FilesystemPlugin { } // Resolve promise - return; + return writeResult; } case 'directory': { if (toObj) { @@ -596,13 +630,24 @@ export class FilesystemWeb extends WebPlugin implements FilesystemPlugin { } } } + return { + uri: toPath, + }; + } + + private isBase64String(str: string): boolean { + try { + return btoa(atob(str)) == str; + } catch (err) { + return false; + } } } interface EntryObj { path: string; folder: string; - type: string; + type: 'directory' | 'file'; size: number; ctime: number; mtime: number; diff --git a/geolocation/CHANGELOG.md b/geolocation/CHANGELOG.md index b5327ff10..8d0d56066 100644 --- a/geolocation/CHANGELOG.md +++ b/geolocation/CHANGELOG.md @@ -3,6 +3,101 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.1.0](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/geolocation@1.3.1...@capacitor/geolocation@4.1.0) (2022-11-16) + + + +## 4.0.1 (2022-07-28) + + + +# 4.0.0 (2022-07-27) + + + +# 4.0.0-beta.2 (2022-07-08) + + + +# 4.0.0-beta.0 (2022-06-27) + + +### Bug Fixes + +* **geolocation:** reject checkPermissions / requestPermissions if location services are disabled ([#1053](https://github.com/ionic-team/capacitor-plugins/issues/1053)) ([774ec6e](https://github.com/ionic-team/capacitor-plugins/commit/774ec6e941193b1b06d07d31e6672340de532385)) +* **geolocation:** stop location requests on pause ([#1018](https://github.com/ionic-team/capacitor-plugins/issues/1018)) ([eb24f25](https://github.com/ionic-team/capacitor-plugins/commit/eb24f2521d05dd25a2087a1de2b3e0644568cda0)) + + +### Features + +* set targetSDK default value to 31 ([#824](https://github.com/ionic-team/capacitor-plugins/issues/824)) ([3ee10de](https://github.com/ionic-team/capacitor-plugins/commit/3ee10de98067984c1a4e75295d001c5a895c47f4)) +* set targetSDK default value to 32 ([#970](https://github.com/ionic-team/capacitor-plugins/issues/970)) ([fa70d96](https://github.com/ionic-team/capacitor-plugins/commit/fa70d96f141af751aae53ceb5642c46b204f5958)) +* Upgrade gradle to 7.4 ([#826](https://github.com/ionic-team/capacitor-plugins/issues/826)) ([5db0906](https://github.com/ionic-team/capacitor-plugins/commit/5db0906f6264287c4f8e69dbaecf19d4d387824b)) +* Use java 11 ([#910](https://github.com/ionic-team/capacitor-plugins/issues/910)) ([5acb2a2](https://github.com/ionic-team/capacitor-plugins/commit/5acb2a288a413492b163e4e97da46a085d9e4be0)) + + + + + +## [4.0.1](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0...4.0.1) (2022-07-28) + +**Note:** Version bump only for package @capacitor/geolocation + + + + + +# [4.0.0](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0-beta.2...4.0.0) (2022-07-27) + +**Note:** Version bump only for package @capacitor/geolocation + + + + + +# [4.0.0-beta.2](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0-beta.0...4.0.0-beta.2) (2022-07-08) + +**Note:** Version bump only for package @capacitor/geolocation + + + + + +# 4.0.0-beta.0 (2022-06-27) + + +### Bug Fixes + +* **geolocation:** reject checkPermissions / requestPermissions if location services are disabled ([#1053](https://github.com/ionic-team/capacitor-plugins/issues/1053)) ([774ec6e](https://github.com/ionic-team/capacitor-plugins/commit/774ec6e941193b1b06d07d31e6672340de532385)) +* **geolocation:** stop location requests on pause ([#1018](https://github.com/ionic-team/capacitor-plugins/issues/1018)) ([eb24f25](https://github.com/ionic-team/capacitor-plugins/commit/eb24f2521d05dd25a2087a1de2b3e0644568cda0)) +* add es2017 lib to tsconfig ([#180](https://github.com/ionic-team/capacitor-plugins/issues/180)) ([2c3776c](https://github.com/ionic-team/capacitor-plugins/commit/2c3776c38ca025c5ee965dec10ccf1cdb6c02e2f)) +* correct addListeners links ([#655](https://github.com/ionic-team/capacitor-plugins/issues/655)) ([f9871e7](https://github.com/ionic-team/capacitor-plugins/commit/f9871e7bd53478addb21155e148829f550c0e457)) +* inline source code in esm map files ([#760](https://github.com/ionic-team/capacitor-plugins/issues/760)) ([a960489](https://github.com/ionic-team/capacitor-plugins/commit/a960489a19db0182b90d187a50deff9dfbe51038)) +* remove postpublish scripts ([#656](https://github.com/ionic-team/capacitor-plugins/issues/656)) ([ed6ac49](https://github.com/ionic-team/capacitor-plugins/commit/ed6ac499ebf4a47525071ccbfc36c27503e11f60)) +* **geolocation:** Make getCurrentPosition return only once ([#470](https://github.com/ionic-team/capacitor-plugins/issues/470)) ([c5f1ceb](https://github.com/ionic-team/capacitor-plugins/commit/c5f1ceb790910b92e3f64d0b7fa8c85d48ea9841)) +* **geolocation:** Replace deprecated call.save with new keepAlive API ([#375](https://github.com/ionic-team/capacitor-plugins/issues/375)) ([e4e7cf4](https://github.com/ionic-team/capacitor-plugins/commit/e4e7cf4afd4a70bf48359c625fa7a548211876d5)) +* **geolocation:** return cached location if newer than maximumAge ([#639](https://github.com/ionic-team/capacitor-plugins/issues/639)) ([7b08eea](https://github.com/ionic-team/capacitor-plugins/commit/7b08eea9729bbf2b2b6b881cc81389cf108b3a2c)) +* **geolocation:** Use the new APIs for handling/saving calls ([#374](https://github.com/ionic-team/capacitor-plugins/issues/374)) ([ebd5b52](https://github.com/ionic-team/capacitor-plugins/commit/ebd5b527cb7f8b6c0016e82d03a0e84287913d3e)) +* support deprecated types from Capacitor 2 ([#139](https://github.com/ionic-team/capacitor-plugins/issues/139)) ([2d7127a](https://github.com/ionic-team/capacitor-plugins/commit/2d7127a488e26f0287951921a6db47c49d817336)) + + +### Features + +* set targetSDK default value to 31 ([#824](https://github.com/ionic-team/capacitor-plugins/issues/824)) ([3ee10de](https://github.com/ionic-team/capacitor-plugins/commit/3ee10de98067984c1a4e75295d001c5a895c47f4)) +* set targetSDK default value to 32 ([#970](https://github.com/ionic-team/capacitor-plugins/issues/970)) ([fa70d96](https://github.com/ionic-team/capacitor-plugins/commit/fa70d96f141af751aae53ceb5642c46b204f5958)) +* Upgrade gradle to 7.4 ([#826](https://github.com/ionic-team/capacitor-plugins/issues/826)) ([5db0906](https://github.com/ionic-team/capacitor-plugins/commit/5db0906f6264287c4f8e69dbaecf19d4d387824b)) +* Use java 11 ([#910](https://github.com/ionic-team/capacitor-plugins/issues/910)) ([5acb2a2](https://github.com/ionic-team/capacitor-plugins/commit/5acb2a288a413492b163e4e97da46a085d9e4be0)) +* **android:** implements Activity Result API changes for permissions and activity results ([#222](https://github.com/ionic-team/capacitor-plugins/issues/222)) ([f671b9f](https://github.com/ionic-team/capacitor-plugins/commit/f671b9f4b472806ef43db6dcf302d4503cf1828c)) +* **geolocation:** Add new alias for coarse location ([#684](https://github.com/ionic-team/capacitor-plugins/issues/684)) ([7563040](https://github.com/ionic-team/capacitor-plugins/commit/7563040983ad397e28616246e7ed5ffce69727c2)) +* **geolocation:** Error if Google Play Services are not available ([#709](https://github.com/ionic-team/capacitor-plugins/issues/709)) ([fc79c43](https://github.com/ionic-team/capacitor-plugins/commit/fc79c4319c54cbcd5dbbb7221dfdd03d0515805b)) +* **geolocation:** Throw error if location is disabled ([#589](https://github.com/ionic-team/capacitor-plugins/issues/589)) ([14724c5](https://github.com/ionic-team/capacitor-plugins/commit/14724c5ec5b23bf94f6f3511bbe204482768d10f)) +* add commonjs output format ([#179](https://github.com/ionic-team/capacitor-plugins/issues/179)) ([8e9e098](https://github.com/ionic-team/capacitor-plugins/commit/8e9e09862064b3f6771d7facbc4008e995d9b463)) +* Geolocation plugin ([#13](https://github.com/ionic-team/capacitor-plugins/issues/13)) ([911ae71](https://github.com/ionic-team/capacitor-plugins/commit/911ae71e6aef4cfa9fb3ab5b0c13f3c06ef6b15c)) + + + + + ## [1.3.1](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/geolocation@1.3.0...@capacitor/geolocation@1.3.1) (2022-01-19) diff --git a/geolocation/CapacitorGeolocation.podspec b/geolocation/CapacitorGeolocation.podspec index cf4aadb87..eda1cfe3b 100644 --- a/geolocation/CapacitorGeolocation.podspec +++ b/geolocation/CapacitorGeolocation.podspec @@ -11,7 +11,7 @@ Pod::Spec.new do |s| s.author = package['author'] s.source = { :git => 'https://github.com/ionic-team/capacitor-plugins.git', :tag => package['name'] + '@' + package['version'] } s.source_files = 'ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}', 'geolocation/ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}' - s.ios.deployment_target = '12.0' + s.ios.deployment_target = '13.0' s.dependency 'Capacitor' s.swift_version = '5.1' end diff --git a/geolocation/README.md b/geolocation/README.md index 01fbb8560..98eb01cc6 100644 --- a/geolocation/README.md +++ b/geolocation/README.md @@ -37,7 +37,7 @@ Read about [Setting Permissions](https://capacitorjs.com/docs/android/configurat This plugin will use the following project variables (defined in your app's `variables.gradle` file): -- `$playServicesLocationVersion` version of `com.google.android.gms:play-services-location` (default: `17.1.0`) +- `$playServicesLocationVersion` version of `com.google.android.gms:play-services-location` (default: `20.0.0`) ## Example @@ -131,7 +131,7 @@ Clear a given watch checkPermissions() => Promise ``` -Check location permissions +Check location permissions. Will throw if system location services are disabled. **Returns:** Promise<PermissionStatus> @@ -146,7 +146,7 @@ Check location permissions requestPermissions(permissions?: GeolocationPluginPermissions | undefined) => Promise ``` -Request location permissions +Request location permissions. Will throw if system location services are disabled. | Param | Type | | ----------------- | ------------------------------------------------------------------------------------- | @@ -175,7 +175,7 @@ Request location permissions | Prop | Type | Description | Default | Since | | ------------------------ | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------ | ----- | | **`enableHighAccuracy`** | boolean | High accuracy mode (such as GPS, if available) On Android 12+ devices it will be ignored if users didn't grant ACCESS_FINE_LOCATION permissions (can be checked with location alias). | false | 1.0.0 | -| **`timeout`** | number | The maximum wait time in milliseconds for location updates | 10000 | 1.0.0 | +| **`timeout`** | number | The maximum wait time in milliseconds for location updates. In Android, since version 4.0.0 of the plugin, timeout gets ignored for getCurrentPosition. | 10000 | 1.0.0 | | **`maximumAge`** | number | The maximum age in milliseconds of a possible cached position that is acceptable to return | 0 | 1.0.0 | diff --git a/geolocation/android/build.gradle b/geolocation/android/build.gradle index 08eabaf0b..5b443cb8d 100644 --- a/geolocation/android/build.gradle +++ b/geolocation/android/build.gradle @@ -1,27 +1,39 @@ ext { - junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.1' - androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.1.2' - androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.3.0' - playServicesLocationVersion = project.hasProperty('playServicesLocationVersion') ? rootProject.ext.playServicesLocationVersion : '17.1.0' + capacitorVersion = System.getenv('CAPACITOR_VERSION') + junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.2' + androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.1.3' + androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.4.0' + playServicesLocationVersion = project.hasProperty('playServicesLocationVersion') ? rootProject.ext.playServicesLocationVersion : '20.0.0' } buildscript { repositories { google() mavenCentral() + maven { + url "https://plugins.gradle.org/m2/" + } } dependencies { - classpath 'com.android.tools.build:gradle:4.2.1' + classpath 'com.android.tools.build:gradle:7.2.1' + if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + classpath 'io.github.gradle-nexus:publish-plugin:1.1.0' + } } } apply plugin: 'com.android.library' +if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + apply plugin: 'io.github.gradle-nexus.publish-plugin' + apply from: file('../../scripts/android/publish-root.gradle') + apply from: file('../../scripts/android/publish-module.gradle') +} android { - compileSdkVersion project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 30 + compileSdkVersion project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 32 defaultConfig { - minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 21 - targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 30 + minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 22 + targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 32 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" @@ -36,21 +48,26 @@ android { abortOnError false } compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility JavaVersion.VERSION_11 + targetCompatibility JavaVersion.VERSION_11 } } repositories { google() mavenCentral() - jcenter() } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation project(':capacitor-android') + + if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + implementation "com.capacitorjs:core:$capacitorVersion" + } else { + implementation project(':capacitor-android') + } + implementation "com.google.android.gms:play-services-location:$playServicesLocationVersion" testImplementation "junit:junit:$junitVersion" androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion" diff --git a/geolocation/android/gradle/wrapper/gradle-wrapper.jar b/geolocation/android/gradle/wrapper/gradle-wrapper.jar index e708b1c02..41d9927a4 100644 Binary files a/geolocation/android/gradle/wrapper/gradle-wrapper.jar and b/geolocation/android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/geolocation/android/gradle/wrapper/gradle-wrapper.properties b/geolocation/android/gradle/wrapper/gradle-wrapper.properties index 3c4101c3e..92f06b50f 100644 --- a/geolocation/android/gradle/wrapper/gradle-wrapper.properties +++ b/geolocation/android/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/geolocation/android/gradlew b/geolocation/android/gradlew index 4f906e0c8..1b6c78733 100755 --- a/geolocation/android/gradlew +++ b/geolocation/android/gradlew @@ -1,7 +1,7 @@ -#!/usr/bin/env sh +#!/bin/sh # -# Copyright 2015 the original author or authors. +# Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,67 +17,101 @@ # ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` +APP_BASE_NAME=${0##*/} # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar @@ -87,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -98,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" + JAVACMD=java which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the @@ -106,80 +140,95 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=`expr $i + 1` + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" diff --git a/geolocation/android/src/main/java/com/capacitorjs/plugins/geolocation/Geolocation.java b/geolocation/android/src/main/java/com/capacitorjs/plugins/geolocation/Geolocation.java index 5823d8d73..1d0644b54 100644 --- a/geolocation/android/src/main/java/com/capacitorjs/plugins/geolocation/Geolocation.java +++ b/geolocation/android/src/main/java/com/capacitorjs/plugins/geolocation/Geolocation.java @@ -12,6 +12,7 @@ import com.google.android.gms.location.LocationRequest; import com.google.android.gms.location.LocationResult; import com.google.android.gms.location.LocationServices; +import com.google.android.gms.location.Priority; public class Geolocation { @@ -24,50 +25,77 @@ public Geolocation(Context context) { this.context = context; } - public void sendLocation( - boolean enableHighAccuracy, - int timeout, - final boolean getCurrentPosition, - final LocationResultCallback resultCallback - ) { - requestLocationUpdates(enableHighAccuracy, timeout, getCurrentPosition, resultCallback); + public Boolean isLocationServicesEnabled() { + LocationManager lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); + return LocationManagerCompat.isLocationEnabled(lm); } @SuppressWarnings("MissingPermission") - public void requestLocationUpdates( - boolean enableHighAccuracy, - int timeout, - final boolean getCurrentPosition, - final LocationResultCallback resultCallback - ) { + public void sendLocation(boolean enableHighAccuracy, final LocationResultCallback resultCallback) { + int resultCode = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(context); + if (resultCode == ConnectionResult.SUCCESS) { + LocationManager lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); + + if (this.isLocationServicesEnabled()) { + boolean networkEnabled = false; + + try { + networkEnabled = lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER); + } catch (Exception ex) {} + + int lowPriority = networkEnabled ? Priority.PRIORITY_BALANCED_POWER_ACCURACY : Priority.PRIORITY_LOW_POWER; + int priority = enableHighAccuracy ? Priority.PRIORITY_HIGH_ACCURACY : lowPriority; + + LocationServices + .getFusedLocationProviderClient(context) + .getCurrentLocation(priority, null) + .addOnFailureListener(e -> resultCallback.error(e.getMessage())) + .addOnSuccessListener( + location -> { + if (location == null) { + resultCallback.error("location unavailable"); + } else { + resultCallback.success(location); + } + } + ); + } else { + resultCallback.error("location disabled"); + } + } else { + resultCallback.error("Google Play Services not available"); + } + } + + @SuppressWarnings("MissingPermission") + public void requestLocationUpdates(boolean enableHighAccuracy, int timeout, final LocationResultCallback resultCallback) { int resultCode = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(context); if (resultCode == ConnectionResult.SUCCESS) { clearLocationUpdates(); fusedLocationClient = LocationServices.getFusedLocationProviderClient(context); LocationManager lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); - if (LocationManagerCompat.isLocationEnabled(lm)) { + if (this.isLocationServicesEnabled()) { boolean networkEnabled = false; try { networkEnabled = lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER); } catch (Exception ex) {} - LocationRequest locationRequest = new LocationRequest(); - locationRequest.setMaxWaitTime(timeout); - locationRequest.setInterval(10000); - locationRequest.setFastestInterval(5000); - int lowPriority = networkEnabled ? LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY : LocationRequest.PRIORITY_LOW_POWER; - int priority = enableHighAccuracy ? LocationRequest.PRIORITY_HIGH_ACCURACY : lowPriority; - locationRequest.setPriority(priority); + int lowPriority = networkEnabled ? Priority.PRIORITY_BALANCED_POWER_ACCURACY : Priority.PRIORITY_LOW_POWER; + int priority = enableHighAccuracy ? Priority.PRIORITY_HIGH_ACCURACY : lowPriority; + + LocationRequest locationRequest = LocationRequest + .create() + .setMaxWaitTime(timeout) + .setInterval(10000) + .setFastestInterval(5000) + .setPriority(priority); locationCallback = new LocationCallback() { @Override public void onLocationResult(LocationResult locationResult) { - if (getCurrentPosition) { - clearLocationUpdates(); - } Location lastLocation = locationResult.getLastLocation(); if (lastLocation == null) { resultCallback.error("location unavailable"); diff --git a/geolocation/android/src/main/java/com/capacitorjs/plugins/geolocation/GeolocationPlugin.java b/geolocation/android/src/main/java/com/capacitorjs/plugins/geolocation/GeolocationPlugin.java index 022fada70..84514a682 100644 --- a/geolocation/android/src/main/java/com/capacitorjs/plugins/geolocation/GeolocationPlugin.java +++ b/geolocation/android/src/main/java/com/capacitorjs/plugins/geolocation/GeolocationPlugin.java @@ -36,6 +36,41 @@ public void load() { implementation = new Geolocation(getContext()); } + @Override + protected void handleOnPause() { + super.handleOnPause(); + // Clear all location updates on pause to avoid possible background location calls + implementation.clearLocationUpdates(); + } + + @Override + protected void handleOnResume() { + super.handleOnResume(); + for (PluginCall call : watchingCalls.values()) { + startWatch(call); + } + } + + @Override + @PluginMethod + public void checkPermissions(PluginCall call) { + if (implementation.isLocationServicesEnabled()) { + super.checkPermissions(call); + } else { + call.reject("Location services are not enabled"); + } + } + + @Override + @PluginMethod + public void requestPermissions(PluginCall call) { + if (implementation.isLocationServicesEnabled()) { + super.requestPermissions(call); + } else { + call.reject("Location services are not enabled"); + } + } + /** * Gets a snapshot of the current device position if permission is granted. The call continues * in the {@link #completeCurrentPosition(PluginCall)} method if a permission request is required. @@ -60,12 +95,8 @@ public void getCurrentPosition(final PluginCall call) { @PermissionCallback private void completeCurrentPosition(PluginCall call) { if (getPermissionState(GeolocationPlugin.COARSE_LOCATION) == PermissionState.GRANTED) { - int timeout = call.getInt("timeout", 10000); - implementation.sendLocation( isHighAccuracy(call), - timeout, - true, new LocationResultCallback() { @Override public void success(Location location) { @@ -116,7 +147,6 @@ private void completeWatchPosition(PluginCall call) { @SuppressWarnings("MissingPermission") private void getPosition(PluginCall call) { - int timeout = call.getInt("timeout", 10000); int maximumAge = call.getInt("maximumAge", 0); Location location = implementation.getLastLocation(maximumAge); if (location != null) { @@ -124,8 +154,6 @@ private void getPosition(PluginCall call) { } else { implementation.sendLocation( isHighAccuracy(call), - timeout, - true, new LocationResultCallback() { @Override public void success(Location location) { @@ -148,7 +176,6 @@ private void startWatch(final PluginCall call) { implementation.requestLocationUpdates( isHighAccuracy(call), timeout, - false, new LocationResultCallback() { @Override public void success(Location location) { @@ -200,7 +227,7 @@ private JSObject getJSObjectForLocation(Location location) { coords.put("longitude", location.getLongitude()); coords.put("accuracy", location.getAccuracy()); coords.put("altitude", location.getAltitude()); - if (Build.VERSION.SDK_INT >= 26) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { coords.put("altitudeAccuracy", location.getVerticalAccuracyMeters()); } coords.put("speed", location.getSpeed()); @@ -210,8 +237,7 @@ private JSObject getJSObjectForLocation(Location location) { private String getAlias(PluginCall call) { String alias = GeolocationPlugin.LOCATION; - // TODO replace with Build.VERSION_CODES.S once we target SDK 31 - if (Build.VERSION.SDK_INT >= 31) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { boolean enableHighAccuracy = call.getBoolean("enableHighAccuracy", false); if (!enableHighAccuracy) { alias = GeolocationPlugin.COARSE_LOCATION; diff --git a/geolocation/ios/Plugin.xcodeproj/project.pbxproj b/geolocation/ios/Plugin.xcodeproj/project.pbxproj index 0672d4995..6aff3e4f8 100644 --- a/geolocation/ios/Plugin.xcodeproj/project.pbxproj +++ b/geolocation/ios/Plugin.xcodeproj/project.pbxproj @@ -382,7 +382,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -442,7 +442,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; @@ -465,12 +465,13 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Plugin/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks $(FRAMEWORK_SEARCH_PATHS)\n$(FRAMEWORK_SEARCH_PATHS)\n$(FRAMEWORK_SEARCH_PATHS)"; ONLY_ACTIVE_ARCH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.getcapacitor.Plugin; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; + SUPPORTS_MACCATALYST = NO; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -490,12 +491,13 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Plugin/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks $(FRAMEWORK_SEARCH_PATHS)"; ONLY_ACTIVE_ARCH = NO; PRODUCT_BUNDLE_IDENTIFIER = com.getcapacitor.Plugin; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; + SUPPORTS_MACCATALYST = NO; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; diff --git a/geolocation/ios/Podfile b/geolocation/ios/Podfile index 54a00c161..dee40960f 100644 --- a/geolocation/ios/Podfile +++ b/geolocation/ios/Podfile @@ -1,4 +1,4 @@ -platform :ios, '12.0' +platform :ios, '13.0' def capacitor_pods # Comment the next line if you're not using Swift and don't want to use dynamic frameworks diff --git a/geolocation/package.json b/geolocation/package.json index f20bbb8a9..7fef5c6da 100644 --- a/geolocation/package.json +++ b/geolocation/package.json @@ -1,6 +1,6 @@ { "name": "@capacitor/geolocation", - "version": "1.3.1", + "version": "4.1.0", "description": "The Geolocation API provides simple methods for getting and tracking the current position of the device using GPS, along with altitude, heading, and speed information if available.", "main": "dist/plugin.cjs.js", "module": "dist/esm/index.js", @@ -29,7 +29,7 @@ ], "scripts": { "verify": "npm run verify:ios && npm run verify:android && npm run verify:web", - "verify:ios": "cd ios && pod install && xcodebuild -workspace Plugin.xcworkspace -scheme Plugin && cd ..", + "verify:ios": "cd ios && pod install && xcodebuild -workspace Plugin.xcworkspace -scheme Plugin -destination generic/platform=iOS && cd ..", "verify:android": "cd android && ./gradlew clean build test && cd ..", "verify:web": "npm run build", "lint": "npm run eslint && npm run prettier -- --check && npm run swiftlint -- lint", @@ -45,10 +45,10 @@ "publish:cocoapod": "pod trunk push ./CapacitorGeolocation.podspec --allow-warnings" }, "devDependencies": { - "@capacitor/android": "^3.0.0", - "@capacitor/core": "^3.0.0", - "@capacitor/docgen": "0.0.18", - "@capacitor/ios": "^3.0.0", + "@capacitor/android": "^4.0.0", + "@capacitor/core": "^4.0.0", + "@capacitor/docgen": "0.2.0", + "@capacitor/ios": "^4.0.0", "@ionic/eslint-config": "^0.3.0", "@ionic/prettier-config": "~1.0.1", "@ionic/swiftlint-config": "^1.1.2", @@ -61,7 +61,7 @@ "typescript": "~4.1.5" }, "peerDependencies": { - "@capacitor/core": "^3.0.0" + "@capacitor/core": "^4.0.0" }, "prettier": "@ionic/prettier-config", "swiftlint": "@ionic/swiftlint-config", diff --git a/geolocation/src/definitions.ts b/geolocation/src/definitions.ts index 69dca9354..94fd9b61f 100644 --- a/geolocation/src/definitions.ts +++ b/geolocation/src/definitions.ts @@ -64,14 +64,14 @@ export interface GeolocationPlugin { clearWatch(options: ClearWatchOptions): Promise; /** - * Check location permissions + * Check location permissions. Will throw if system location services are disabled. * * @since 1.0.0 */ checkPermissions(): Promise; /** - * Request location permissions + * Request location permissions. Will throw if system location services are disabled. * * @since 1.0.0 */ @@ -164,7 +164,9 @@ export interface PositionOptions { enableHighAccuracy?: boolean; /** - * The maximum wait time in milliseconds for location updates + * The maximum wait time in milliseconds for location updates. + * + * In Android, since version 4.0.0 of the plugin, timeout gets ignored for getCurrentPosition. * * @default 10000 * @since 1.0.0 diff --git a/google-maps/.eslintignore b/google-maps/.eslintignore new file mode 100644 index 000000000..179ca25ab --- /dev/null +++ b/google-maps/.eslintignore @@ -0,0 +1,4 @@ +build +dist +e2e-tests +unit-tests \ No newline at end of file diff --git a/google-maps/.gitignore b/google-maps/.gitignore new file mode 100644 index 000000000..482d6d236 --- /dev/null +++ b/google-maps/.gitignore @@ -0,0 +1,62 @@ +# node files +dist +node_modules + +# iOS files +Pods +Podfile.lock +Build +xcuserdata + +# macOS files +.DS_Store + + + +# Based on Android gitignore template: https://github.com/github/gitignore/blob/HEAD/Android.gitignore + +# Built application files +*.apk +*.ap_ + +# Files for the ART/Dalvik VM +*.dex + +# Java class files +*.class + +# Generated files +bin +gen +out + +# Gradle files +.gradle +build + +# Local configuration file (sdk path, etc) +local.properties + +# Proguard folder generated by Eclipse +proguard + +# Log Files +*.log + +# Android Studio Navigation editor temp files +.navigation + +# Android Studio captures folder +captures + +# IntelliJ +*.iml +.idea + +# Keystore files +# Uncomment the following line if you do not want to check your keystore files in. +#*.jks + +# External native build folder generated in Android Studio 2.2 and later +.externalNativeBuild +*.tgz diff --git a/google-maps/.prettierignore b/google-maps/.prettierignore new file mode 100644 index 000000000..1cb23c439 --- /dev/null +++ b/google-maps/.prettierignore @@ -0,0 +1,4 @@ +build +dist +e2e-tests +unit-tests diff --git a/google-maps/CHANGELOG.md b/google-maps/CHANGELOG.md new file mode 100644 index 000000000..a73753f88 --- /dev/null +++ b/google-maps/CHANGELOG.md @@ -0,0 +1,136 @@ +# Change Log + +All notable changes to this project will be documented in this file. +See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [4.3.1](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/google-maps@4.3.0...@capacitor/google-maps@4.3.1) (2022-11-16) + + +### Bug Fixes + +* **google-maps:** install google.maps types as dependency ([#1269](https://github.com/ionic-team/capacitor-plugins/issues/1269)) ([6cc7783](https://github.com/ionic-team/capacitor-plugins/commit/6cc77835d301f9c7734ae8a25dd0fc08ea91c74a)) +* **google-maps:** Remove log of marker options ([#1247](https://github.com/ionic-team/capacitor-plugins/issues/1247)) ([5bb3000](https://github.com/ionic-team/capacitor-plugins/commit/5bb30005df075ce1679695792e33f398eee298c4)) +* **google-maps:** Retry getting the map size if it's 0 ([#1252](https://github.com/ionic-team/capacitor-plugins/issues/1252)) ([9bffdb5](https://github.com/ionic-team/capacitor-plugins/commit/9bffdb529f41cadc2e5a33c4a09d5ebfacf4baed)) + + + + + +# [4.3.0](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/google-maps@4.2.1...@capacitor/google-maps@4.3.0) (2022-10-21) + + +### Bug Fixes + +* **google-maps:** allow remote marker icons on native platforms ([#1216](https://github.com/ionic-team/capacitor-plugins/issues/1216)) ([8b4de64](https://github.com/ionic-team/capacitor-plugins/commit/8b4de6435decf5d37c29ac6d543191f32b5a6c6e)) +* **google-maps:** allow to resize icons with same image ([#1228](https://github.com/ionic-team/capacitor-plugins/issues/1228)) ([f6522d3](https://github.com/ionic-team/capacitor-plugins/commit/f6522d37c1418933207ee9a54d08222fcf264334)) +* **google-maps:** event listeners not firing when clustering enabled ([dd80da2](https://github.com/ionic-team/capacitor-plugins/commit/dd80da263ba684463fa35c9cff3a237ffd257058)) + + +### Features + +* **google-maps:** Add more config options ([#1233](https://github.com/ionic-team/capacitor-plugins/issues/1233)) ([8bebf97](https://github.com/ionic-team/capacitor-plugins/commit/8bebf9745f6538d4bc7f1622b2b4a0317f306bfb)) + + + + + +## [4.2.1](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/google-maps@4.2.0...@capacitor/google-maps@4.2.1) (2022-09-29) + + +### Bug Fixes + +* **google-maps:** adding missing marker draggable property for web ([#1184](https://github.com/ionic-team/capacitor-plugins/issues/1184)) ([2eb0e7e](https://github.com/ionic-team/capacitor-plugins/commit/2eb0e7e6db9d3f6a684d2c9a0e2e7ec94d5dfa63)) +* **google-maps:** onClusterClickHandler not getting marker ids on web ([#1039](https://github.com/ionic-team/capacitor-plugins/issues/1039)) ([b04e32d](https://github.com/ionic-team/capacitor-plugins/commit/b04e32d6fcab39285ba6dbe49408e001177cf13f)) + + + + + +# [4.2.0](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/google-maps@4.1.0...@capacitor/google-maps@4.2.0) (2022-09-12) + + +### Features + +* **google-maps:** Marker Customization Options ([#1146](https://github.com/ionic-team/capacitor-plugins/issues/1146)) ([bb77432](https://github.com/ionic-team/capacitor-plugins/commit/bb77432ac28ec5de5c5d2584f4f2ccf874e5c197)) +* **google-maps:** Marker Drag Listeners ([833f28d](https://github.com/ionic-team/capacitor-plugins/commit/833f28dc8e28553673c861619a2ac9540f39e33a)) + + + + + +# [4.1.0](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/google-maps@1.1.0...@capacitor/google-maps@4.1.0) (2022-08-24) + + +### Bug Fixes + +* **google-maps:** Check for WKScrollView and WKChildScrollView ([#1109](https://github.com/ionic-team/capacitor-plugins/issues/1109)) ([7513602](https://github.com/ionic-team/capacitor-plugins/commit/7513602c6c9830de305e6097db3023e42a8afa30)) + + + + + +## [4.0.1](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0...4.0.1) (2022-07-28) + +**Note:** Version bump only for package @capacitor/google-maps + + + + + +# [4.0.0](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0-beta.2...4.0.0) (2022-07-27) + +**Note:** Version bump only for package @capacitor/google-maps + + + + + +# [4.0.0-beta.2](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0-beta.0...4.0.0-beta.2) (2022-07-08) + + +### Features + +* **google-maps:** provides variables for configuring dependencies ([#1063](https://github.com/ionic-team/capacitor-plugins/issues/1063)) ([5c077f1](https://github.com/ionic-team/capacitor-plugins/commit/5c077f199cbd16b459a77061509e0504029f78db)) + + + + + +# 4.0.0-beta.0 (2022-06-27) + + +### Bug Fixes + +* **google-maps:** correctly typed event listeners ([656f916](https://github.com/ionic-team/capacitor-plugins/commit/656f9169ccd8d7fa880143b13ca5f62bb546edb0)) +* **google-maps:** Fixing map touch events on Android ([7cb89fb](https://github.com/ionic-team/capacitor-plugins/commit/7cb89fb788e05aa9e90c39698e041ebe094132ea)) + + +### Features + +* **google-maps:** Google Maps Bounds ([14a045d](https://github.com/ionic-team/capacitor-plugins/commit/14a045d3880124996b2770cec7b3e28a9f13d231)) + + + + + +# 1.1.0 (2022-06-17) + + +### Bug Fixes + +* **google-maps:** correctly typed event listeners ([656f916](https://github.com/ionic-team/capacitor-plugins/commit/656f9169ccd8d7fa880143b13ca5f62bb546edb0)) +* **google-maps:** Fixing map touch events on Android ([7cb89fb](https://github.com/ionic-team/capacitor-plugins/commit/7cb89fb788e05aa9e90c39698e041ebe094132ea)) + + +### Features + +* **google-maps:** Google Maps Bounds ([14a045d](https://github.com/ionic-team/capacitor-plugins/commit/14a045d3880124996b2770cec7b3e28a9f13d231)) + + + + + + +# [1.0.0](https://github.com/ionic-team/capacitor-plugins/tree/main/google-maps) (2022-04-28) + +**Note:** Version bump only for package @capacitor/google-maps diff --git a/google-maps/CapacitorGoogleMaps.podspec b/google-maps/CapacitorGoogleMaps.podspec new file mode 100644 index 000000000..8526424ca --- /dev/null +++ b/google-maps/CapacitorGoogleMaps.podspec @@ -0,0 +1,20 @@ +require 'json' + +package = JSON.parse(File.read(File.join(__dir__, 'package.json'))) + +Pod::Spec.new do |s| + s.name = 'CapacitorGoogleMaps' + s.version = package['version'] + s.summary = package['description'] + s.license = package['license'] + s.homepage = 'https://capacitorjs.com' + s.author = package['author'] + s.source = { :git => 'https://github.com/ionic-team/capacitor-plugins.git', :tag => package['name'] + '@' + package['version'] } + s.source_files = 'ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}', 'google-maps/ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}' + s.ios.deployment_target = '13.0' + s.dependency 'Capacitor' + s.dependency 'GoogleMaps', '~> 6.0.0' + s.dependency 'Google-Maps-iOS-Utils', '~> 4.1.0' + s.swift_version = '5.1' + s.static_framework = true +end diff --git a/google-maps/README.md b/google-maps/README.md new file mode 100644 index 000000000..ff6633ebc --- /dev/null +++ b/google-maps/README.md @@ -0,0 +1,881 @@ +# @capacitor/google-maps + +Google maps on Capacitor + +## Install + +```bash +npm install @capacitor/google-maps +npx cap sync +``` + +## API Keys + +To use the Google Maps SDK on any platform, API keys associated with an account _with billing enabled_ are required. These can be obtained from the [Google Cloud Console](https://console.cloud.google.com). This is required for all three platforms, Android, iOS, and Javascript. Additional information about obtaining these API keys can be found in the [Google Maps documentation](https://developers.google.com/maps/documentation/android-sdk/overview) for each platform. + +## iOS + +The Google Maps SDK supports the use of showing the users current location via `enableCurrentLocation(bool)`. To use this, Apple requires privacy descriptions to be specified in `Info.plist`: + +- `NSLocationAlwaysUsageDescription` (`Privacy - Location Always Usage Description`) +- `NSLocationWhenInUseUsageDescription` (`Privacy - Location When In Use Usage Description`) + +Read about [Configuring `Info.plist`](https://capacitorjs.com/docs/ios/configuration#configuring-infoplist) in the [iOS Guide](https://capacitorjs.com/docs/ios) for more information on setting iOS permissions in Xcode. + +> The Google Maps SDK currently does not support running on simulators using the new M1-based Macbooks. This is a [known and acknowledged issue](https://developers.google.com/maps/faq#arm-based-macs) and requires a fix from Google. If you are developing on a M1 Macbook, building and running on physical devices is still supported and is the recommended approach. + +## Android + +The Google Maps SDK for Android requires you to add your API key to the AndroidManifest.xml file in your project. + +```xml + +``` + +To use certain location features, the SDK requires the following permissions to also be added to your AndroidManifest.xml: + +```xml + + +``` + +### Variables + +This plugin will use the following project variables (defined in your app's `variables.gradle` file): + +- `$googleMapsPlayServicesVersion`: version of `com.google.android.gms:play-services-maps` (default: `18.0.2`) +- `$googleMapsUtilsVersion`: version of `com.google.maps.android:android-maps-utils` (default: `2.3.0`) +- `$googleMapsKtxVersion`: version of `com.google.maps.android:maps-ktx` (default: `3.4.0`) +- `$googleMapsUtilsKtxVersion`: version of `com.google.maps.android:maps-utils-ktx` (default: `3.4.0`) +- `$kotlinxCoroutinesVersion`: version of `org.jetbrains.kotlinx:kotlinx-coroutines-android` and `org.jetbrains.kotlinx:kotlinx-coroutines-core` (default: `1.6.3`) +- `$androidxCoreKTXVersion`: version of `androidx.core:core-ktx` (default: `1.8.0`) +- `$kotlin_version`: version of `org.jetbrains.kotlin:kotlin-stdlib-jdk7` (default: `1.7.0`) + + +## Usage + +The Google Maps Capacitor plugin ships with a web component that must be used to render the map in your application as it enables us to embed the native view more effectively on iOS. The plugin will automatically register this web component for use in your application. + +> For Angular users, you will get an error warning that this web component is unknown to the Angular compiler. This is resolved by modifying the module that declares your component to allow for custom web components. +> +> ```typescript +> import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; +> +> @NgModule({ +> schemas: [CUSTOM_ELEMENTS_SCHEMA] +> }) +> ``` + +Include this component in your HTML and assign it an ID so that you can easily query for that element reference later. + +```html + +``` + +> On Android, the map is rendered beneath the entire webview, and uses this component to manage its positioning during scrolling events. This means that as the developer, you _must_ ensure that the webview is transparent all the way through the layers to the very bottom. In a typically Ionic application, that means setting transparency on elements such as IonContent and the root HTML tag to ensure that it can be seen. If you can't see your map on Android, this should be the first thing you check. +> +> On iOS, we render the map directly into the webview and so the same transparency effects are not required. We are investigating alternate methods for Android still and hope to resolve this better in a future update. + +The Google Map element itself comes unstyled, so you should style it to fit within the layout of your page structure. Because we're rendering a view into this slot, by itself the element has no width or height, so be sure to set those explicitly. + +```css +capacitor-google-map { + display: inline-block; + width: 275px; + height: 400px; +} +``` + +Next, we should create the map reference. This is done by importing the GoogleMap class from the Capacitor plugin and calling the create method, and passing in the required parameters. + +```typescript +import { GoogleMap } from '@capacitor/google-maps'; + +const apiKey = 'YOUR_API_KEY_HERE'; + +const mapRef = document.getElementById('map'); + +const newMap = await GoogleMap.create({ + id: 'my-map', // Unique identifier for this map instance + element: mapRef, // reference to the capacitor-google-map element + apiKey: apiKey, // Your Google Maps API Key + config: { + center: { + // The initial position to be rendered by the map + lat: 33.6, + lng: -117.9, + }, + zoom: 8, // The initial zoom level to be rendered by the map + }, +}); +``` + +At this point, your map should be created within your application. Using the returned reference to the map, you can easily interact with your map in a number of way, a few of which are shown here. + +```typescript +const newMap = await GoogleMap.create({...}); + +// Add a marker to the map +const markerId = await newMap.addMarker({ + coordinate: { + lat: 33.6, + lng: -117.9 + } +}); + +// Move the map programmatically +await newMap.setCamera({ + coordinate: { + lat: 33.6, + lng: -117.9 + } +}); + +// Enable marker clustering +await newMap.enableClustering(); + +// Handle marker click +await newMap.setOnMarkerClickListener((event) => {...}); + +// Clean up map reference +await newMap.destroy(); +``` + +## Full Examples + +### Angular + +```typescript +import { GoogleMap } from '@capacitor/google-maps'; + +@Component({ + template: ` + + + `, + styles: [ + ` + capacitor-google-map { + display: inline-block; + width: 275px; + height: 400px; + } + `, + ], +}) +export class MyMap { + @ViewChild('map') + mapRef: ElementRef; + newMap: GoogleMap; + + async createMap() { + this.newMap = await GoogleMap.create({ + id: 'my-cool-map', + element: this.mapRef.nativeElement, + apiKey: environment.apiKey, + config: { + center: { + lat: 33.6, + lng: -117.9, + }, + zoom: 8, + }, + }); + } +} +``` + +### React + +```jsx +import { GoogleMap } from '@capacitor/google-maps'; +import { useRef } from 'react'; + +const MyMap: React.FC = () => { + const mapRef = useRef(); + let newMap: GoogleMap; + + async function createMap() { + if (!mapRef.current) return; + + newMap = await GoogleMap.create({ + id: 'my-cool-map', + element: mapRef.current, + apiKey: process.env.REACT_APP_YOUR_API_KEY_HERE, + config: { + center: { + lat: 33.6, + lng: -117.9 + }, + zoom: 8 + } + }) + } + + return ( +
+ + + +
+ ) +} + +export default MyMap; +``` + +### Javascript + +```html + + + + + + +``` + +## API + + + +* [`create(...)`](#create) +* [`enableClustering()`](#enableclustering) +* [`disableClustering()`](#disableclustering) +* [`addMarker(...)`](#addmarker) +* [`addMarkers(...)`](#addmarkers) +* [`removeMarker(...)`](#removemarker) +* [`removeMarkers(...)`](#removemarkers) +* [`destroy()`](#destroy) +* [`setCamera(...)`](#setcamera) +* [`setMapType(...)`](#setmaptype) +* [`enableIndoorMaps(...)`](#enableindoormaps) +* [`enableTrafficLayer(...)`](#enabletrafficlayer) +* [`enableAccessibilityElements(...)`](#enableaccessibilityelements) +* [`enableCurrentLocation(...)`](#enablecurrentlocation) +* [`setPadding(...)`](#setpadding) +* [`setOnBoundsChangedListener(...)`](#setonboundschangedlistener) +* [`setOnCameraIdleListener(...)`](#setoncameraidlelistener) +* [`setOnCameraMoveStartedListener(...)`](#setoncameramovestartedlistener) +* [`setOnClusterClickListener(...)`](#setonclusterclicklistener) +* [`setOnClusterInfoWindowClickListener(...)`](#setonclusterinfowindowclicklistener) +* [`setOnInfoWindowClickListener(...)`](#setoninfowindowclicklistener) +* [`setOnMapClickListener(...)`](#setonmapclicklistener) +* [`setOnMarkerClickListener(...)`](#setonmarkerclicklistener) +* [`setOnMarkerDragStartListener(...)`](#setonmarkerdragstartlistener) +* [`setOnMarkerDragListener(...)`](#setonmarkerdraglistener) +* [`setOnMarkerDragEndListener(...)`](#setonmarkerdragendlistener) +* [`setOnMyLocationButtonClickListener(...)`](#setonmylocationbuttonclicklistener) +* [`setOnMyLocationClickListener(...)`](#setonmylocationclicklistener) +* [Interfaces](#interfaces) +* [Type Aliases](#type-aliases) +* [Enums](#enums) + + + + + + +### create(...) + +```typescript +create(options: CreateMapArgs, callback?: MapListenerCallback | undefined) => Promise +``` + +| Param | Type | +| -------------- | ----------------------------------------------------------------------------------------------------------------------------------- | +| **`options`** | CreateMapArgs | +| **`callback`** | MapListenerCallback<MapReadyCallbackData> | + +**Returns:** Promise<GoogleMap> + +-------------------- + + +### enableClustering() + +```typescript +enableClustering() => Promise +``` + +-------------------- + + +### disableClustering() + +```typescript +disableClustering() => Promise +``` + +-------------------- + + +### addMarker(...) + +```typescript +addMarker(marker: Marker) => Promise +``` + +| Param | Type | +| ------------ | ----------------------------------------- | +| **`marker`** | Marker | + +**Returns:** Promise<string> + +-------------------- + + +### addMarkers(...) + +```typescript +addMarkers(markers: Marker[]) => Promise +``` + +| Param | Type | +| ------------- | --------------------- | +| **`markers`** | Marker[] | + +**Returns:** Promise<string[]> + +-------------------- + + +### removeMarker(...) + +```typescript +removeMarker(id: string) => Promise +``` + +| Param | Type | +| -------- | ------------------- | +| **`id`** | string | + +-------------------- + + +### removeMarkers(...) + +```typescript +removeMarkers(ids: string[]) => Promise +``` + +| Param | Type | +| --------- | --------------------- | +| **`ids`** | string[] | + +-------------------- + + +### destroy() + +```typescript +destroy() => Promise +``` + +-------------------- + + +### setCamera(...) + +```typescript +setCamera(config: CameraConfig) => Promise +``` + +| Param | Type | +| ------------ | ----------------------------------------------------- | +| **`config`** | CameraConfig | + +-------------------- + + +### setMapType(...) + +```typescript +setMapType(mapType: MapType) => Promise +``` + +| Param | Type | +| ------------- | ------------------------------------------- | +| **`mapType`** | MapType | + +-------------------- + + +### enableIndoorMaps(...) + +```typescript +enableIndoorMaps(enabled: boolean) => Promise +``` + +| Param | Type | +| ------------- | -------------------- | +| **`enabled`** | boolean | + +-------------------- + + +### enableTrafficLayer(...) + +```typescript +enableTrafficLayer(enabled: boolean) => Promise +``` + +| Param | Type | +| ------------- | -------------------- | +| **`enabled`** | boolean | + +-------------------- + + +### enableAccessibilityElements(...) + +```typescript +enableAccessibilityElements(enabled: boolean) => Promise +``` + +| Param | Type | +| ------------- | -------------------- | +| **`enabled`** | boolean | + +-------------------- + + +### enableCurrentLocation(...) + +```typescript +enableCurrentLocation(enabled: boolean) => Promise +``` + +| Param | Type | +| ------------- | -------------------- | +| **`enabled`** | boolean | + +-------------------- + + +### setPadding(...) + +```typescript +setPadding(padding: MapPadding) => Promise +``` + +| Param | Type | +| ------------- | ------------------------------------------------- | +| **`padding`** | MapPadding | + +-------------------- + + +### setOnBoundsChangedListener(...) + +```typescript +setOnBoundsChangedListener(callback?: MapListenerCallback | undefined) => Promise +``` + +| Param | Type | +| -------------- | --------------------------------------------------------------------------------------------------------------------------------------- | +| **`callback`** | MapListenerCallback<CameraIdleCallbackData> | + +-------------------- + + +### setOnCameraIdleListener(...) + +```typescript +setOnCameraIdleListener(callback?: MapListenerCallback | undefined) => Promise +``` + +| Param | Type | +| -------------- | --------------------------------------------------------------------------------------------------------------------------------------- | +| **`callback`** | MapListenerCallback<CameraIdleCallbackData> | + +-------------------- + + +### setOnCameraMoveStartedListener(...) + +```typescript +setOnCameraMoveStartedListener(callback?: MapListenerCallback | undefined) => Promise +``` + +| Param | Type | +| -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | +| **`callback`** | MapListenerCallback<CameraMoveStartedCallbackData> | + +-------------------- + + +### setOnClusterClickListener(...) + +```typescript +setOnClusterClickListener(callback?: MapListenerCallback | undefined) => Promise +``` + +| Param | Type | +| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | +| **`callback`** | MapListenerCallback<ClusterClickCallbackData> | + +-------------------- + + +### setOnClusterInfoWindowClickListener(...) + +```typescript +setOnClusterInfoWindowClickListener(callback?: MapListenerCallback | undefined) => Promise +``` + +| Param | Type | +| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | +| **`callback`** | MapListenerCallback<ClusterClickCallbackData> | + +-------------------- + + +### setOnInfoWindowClickListener(...) + +```typescript +setOnInfoWindowClickListener(callback?: MapListenerCallback | undefined) => Promise +``` + +| Param | Type | +| -------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | +| **`callback`** | MapListenerCallback<MarkerClickCallbackData> | + +-------------------- + + +### setOnMapClickListener(...) + +```typescript +setOnMapClickListener(callback?: MapListenerCallback | undefined) => Promise +``` + +| Param | Type | +| -------------- | ----------------------------------------------------------------------------------------------------------------------------------- | +| **`callback`** | MapListenerCallback<MapClickCallbackData> | + +-------------------- + + +### setOnMarkerClickListener(...) + +```typescript +setOnMarkerClickListener(callback?: MapListenerCallback | undefined) => Promise +``` + +| Param | Type | +| -------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | +| **`callback`** | MapListenerCallback<MarkerClickCallbackData> | + +-------------------- + + +### setOnMarkerDragStartListener(...) + +```typescript +setOnMarkerDragStartListener(callback?: MapListenerCallback | undefined) => Promise +``` + +| Param | Type | +| -------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | +| **`callback`** | MapListenerCallback<MarkerClickCallbackData> | + +-------------------- + + +### setOnMarkerDragListener(...) + +```typescript +setOnMarkerDragListener(callback?: MapListenerCallback | undefined) => Promise +``` + +| Param | Type | +| -------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | +| **`callback`** | MapListenerCallback<MarkerClickCallbackData> | + +-------------------- + + +### setOnMarkerDragEndListener(...) + +```typescript +setOnMarkerDragEndListener(callback?: MapListenerCallback | undefined) => Promise +``` + +| Param | Type | +| -------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | +| **`callback`** | MapListenerCallback<MarkerClickCallbackData> | + +-------------------- + + +### setOnMyLocationButtonClickListener(...) + +```typescript +setOnMyLocationButtonClickListener(callback?: MapListenerCallback | undefined) => Promise +``` + +| Param | Type | +| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **`callback`** | MapListenerCallback<MyLocationButtonClickCallbackData> | + +-------------------- + + +### setOnMyLocationClickListener(...) + +```typescript +setOnMyLocationClickListener(callback?: MapListenerCallback | undefined) => Promise +``` + +| Param | Type | +| -------------- | ----------------------------------------------------------------------------------------------------------------------------------- | +| **`callback`** | MapListenerCallback<MapClickCallbackData> | + +-------------------- + + +### Interfaces + + +#### CreateMapArgs + +An interface containing the options used when creating a map. + +| Prop | Type | Description | Default | +| ----------------- | ----------------------------------------------------------- | -------------------------------------------------------------------------------------------------- | ------------------ | +| **`id`** | string | A unique identifier for the map instance. | | +| **`apiKey`** | string | The Google Maps SDK API Key. | | +| **`config`** | GoogleMapConfig | The initial configuration settings for the map. | | +| **`element`** | HTMLElement | The DOM element that the Google Map View will be mounted on which determines size and positioning. | | +| **`forceCreate`** | boolean | Destroy and re-create the map instance if a map with the supplied id already exists | false | + + +#### GoogleMapConfig + +For web, all the javascript Google Maps options are available as +GoogleMapConfig extends google.maps.MapOptions. +For iOS and Android only the config options declared on GoogleMapConfig are available. + +| Prop | Type | Description | Default | Since | +| ---------------------- | ----------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------ | ----- | +| **`width`** | number | Override width for native map. | | | +| **`height`** | number | Override height for native map. | | | +| **`x`** | number | Override absolute x coordinate position for native map. | | | +| **`y`** | number | Override absolute y coordinate position for native map. | | | +| **`center`** | LatLng | Default location on the Earth towards which the camera points. | | | +| **`zoom`** | number | Sets the zoom of the map. | | | +| **`androidLiteMode`** | boolean | Enables image-based lite mode on Android. | false | | +| **`devicePixelRatio`** | number | Override pixel ratio for native map. | | | +| **`styles`** | MapTypeStyle[] \| null | Styles to apply to each of the default map types. Note that for satellite, hybrid and terrain modes, these styles will only apply to labels and geometry. | | 4.3.0 | + + +#### LatLng + +An interface representing a pair of latitude and longitude coordinates. + +| Prop | Type | Description | +| --------- | ------------------- | ------------------------------------------------------------------------- | +| **`lat`** | number | Coordinate latitude, in degrees. This value is in the range [-90, 90]. | +| **`lng`** | number | Coordinate longitude, in degrees. This value is in the range [-180, 180]. | + + +#### MapReadyCallbackData + +| Prop | Type | +| ----------- | ------------------- | +| **`mapId`** | string | + + +#### Marker + +A marker is an icon placed at a particular point on the map's surface. + +| Prop | Type | Description | Default | Since | +| ---------------- | ------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------ | ----- | +| **`coordinate`** | LatLng | Marker position | | | +| **`opacity`** | number | Sets the opacity of the marker, between 0 (completely transparent) and 1 inclusive. | 1 | | +| **`title`** | string | Title, a short description of the overlay. | | | +| **`snippet`** | string | Snippet text, shown beneath the title in the info window when selected. | | | +| **`isFlat`** | boolean | Controls whether this marker should be flat against the Earth's surface or a billboard facing the camera. | false | | +| **`iconUrl`** | string | Path to a marker icon to render. It can be relative to the web app public directory, or a https url of a remote marker icon. **SVGs are not supported on native platforms.** | | 4.2.0 | +| **`iconSize`** | Size | Controls the scaled size of the marker image set in `iconUrl`. | | 4.2.0 | +| **`iconOrigin`** | Point | The position of the image within a sprite, if any. By default, the origin is located at the top left corner of the image . | | 4.2.0 | +| **`iconAnchor`** | Point | The position at which to anchor an image in correspondence to the location of the marker on the map. By default, the anchor is located along the center point of the bottom of the image. | | 4.2.0 | +| **`tintColor`** | { r: number; g: number; b: number; a: number; } | Customizes the color of the default marker image. Each value must be between 0 and 255. Only for iOS and Android. | | 4.2.0 | +| **`draggable`** | boolean | Controls whether this marker can be dragged interactively | false | | + + +#### Size + +| Prop | Type | +| ------------ | ------------------- | +| **`width`** | number | +| **`height`** | number | + + +#### Point + +| Prop | Type | +| ------- | ------------------- | +| **`x`** | number | +| **`y`** | number | + + +#### CameraConfig + +Configuration properties for a Google Map Camera + +| Prop | Type | Description | Default | +| ----------------------- | ----------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | ------------------ | +| **`coordinate`** | LatLng | Location on the Earth towards which the camera points. | | +| **`zoom`** | number | Sets the zoom of the map. | | +| **`bearing`** | number | Bearing of the camera, in degrees clockwise from true north. | 0 | +| **`angle`** | number | The angle, in degrees, of the camera from the nadir (directly facing the Earth). The only allowed values are 0 and 45. | 0 | +| **`animate`** | boolean | Animate the transition to the new Camera properties. | false | +| **`animationDuration`** | number | | | + + +#### MapPadding + +Controls for setting padding on the 'visible' region of the view. + +| Prop | Type | +| ------------ | ------------------- | +| **`top`** | number | +| **`left`** | number | +| **`right`** | number | +| **`bottom`** | number | + + +#### CameraIdleCallbackData + +| Prop | Type | +| --------------- | ----------------------------------------------------- | +| **`mapId`** | string | +| **`bounds`** | LatLngBounds | +| **`bearing`** | number | +| **`latitude`** | number | +| **`longitude`** | number | +| **`tilt`** | number | +| **`zoom`** | number | + + +#### LatLngBounds + +An interface representing the viewports latitude and longitude bounds. + +| Prop | Type | +| --------------- | ----------------------------------------- | +| **`southwest`** | LatLng | +| **`center`** | LatLng | +| **`northeast`** | LatLng | + + +#### CameraMoveStartedCallbackData + +| Prop | Type | +| --------------- | -------------------- | +| **`mapId`** | string | +| **`isGesture`** | boolean | + + +#### ClusterClickCallbackData + +| Prop | Type | +| --------------- | --------------------------------- | +| **`mapId`** | string | +| **`latitude`** | number | +| **`longitude`** | number | +| **`size`** | number | +| **`items`** | MarkerCallbackData[] | + + +#### MarkerCallbackData + +| Prop | Type | +| --------------- | ------------------- | +| **`markerId`** | string | +| **`latitude`** | number | +| **`longitude`** | number | +| **`title`** | string | +| **`snippet`** | string | + + +#### MarkerClickCallbackData + +| Prop | Type | +| ----------- | ------------------- | +| **`mapId`** | string | + + +#### MapClickCallbackData + +| Prop | Type | +| --------------- | ------------------- | +| **`mapId`** | string | +| **`latitude`** | number | +| **`longitude`** | number | + + +#### MyLocationButtonClickCallbackData + +| Prop | Type | +| ----------- | ------------------- | +| **`mapId`** | string | + + +### Type Aliases + + +#### MapListenerCallback + +The callback function to be called when map events are emitted. + +(data: T): void + + +### Enums + + +#### MapType + +| Members | Value | Description | +| --------------- | ------------------------ | ---------------------------------------- | +| **`Normal`** | 'Normal' | Basic map. | +| **`Hybrid`** | 'Hybrid' | Satellite imagery with roads and labels. | +| **`Satellite`** | 'Satellite' | Satellite imagery with no labels. | +| **`Terrain`** | 'Terrain' | Topographic data. | +| **`None`** | 'None' | No base map tiles. | + + diff --git a/storage/android/.gitignore b/google-maps/android/.gitignore similarity index 100% rename from storage/android/.gitignore rename to google-maps/android/.gitignore diff --git a/google-maps/android/build.gradle b/google-maps/android/build.gradle new file mode 100644 index 000000000..94bdef181 --- /dev/null +++ b/google-maps/android/build.gradle @@ -0,0 +1,96 @@ +ext { + capacitorVersion = System.getenv('CAPACITOR_VERSION') + junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.2' + androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.4.2' + androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.1.3' + androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.4.0' + androidxCoreKTXVersion = project.hasProperty('androidxCoreKTXVersion') ? rootProject.ext.androidxCoreKTXVersion : '1.8.0' + googleMapsPlayServicesVersion = project.hasProperty('googleMapsPlayServicesVersion') ? rootProject.ext.googleMapsPlayServicesVersion : '18.0.2' + googleMapsUtilsVersion = project.hasProperty('googleMapsUtilsVersion') ? rootProject.ext.googleMapsUtilsVersion : '2.3.0' + googleMapsKtxVersion = project.hasProperty('googleMapsKtxVersion') ? rootProject.ext.googleMapsKtxVersion : '3.4.0' + googleMapsUtilsKtxVersion = project.hasProperty('googleMapsUtilsKtxVersion') ? rootProject.ext.googleMapsUtilsKtxVersion : '3.4.0' + kotlinxCoroutinesVersion = project.hasProperty('kotlinxCoroutinesVersion') ? rootProject.ext.kotlinxCoroutinesVersion : '1.6.3' +} + +buildscript { + ext.kotlin_version = project.hasProperty("kotlin_version") ? rootProject.ext.kotlin_version : '1.7.0' + repositories { + google() + mavenCentral() + maven { + url "https://plugins.gradle.org/m2/" + } + } + dependencies { + classpath 'com.android.tools.build:gradle:7.2.1' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + classpath 'io.github.gradle-nexus:publish-plugin:1.1.0' + } + } +} + +apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' +if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + apply plugin: 'io.github.gradle-nexus.publish-plugin' + apply from: file('../../scripts/android/publish-root.gradle') + apply from: file('../../scripts/android/publish-module.gradle') +} + +android { + compileSdkVersion project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 32 + defaultConfig { + minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 22 + targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 32 + versionCode 1 + versionName "1.0" + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + lintOptions { + abortOnError false + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_11 + targetCompatibility JavaVersion.VERSION_11 + } + + dependencies { + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlinxCoroutinesVersion") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinxCoroutinesVersion") + } +} + +repositories { + google() + mavenCentral() +} + + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + + if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + implementation "com.capacitorjs:core:$capacitorVersion" + } else { + implementation project(':capacitor-android') + } + + implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion" + testImplementation "junit:junit:$junitVersion" + androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion" + androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion" + implementation "androidx.core:core-ktx:$androidxCoreKTXVersion" + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + + implementation "com.google.maps.android:maps-ktx:$googleMapsKtxVersion" + implementation "com.google.maps.android:maps-utils-ktx:$googleMapsUtilsKtxVersion" + implementation "com.google.maps.android:android-maps-utils:$googleMapsUtilsVersion" + implementation "com.google.android.gms:play-services-maps:$googleMapsPlayServicesVersion" +} diff --git a/google-maps/android/gradle.properties b/google-maps/android/gradle.properties new file mode 100644 index 000000000..84e2d9f2f --- /dev/null +++ b/google-maps/android/gradle.properties @@ -0,0 +1,24 @@ +# Project-wide Gradle settings. + +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. + +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html + +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx1536m -XX:MaxMetaspaceSize=512m + +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true + +# AndroidX package structure to make it clearer which packages are bundled with the +# Android operating system, and which are packaged with your app's APK +# https://developer.android.com/topic/libraries/support-library/androidx-rn +android.useAndroidX=true +# Automatically convert third-party libraries to use AndroidX +android.enableJetifier=true diff --git a/storage/android/gradle/wrapper/gradle-wrapper.jar b/google-maps/android/gradle/wrapper/gradle-wrapper.jar similarity index 61% rename from storage/android/gradle/wrapper/gradle-wrapper.jar rename to google-maps/android/gradle/wrapper/gradle-wrapper.jar index e708b1c02..41d9927a4 100644 Binary files a/storage/android/gradle/wrapper/gradle-wrapper.jar and b/google-maps/android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/storage/android/gradle/wrapper/gradle-wrapper.properties b/google-maps/android/gradle/wrapper/gradle-wrapper.properties similarity index 92% rename from storage/android/gradle/wrapper/gradle-wrapper.properties rename to google-maps/android/gradle/wrapper/gradle-wrapper.properties index 3c4101c3e..92f06b50f 100644 --- a/storage/android/gradle/wrapper/gradle-wrapper.properties +++ b/google-maps/android/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/google-maps/android/gradlew b/google-maps/android/gradlew new file mode 100755 index 000000000..1b6c78733 --- /dev/null +++ b/google-maps/android/gradlew @@ -0,0 +1,234 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +APP_NAME="Gradle" +APP_BASE_NAME=${0##*/} + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/storage/android/gradlew.bat b/google-maps/android/gradlew.bat similarity index 100% rename from storage/android/gradlew.bat rename to google-maps/android/gradlew.bat diff --git a/storage/android/proguard-rules.pro b/google-maps/android/proguard-rules.pro similarity index 100% rename from storage/android/proguard-rules.pro rename to google-maps/android/proguard-rules.pro diff --git a/storage/android/settings.gradle b/google-maps/android/settings.gradle similarity index 100% rename from storage/android/settings.gradle rename to google-maps/android/settings.gradle diff --git a/storage/android/src/main/AndroidManifest.xml b/google-maps/android/src/main/AndroidManifest.xml similarity index 61% rename from storage/android/src/main/AndroidManifest.xml rename to google-maps/android/src/main/AndroidManifest.xml index 1eb3372c8..360a49ef9 100644 --- a/storage/android/src/main/AndroidManifest.xml +++ b/google-maps/android/src/main/AndroidManifest.xml @@ -1,3 +1,3 @@ + package="com.capacitorjs.plugins.googlemaps"> diff --git a/google-maps/android/src/main/java/com/capacitorjs/plugins/googlemaps/CapacitorGoogleMap.kt b/google-maps/android/src/main/java/com/capacitorjs/plugins/googlemaps/CapacitorGoogleMap.kt new file mode 100644 index 000000000..82e9221b6 --- /dev/null +++ b/google-maps/android/src/main/java/com/capacitorjs/plugins/googlemaps/CapacitorGoogleMap.kt @@ -0,0 +1,801 @@ +package com.capacitorjs.plugins.googlemaps + +import android.annotation.SuppressLint +import android.graphics.* +import android.location.Location +import android.util.Log +import android.view.MotionEvent +import android.view.View +import android.view.ViewGroup +import android.widget.FrameLayout +import com.getcapacitor.Bridge +import com.getcapacitor.JSArray +import com.getcapacitor.JSObject +import com.google.android.gms.maps.CameraUpdateFactory +import com.google.android.gms.maps.GoogleMap +import com.google.android.gms.maps.GoogleMap.* +import com.google.android.gms.maps.MapView +import com.google.android.gms.maps.OnMapReadyCallback +import com.google.android.gms.maps.model.* +import com.google.maps.android.clustering.Cluster +import com.google.maps.android.clustering.ClusterManager +import java.io.InputStream +import java.net.URL +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Deferred +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.async +import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking + +class CapacitorGoogleMap( + val id: String, + val config: GoogleMapConfig, + val delegate: CapacitorGoogleMapsPlugin +) : + OnCameraIdleListener, + OnCameraMoveStartedListener, + OnMyLocationButtonClickListener, + OnMyLocationClickListener, + OnMapReadyCallback, + OnMapClickListener, + OnMarkerClickListener, + OnMarkerDragListener, + OnInfoWindowClickListener { + private var mapView: MapView + private var googleMap: GoogleMap? = null + private val markers = HashMap() + private val markerIcons = HashMap() + private var clusterManager: ClusterManager? = null + + private val isReadyChannel = Channel() + + init { + val bridge = delegate.bridge + mapView = MapView(bridge.context, config.googleMapOptions) + initMap() + setListeners() + } + + private fun initMap() { + runBlocking { + val job = + CoroutineScope(Dispatchers.Main).launch { + mapView.onCreate(null) + mapView.onStart() + mapView.getMapAsync(this@CapacitorGoogleMap) + mapView.setWillNotDraw(false) + isReadyChannel.receive() + + render() + } + + job.join() + } + } + + private fun render() { + runBlocking { + CoroutineScope(Dispatchers.Main).launch { + val bridge = delegate.bridge + val mapViewParent = FrameLayout(bridge.context) + mapViewParent.minimumHeight = bridge.webView.height + mapViewParent.minimumWidth = bridge.webView.width + + val layoutParams = + FrameLayout.LayoutParams( + getScaledPixels(bridge, config.width), + getScaledPixels(bridge, config.height), + ) + layoutParams.leftMargin = getScaledPixels(bridge, config.x) + layoutParams.topMargin = getScaledPixels(bridge, config.y) + + mapViewParent.tag = id + + mapView.layoutParams = layoutParams + mapViewParent.addView(mapView) + + ((bridge.webView.parent) as ViewGroup).addView(mapViewParent) + + bridge.webView.bringToFront() + bridge.webView.setBackgroundColor(Color.TRANSPARENT) + if (config.styles != null) { + googleMap?.setMapStyle(MapStyleOptions(config.styles!!)); + } + } + } + } + + fun updateRender(updatedBounds: RectF) { + this.config.x = updatedBounds.left.toInt() + this.config.y = updatedBounds.top.toInt() + this.config.width = updatedBounds.width().toInt() + this.config.height = updatedBounds.height().toInt() + + runBlocking { + CoroutineScope(Dispatchers.Main).launch { + val mapRect = getScaledRect(delegate.bridge, updatedBounds) + this@CapacitorGoogleMap.mapView.x = mapRect.left + this@CapacitorGoogleMap.mapView.y = mapRect.top + } + } + } + + fun dispatchTouchEvent(event: MotionEvent) { + CoroutineScope(Dispatchers.Main).launch { + val offsetViewBounds = getMapBounds() + + val relativeTop = offsetViewBounds.top + val relativeLeft = offsetViewBounds.left + + event.setLocation(event.x - relativeLeft, event.y - relativeTop) + mapView.dispatchTouchEvent(event) + } + } + + fun bringToFront() { + CoroutineScope(Dispatchers.Main).launch { + val mapViewParent = + ((delegate.bridge.webView.parent) as ViewGroup).findViewWithTag( + this@CapacitorGoogleMap.id + ) + mapViewParent.bringToFront() + } + } + + fun destroy() { + runBlocking { + val job = + CoroutineScope(Dispatchers.Main).launch { + val bridge = delegate.bridge + + val viewToRemove: View? = + ((bridge.webView.parent) as ViewGroup).findViewWithTag(id) + if (null != viewToRemove) { + ((bridge.webView.parent) as ViewGroup).removeView(viewToRemove) + } + mapView.onDestroy() + googleMap = null + clusterManager = null + } + + job.join() + } + } + + fun addMarkers( + newMarkers: List, + callback: (ids: Result>) -> Unit + ) { + try { + googleMap ?: throw GoogleMapNotAvailable() + val markerIds: MutableList = mutableListOf() + + CoroutineScope(Dispatchers.Main).launch { + newMarkers.forEach { + val markerOptions: Deferred = + CoroutineScope(Dispatchers.IO).async { + this@CapacitorGoogleMap.buildMarker(it) + } + val googleMapMarker = googleMap?.addMarker(markerOptions.await()) + it.googleMapMarker = googleMapMarker + + if (clusterManager != null) { + googleMapMarker?.remove() + } + + markers[googleMapMarker!!.id] = it + markerIds.add(googleMapMarker.id) + } + + if (clusterManager != null) { + clusterManager?.addItems(newMarkers) + clusterManager?.cluster() + } + + callback(Result.success(markerIds)) + } + } catch (e: GoogleMapsError) { + callback(Result.failure(e)) + } + } + + fun addMarker(marker: CapacitorGoogleMapMarker, callback: (result: Result) -> Unit) { + try { + googleMap ?: throw GoogleMapNotAvailable() + + var markerId: String + + CoroutineScope(Dispatchers.Main).launch { + val markerOptions: Deferred = + CoroutineScope(Dispatchers.IO).async { + this@CapacitorGoogleMap.buildMarker(marker) + } + val googleMapMarker = googleMap?.addMarker(markerOptions.await()) + + marker.googleMapMarker = googleMapMarker + + if (clusterManager != null) { + googleMapMarker?.remove() + clusterManager?.addItem(marker) + clusterManager?.cluster() + } + + markers[googleMapMarker!!.id] = marker + + markerId = googleMapMarker.id + + callback(Result.success(markerId)) + } + } catch (e: GoogleMapsError) { + callback(Result.failure(e)) + } + } + + @SuppressLint("PotentialBehaviorOverride") + fun enableClustering(callback: (error: GoogleMapsError?) -> Unit) { + try { + googleMap ?: throw GoogleMapNotAvailable() + + if (clusterManager != null) { + callback(null) + return + } + + CoroutineScope(Dispatchers.Main).launch { + val bridge = delegate.bridge + clusterManager = ClusterManager(bridge.context, googleMap) + + setClusterListeners() + + // add existing markers to the cluster + if (markers.isNotEmpty()) { + for ((_, marker) in markers) { + marker.googleMapMarker?.remove() + // marker.googleMapMarker = null + } + clusterManager?.addItems(markers.values) + clusterManager?.cluster() + } + + callback(null) + } + } catch (e: GoogleMapsError) { + callback(e) + } + } + + @SuppressLint("PotentialBehaviorOverride") + fun disableClustering(callback: (error: GoogleMapsError?) -> Unit) { + try { + googleMap ?: throw GoogleMapNotAvailable() + + CoroutineScope(Dispatchers.Main).launch { + clusterManager?.clearItems() + clusterManager?.cluster() + clusterManager = null + + googleMap?.setOnMarkerClickListener(this@CapacitorGoogleMap) + + // add existing markers back to the map + if (markers.isNotEmpty()) { + for ((_, marker) in markers) { + val markerOptions: Deferred = + CoroutineScope(Dispatchers.IO).async { + this@CapacitorGoogleMap.buildMarker(marker) + } + val googleMapMarker = googleMap?.addMarker(markerOptions.await()) + marker.googleMapMarker = googleMapMarker + } + } + + callback(null) + } + } catch (e: GoogleMapsError) { + callback(e) + } + } + + fun removeMarker(id: String, callback: (error: GoogleMapsError?) -> Unit) { + try { + googleMap ?: throw GoogleMapNotAvailable() + + val marker = markers[id] + marker ?: throw MarkerNotFoundError() + + CoroutineScope(Dispatchers.Main).launch { + if (clusterManager != null) { + clusterManager?.removeItem(marker) + clusterManager?.cluster() + } + + marker.googleMapMarker?.remove() + markers.remove(id) + + callback(null) + } + } catch (e: GoogleMapsError) { + callback(e) + } + } + + fun removeMarkers(ids: List, callback: (error: GoogleMapsError?) -> Unit) { + try { + googleMap ?: throw GoogleMapNotAvailable() + + CoroutineScope(Dispatchers.Main).launch { + val deletedMarkers: MutableList = mutableListOf() + + ids.forEach { + val marker = markers[it] + if (marker != null) { + marker.googleMapMarker?.remove() + markers.remove(it) + + deletedMarkers.add(marker) + } + } + + if (clusterManager != null) { + clusterManager?.removeItems(deletedMarkers) + clusterManager?.cluster() + } + + callback(null) + } + } catch (e: GoogleMapsError) { + callback(e) + } + } + + fun setCamera(config: GoogleMapCameraConfig, callback: (error: GoogleMapsError?) -> Unit) { + try { + googleMap ?: throw GoogleMapNotAvailable() + CoroutineScope(Dispatchers.Main).launch { + val currentPosition = googleMap!!.cameraPosition + + var updatedTarget = config.coordinate + if (updatedTarget == null) { + updatedTarget = currentPosition.target + } + + var zoom = config.zoom + if (zoom == null) { + zoom = currentPosition.zoom.toDouble() + } + + var bearing = config.bearing + if (bearing == null) { + bearing = currentPosition.bearing.toDouble() + } + + var angle = config.angle + if (angle == null) { + angle = currentPosition.tilt.toDouble() + } + + var animate = config.animate + if (animate == null) { + animate = false + } + + val updatedPosition = + CameraPosition.Builder() + .target(updatedTarget) + .zoom(zoom.toFloat()) + .bearing(bearing.toFloat()) + .tilt(angle.toFloat()) + .build() + + if (animate) { + googleMap?.animateCamera(CameraUpdateFactory.newCameraPosition(updatedPosition)) + } else { + googleMap?.moveCamera(CameraUpdateFactory.newCameraPosition(updatedPosition)) + } + callback(null) + } + } catch (e: GoogleMapsError) { + callback(e) + } + } + + fun setMapType(mapType: String, callback: (error: GoogleMapsError?) -> Unit) { + try { + googleMap ?: throw GoogleMapNotAvailable() + CoroutineScope(Dispatchers.Main).launch { + val mapTypeInt: Int = + when (mapType) { + "Normal" -> MAP_TYPE_NORMAL + "Hybrid" -> MAP_TYPE_HYBRID + "Satellite" -> MAP_TYPE_SATELLITE + "Terrain" -> MAP_TYPE_TERRAIN + "None" -> MAP_TYPE_NONE + else -> { + Log.w( + "CapacitorGoogleMaps", + "unknown mapView type '$mapType' Defaulting to normal." + ) + MAP_TYPE_NORMAL + } + } + + googleMap?.mapType = mapTypeInt + callback(null) + } + } catch (e: GoogleMapsError) { + callback(e) + } + } + + fun enableIndoorMaps(enabled: Boolean, callback: (error: GoogleMapsError?) -> Unit) { + try { + googleMap ?: throw GoogleMapNotAvailable() + CoroutineScope(Dispatchers.Main).launch { + googleMap?.isIndoorEnabled = enabled + callback(null) + } + } catch (e: GoogleMapsError) { + callback(e) + } + } + + fun enableTrafficLayer(enabled: Boolean, callback: (error: GoogleMapsError?) -> Unit) { + try { + googleMap ?: throw GoogleMapNotAvailable() + CoroutineScope(Dispatchers.Main).launch { + googleMap?.isTrafficEnabled = enabled + callback(null) + } + } catch (e: GoogleMapsError) { + callback(e) + } + } + + @SuppressLint("MissingPermission") + fun enableCurrentLocation(enabled: Boolean, callback: (error: GoogleMapsError?) -> Unit) { + try { + googleMap ?: throw GoogleMapNotAvailable() + CoroutineScope(Dispatchers.Main).launch { + googleMap?.isMyLocationEnabled = enabled + callback(null) + } + } catch (e: GoogleMapsError) { + callback(e) + } + } + + fun setPadding(padding: GoogleMapPadding, callback: (error: GoogleMapsError?) -> Unit) { + try { + googleMap ?: throw GoogleMapNotAvailable() + CoroutineScope(Dispatchers.Main).launch { + googleMap?.setPadding(padding.left, padding.top, padding.right, padding.bottom) + callback(null) + } + } catch (e: GoogleMapsError) { + callback(e) + } + } + + fun getMapBounds(): Rect { + return Rect( + getScaledPixels(delegate.bridge, config.x), + getScaledPixels(delegate.bridge, config.y), + getScaledPixels(delegate.bridge, config.x + config.width), + getScaledPixels(delegate.bridge, config.y + config.height) + ) + } + + fun getLatLngBounds(): LatLngBounds { + return googleMap?.projection?.visibleRegion?.latLngBounds ?: throw BoundsNotFoundError() + } + + fun getLatLngBoundsJSObject(bounds: LatLngBounds): JSObject { + val data = JSObject() + + val southwestJS = JSObject() + val centerJS = JSObject() + val northeastJS = JSObject() + + southwestJS.put("lat", bounds.southwest.latitude) + southwestJS.put("lng", bounds.southwest.longitude) + centerJS.put("lat", bounds.center.latitude) + centerJS.put("lng", bounds.center.longitude) + northeastJS.put("lat", bounds.northeast.latitude) + northeastJS.put("lng", bounds.northeast.longitude) + + data.put("southwest", southwestJS) + data.put("center", centerJS) + data.put("northeast", northeastJS) + + return data + } + + private fun getScaledPixels(bridge: Bridge, pixels: Int): Int { + // Get the screen's density scale + val scale = bridge.activity.resources.displayMetrics.density + // Convert the dps to pixels, based on density scale + return (pixels * scale + 0.5f).toInt() + } + + private fun getScaledPixelsF(bridge: Bridge, pixels: Float): Float { + // Get the screen's density scale + val scale = bridge.activity.resources.displayMetrics.density + // Convert the dps to pixels, based on density scale + return (pixels * scale + 0.5f) + } + + private fun getScaledRect(bridge: Bridge, rectF: RectF): RectF { + return RectF( + getScaledPixelsF(bridge, rectF.left), + getScaledPixelsF(bridge, rectF.top), + getScaledPixelsF(bridge, rectF.right), + getScaledPixelsF(bridge, rectF.bottom) + ) + } + + private fun buildMarker(marker: CapacitorGoogleMapMarker): MarkerOptions { + val markerOptions = MarkerOptions() + markerOptions.position(marker.coordinate) + markerOptions.title(marker.title) + markerOptions.snippet(marker.snippet) + markerOptions.alpha(marker.opacity) + markerOptions.flat(marker.isFlat) + markerOptions.draggable(marker.draggable) + + if (!marker.iconUrl.isNullOrEmpty()) { + if (this.markerIcons.contains(marker.iconUrl)) { + val cachedBitmap = this.markerIcons[marker.iconUrl] + markerOptions.icon(getResizedIcon(cachedBitmap!!, marker)) + } else { + try { + var stream: InputStream? = null + if (marker.iconUrl!!.startsWith("https:")) { + stream = URL(marker.iconUrl).openConnection().getInputStream() + } else { + stream = this.delegate.context.assets.open("public/${marker.iconUrl}") + } + var bitmap = BitmapFactory.decodeStream(stream) + this.markerIcons[marker.iconUrl!!] = bitmap + markerOptions.icon(getResizedIcon(bitmap, marker)) + } catch (e: Exception) { + var detailedMessage = "${e.javaClass} - ${e.localizedMessage}" + if (marker.iconUrl!!.endsWith(".svg")) { + detailedMessage = "SVG not supported" + } + + Log.w( + "CapacitorGoogleMaps", + "Could not load image '${marker.iconUrl}': ${detailedMessage}. Using default marker icon." + ) + } + } + } else { + if (marker.colorHue != null) { + markerOptions.icon(BitmapDescriptorFactory.defaultMarker(marker.colorHue!!)) + } + } + + return markerOptions + } + + private fun getResizedIcon(_bitmap: Bitmap, marker: CapacitorGoogleMapMarker): BitmapDescriptor { + var bitmap = _bitmap + if (marker.iconSize != null) { + bitmap = + Bitmap.createScaledBitmap( + bitmap, + (marker.iconSize!!.width * this.config.devicePixelRatio) + .toInt(), + (marker.iconSize!!.height * this.config.devicePixelRatio) + .toInt(), + false + ) + } + return BitmapDescriptorFactory.fromBitmap(bitmap) + } + + fun onStart() { + mapView.onStart() + } + + fun onResume() { + mapView.onResume() + } + + fun onStop() { + mapView.onStop() + } + + fun onPause() { + mapView.onPause() + } + + fun onDestroy() { + mapView.onDestroy() + } + + override fun onMapReady(map: GoogleMap) { + runBlocking { + googleMap = map + + val data = JSObject() + data.put("mapId", this@CapacitorGoogleMap.id) + delegate.notify("onMapReady", data) + + isReadyChannel.send(true) + isReadyChannel.close() + } + } + + @SuppressLint("PotentialBehaviorOverride") + fun setListeners() { + CoroutineScope(Dispatchers.Main).launch { + this@CapacitorGoogleMap.googleMap?.setOnCameraIdleListener(this@CapacitorGoogleMap) + this@CapacitorGoogleMap.googleMap?.setOnCameraMoveStartedListener( + this@CapacitorGoogleMap + ) + this@CapacitorGoogleMap.googleMap?.setOnMarkerClickListener(this@CapacitorGoogleMap) + this@CapacitorGoogleMap.googleMap?.setOnMarkerDragListener(this@CapacitorGoogleMap) + this@CapacitorGoogleMap.googleMap?.setOnMapClickListener(this@CapacitorGoogleMap) + this@CapacitorGoogleMap.googleMap?.setOnMyLocationButtonClickListener( + this@CapacitorGoogleMap + ) + this@CapacitorGoogleMap.googleMap?.setOnMyLocationClickListener(this@CapacitorGoogleMap) + this@CapacitorGoogleMap.googleMap?.setOnInfoWindowClickListener(this@CapacitorGoogleMap) + } + } + + fun setClusterListeners() { + CoroutineScope(Dispatchers.Main).launch { + clusterManager?.setOnClusterItemClickListener { + if (null == it.googleMapMarker) false + else this@CapacitorGoogleMap.onMarkerClick(it.googleMapMarker!!) + } + + clusterManager?.setOnClusterItemInfoWindowClickListener { + if (null != it.googleMapMarker) { + this@CapacitorGoogleMap.onInfoWindowClick(it.googleMapMarker!!) + } + } + + clusterManager?.setOnClusterInfoWindowClickListener { + val data = this@CapacitorGoogleMap.getClusterData(it) + delegate.notify("onClusterInfoWindowClick", data) + } + + clusterManager?.setOnClusterClickListener { + val data = this@CapacitorGoogleMap.getClusterData(it) + delegate.notify("onClusterClick", data) + false + } + } + } + + private fun getClusterData(it: Cluster): JSObject { + val data = JSObject() + data.put("mapId", this.id) + data.put("latitude", it.position.latitude) + data.put("longitude", it.position.longitude) + data.put("size", it.size) + + val items = JSArray() + for (item in it.items) { + val marker = item.googleMapMarker + + if (marker != null) { + val jsItem = JSObject() + jsItem.put("markerId", marker.id) + jsItem.put("latitude", marker.position.latitude) + jsItem.put("longitude", marker.position.longitude) + jsItem.put("title", marker.title) + jsItem.put("snippet", marker.snippet) + + items.put(jsItem) + } + } + + data.put("items", items) + + return data + } + + override fun onMapClick(point: LatLng) { + val data = JSObject() + data.put("mapId", this@CapacitorGoogleMap.id) + data.put("latitude", point.latitude) + data.put("longitude", point.longitude) + delegate.notify("onMapClick", data) + } + + override fun onMarkerClick(marker: Marker): Boolean { + val data = JSObject() + data.put("mapId", this@CapacitorGoogleMap.id) + data.put("markerId", marker.id) + data.put("latitude", marker.position.latitude) + data.put("longitude", marker.position.longitude) + data.put("title", marker.title) + data.put("snippet", marker.snippet) + delegate.notify("onMarkerClick", data) + return false + } + + override fun onMarkerDrag(marker: Marker) { + val data = JSObject() + data.put("mapId", this@CapacitorGoogleMap.id) + data.put("markerId", marker.id) + data.put("latitude", marker.position.latitude) + data.put("longitude", marker.position.longitude) + data.put("title", marker.title) + data.put("snippet", marker.snippet) + delegate.notify("onMarkerDrag", data) + } + + override fun onMarkerDragStart(marker: Marker) { + val data = JSObject() + data.put("mapId", this@CapacitorGoogleMap.id) + data.put("markerId", marker.id) + data.put("latitude", marker.position.latitude) + data.put("longitude", marker.position.longitude) + data.put("title", marker.title) + data.put("snippet", marker.snippet) + delegate.notify("onMarkerDragStart", data) + } + + override fun onMarkerDragEnd(marker: Marker) { + val data = JSObject() + data.put("mapId", this@CapacitorGoogleMap.id) + data.put("markerId", marker.id) + data.put("latitude", marker.position.latitude) + data.put("longitude", marker.position.longitude) + data.put("title", marker.title) + data.put("snippet", marker.snippet) + delegate.notify("onMarkerDragEnd", data) + } + + override fun onMyLocationButtonClick(): Boolean { + val data = JSObject() + data.put("mapId", this@CapacitorGoogleMap.id) + delegate.notify("onMyLocationButtonClick", data) + return false + } + + override fun onMyLocationClick(location: Location) { + val data = JSObject() + data.put("mapId", this@CapacitorGoogleMap.id) + data.put("latitude", location.latitude) + data.put("longitude", location.longitude) + delegate.notify("onMyLocationClick", data) + } + + override fun onCameraIdle() { + val data = JSObject() + data.put("mapId", this@CapacitorGoogleMap.id) + data.put("bounds", getLatLngBoundsJSObject(getLatLngBounds())) + data.put("bearing", this@CapacitorGoogleMap.googleMap?.cameraPosition?.bearing) + data.put("latitude", this@CapacitorGoogleMap.googleMap?.cameraPosition?.target?.latitude) + data.put("longitude", this@CapacitorGoogleMap.googleMap?.cameraPosition?.target?.longitude) + data.put("tilt", this@CapacitorGoogleMap.googleMap?.cameraPosition?.tilt) + data.put("zoom", this@CapacitorGoogleMap.googleMap?.cameraPosition?.zoom) + delegate.notify("onCameraIdle", data) + delegate.notify("onBoundsChanged", data) + } + + override fun onCameraMoveStarted(reason: Int) { + val data = JSObject() + data.put("mapId", this@CapacitorGoogleMap.id) + data.put("isGesture", reason == 1) + delegate.notify("onCameraMoveStarted", data) + } + + override fun onInfoWindowClick(marker: Marker) { + val data = JSObject() + data.put("mapId", this@CapacitorGoogleMap.id) + data.put("markerId", marker.id) + data.put("latitude", marker.position.latitude) + data.put("longitude", marker.position.longitude) + data.put("title", marker.title) + data.put("snippet", marker.snippet) + delegate.notify("onInfoWindowClick", data) + } +} diff --git a/google-maps/android/src/main/java/com/capacitorjs/plugins/googlemaps/CapacitorGoogleMapMarker.kt b/google-maps/android/src/main/java/com/capacitorjs/plugins/googlemaps/CapacitorGoogleMapMarker.kt new file mode 100644 index 000000000..7788a4e61 --- /dev/null +++ b/google-maps/android/src/main/java/com/capacitorjs/plugins/googlemaps/CapacitorGoogleMapMarker.kt @@ -0,0 +1,86 @@ +package com.capacitorjs.plugins.googlemaps + +import android.graphics.Color +import android.util.Size +import androidx.core.math.MathUtils +import com.google.android.gms.maps.model.* +import com.google.maps.android.clustering.ClusterItem +import org.json.JSONObject + + +class CapacitorGoogleMapMarker(fromJSONObject: JSONObject): ClusterItem { + var coordinate: LatLng = LatLng(0.0, 0.0) + var opacity: Float = 1.0f + private var title: String + private var snippet: String + var isFlat: Boolean = false + var iconUrl: String? = null + var iconSize: Size? = null + var iconAnchor: CapacitorGoogleMapsPoint? = null + var draggable: Boolean = false + var googleMapMarker: Marker? = null + var colorHue: Float? = null + + init { + if(!fromJSONObject.has("coordinate")) { + throw InvalidArgumentsError("Marker object is missing the required 'coordinate' property") + } + + val latLngObj = fromJSONObject.getJSONObject("coordinate") + if (!latLngObj.has("lat") || !latLngObj.has("lng")) { + throw InvalidArgumentsError("LatLng object is missing the required 'lat' and/or 'lng' property") + } + + coordinate = LatLng(latLngObj.getDouble("lat"), latLngObj.getDouble("lng")) + title = fromJSONObject.optString("title") + opacity = fromJSONObject.optDouble("opacity", 1.0).toFloat() + snippet = fromJSONObject.optString("snippet") + isFlat = fromJSONObject.optBoolean("isFlat", false) + iconUrl = fromJSONObject.optString("iconUrl") + if (fromJSONObject.has("iconSize")) { + val iconSizeObject = fromJSONObject.getJSONObject("iconSize") + iconSize = Size(iconSizeObject.optInt("width", 0), iconSizeObject.optInt("height", 0)) + } + + if (fromJSONObject.has("iconAnchor")) { + val inputAnchorPoint = CapacitorGoogleMapsPoint(fromJSONObject.getJSONObject("iconAnchor")) + iconAnchor = this.buildIconAnchorPoint(inputAnchorPoint) + } + + if(fromJSONObject.has("tintColor")) { + val tintColorObject = fromJSONObject.getJSONObject("tintColor") + + val r = MathUtils.clamp(tintColorObject.optDouble("r", 0.00), 0.00, 255.0) + val g = MathUtils.clamp(tintColorObject.optDouble("g", 0.00), 0.00, 255.0) + val b = MathUtils.clamp(tintColorObject.optDouble("b", 0.00), 0.00, 255.0) + + val hsl = FloatArray(3) + Color.RGBToHSV(r.toInt(), g.toInt(), b.toInt(), hsl) + + colorHue = hsl[0] + } + + draggable = fromJSONObject.optBoolean("draggable", false) + } + + override fun getPosition(): LatLng { + return LatLng(coordinate.latitude, coordinate.longitude) + } + + override fun getTitle(): String { + return title + } + + override fun getSnippet(): String { + return snippet + } + + private fun buildIconAnchorPoint(iconAnchor: CapacitorGoogleMapsPoint): CapacitorGoogleMapsPoint? { + iconSize ?: return null + + val u: Float = iconAnchor.x / iconSize!!.width + val v: Float = iconAnchor.y / iconSize!!.height + + return CapacitorGoogleMapsPoint(u, v) + } +} \ No newline at end of file diff --git a/google-maps/android/src/main/java/com/capacitorjs/plugins/googlemaps/CapacitorGoogleMapsBounds.kt b/google-maps/android/src/main/java/com/capacitorjs/plugins/googlemaps/CapacitorGoogleMapsBounds.kt new file mode 100644 index 000000000..ab757e946 --- /dev/null +++ b/google-maps/android/src/main/java/com/capacitorjs/plugins/googlemaps/CapacitorGoogleMapsBounds.kt @@ -0,0 +1,33 @@ +package com.capacitorjs.plugins.googlemaps + +import org.json.JSONObject + +class CapacitorGoogleMapsBounds(fromJSONObject: JSONObject) { + var width: Int = 0 + var height: Int = 0 + var x: Int = 0 + var y: Int = 0 + + init { + if(!fromJSONObject.has("width")) { + throw InvalidArgumentsError("GoogleMapConfig object is missing the required 'width' property") + } + + if(!fromJSONObject.has("height")) { + throw InvalidArgumentsError("GoogleMapConfig object is missing the required 'height' property") + } + + if(!fromJSONObject.has("x")) { + throw InvalidArgumentsError("GoogleMapConfig object is missing the required 'x' property") + } + + if(!fromJSONObject.has("y")) { + throw InvalidArgumentsError("GoogleMapConfig object is missing the required 'y' property") + } + + width = fromJSONObject.getInt("width") + height = fromJSONObject.getInt("height") + x = fromJSONObject.getInt("x") + y = fromJSONObject.getInt("y") + } +} \ No newline at end of file diff --git a/google-maps/android/src/main/java/com/capacitorjs/plugins/googlemaps/CapacitorGoogleMapsPlugin.kt b/google-maps/android/src/main/java/com/capacitorjs/plugins/googlemaps/CapacitorGoogleMapsPlugin.kt new file mode 100644 index 000000000..5303162d6 --- /dev/null +++ b/google-maps/android/src/main/java/com/capacitorjs/plugins/googlemaps/CapacitorGoogleMapsPlugin.kt @@ -0,0 +1,655 @@ +package com.capacitorjs.plugins.googlemaps + +import android.Manifest +import android.annotation.SuppressLint +import android.graphics.RectF +import android.util.Log +import android.view.MotionEvent +import android.view.View +import com.getcapacitor.* +import com.getcapacitor.annotation.CapacitorPlugin +import com.getcapacitor.annotation.Permission +import com.getcapacitor.annotation.PermissionCallback +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import org.json.JSONArray +import org.json.JSONObject + +@CapacitorPlugin( + name = "CapacitorGoogleMaps", + permissions = + [ + Permission( + strings = [Manifest.permission.ACCESS_FINE_LOCATION], + alias = CapacitorGoogleMapsPlugin.LOCATION + ), + ], +) +class CapacitorGoogleMapsPlugin : Plugin() { + private var maps: HashMap = HashMap() + private var cachedTouchEvents: HashMap> = HashMap() + private val tag: String = "CAP-GOOGLE-MAPS" + + companion object { + const val LOCATION = "location" + } + + @SuppressLint("ClickableViewAccessibility") + override fun load() { + super.load() + + this.bridge.webView.setOnTouchListener( + object : View.OnTouchListener { + override fun onTouch(v: View?, event: MotionEvent?): Boolean { + if (event != null) { + if (event.source == -1) { + return v?.onTouchEvent(event) ?: true + } + + val touchX = event.x + val touchY = event.y + + for ((id, map) in maps) { + val mapRect = map.getMapBounds() + if (mapRect.contains(touchX.toInt(), touchY.toInt())) { + if (event.action == MotionEvent.ACTION_DOWN) { + if (cachedTouchEvents[id] == null) { + cachedTouchEvents[id] = mutableListOf() + } + + cachedTouchEvents[id]?.clear() + } + + val motionEvent = MotionEvent.obtain(event) + cachedTouchEvents[id]?.add(motionEvent) + + val payload = JSObject() + payload.put("x", touchX / map.config.devicePixelRatio) + payload.put("y", touchY / map.config.devicePixelRatio) + payload.put("mapId", map.id) + + notifyListeners("isMapInFocus", payload) + return true + } + } + } + + return v?.onTouchEvent(event) ?: true + } + } + ) + } + + override fun handleOnStart() { + super.handleOnStart() + maps.forEach { it.value.onStart() } + } + + override fun handleOnResume() { + super.handleOnResume() + maps.forEach { it.value.onResume() } + } + + override fun handleOnPause() { + super.handleOnPause() + maps.forEach { it.value.onPause() } + } + + override fun handleOnStop() { + super.handleOnStop() + maps.forEach { it.value.onStop() } + } + + override fun handleOnDestroy() { + super.handleOnDestroy() + maps.forEach { it.value.onDestroy() } + } + + @PluginMethod + fun create(call: PluginCall) { + try { + val id = call.getString("id") + + if (null == id || id.isEmpty()) { + throw InvalidMapIdError() + } + + val configObject = + call.getObject("config") + ?: throw InvalidArgumentsError("config object is missing") + + val forceCreate = call.getBoolean("forceCreate", false)!! + + val config = GoogleMapConfig(configObject) + + if (maps.contains(id)) { + if (!forceCreate) { + call.resolve() + return + } + + val oldMap = maps.remove(id) + oldMap?.destroy() + } + + val newMap = CapacitorGoogleMap(id, config, this) + maps[id] = newMap + + call.resolve() + } catch (e: GoogleMapsError) { + handleError(call, e) + } catch (e: Exception) { + handleError(call, e) + } + } + + @PluginMethod + fun destroy(call: PluginCall) { + try { + val id = call.getString("id") + + if (null == id || id.isEmpty()) { + throw InvalidMapIdError() + } + + val removedMap = maps.remove(id) ?: throw MapNotFoundError() + removedMap.destroy() + + call.resolve() + } catch (e: GoogleMapsError) { + handleError(call, e) + } catch (e: Exception) { + handleError(call, e) + } + } + + @PluginMethod + fun addMarker(call: PluginCall) { + try { + val id = call.getString("id") + id ?: throw InvalidMapIdError() + + val markerObj = call.getObject("marker", null) + markerObj ?: throw InvalidArgumentsError("marker object is missing") + + val map = maps[id] + map ?: throw MapNotFoundError() + + val marker = CapacitorGoogleMapMarker(markerObj) + map.addMarker(marker) { result -> + val markerId = result.getOrThrow() + + val res = JSObject() + res.put("id", markerId) + call.resolve(res) + } + } catch (e: GoogleMapsError) { + handleError(call, e) + } catch (e: Exception) { + handleError(call, e) + } + } + + @PluginMethod + fun addMarkers(call: PluginCall) { + try { + val id = call.getString("id") + id ?: throw InvalidMapIdError() + + val markerObjectArray = call.getArray("markers", null) + markerObjectArray ?: throw InvalidArgumentsError("markers array is missing") + + if (markerObjectArray.length() == 0) { + throw InvalidArgumentsError("markers array requires at least one marker") + } + + val map = maps[id] + map ?: throw MapNotFoundError() + + val markers: MutableList = mutableListOf() + + for (i in 0 until markerObjectArray.length()) { + val markerObj = markerObjectArray.getJSONObject(i) + val marker = CapacitorGoogleMapMarker(markerObj) + + markers.add(marker) + } + + map.addMarkers(markers) { result -> + val ids = result.getOrThrow() + + val jsonIDs = JSONArray() + ids.forEach { jsonIDs.put(it) } + + val res = JSObject() + res.put("ids", jsonIDs) + call.resolve(res) + } + } catch (e: GoogleMapsError) { + handleError(call, e) + } catch (e: Exception) { + handleError(call, e) + } + } + + @PluginMethod + fun enableClustering(call: PluginCall) { + try { + val id = call.getString("id") + id ?: throw InvalidMapIdError() + + val map = maps[id] + map ?: throw MapNotFoundError() + + map.enableClustering { err -> + if (err != null) { + throw err + } + + call.resolve() + } + } catch (e: GoogleMapsError) { + handleError(call, e) + } catch (e: Exception) { + handleError(call, e) + } + } + + @PluginMethod + fun disableClustering(call: PluginCall) { + try { + val id = call.getString("id") + id ?: throw InvalidMapIdError() + + val map = maps[id] + map ?: throw MapNotFoundError() + + map.disableClustering { err -> + if (err != null) { + throw err + } + + call.resolve() + } + } catch (e: GoogleMapsError) { + handleError(call, e) + } catch (e: Exception) { + handleError(call, e) + } + } + + @PluginMethod + fun removeMarker(call: PluginCall) { + try { + val id = call.getString("id") + id ?: throw InvalidMapIdError() + + val markerId = call.getString("markerId") + markerId ?: throw InvalidArgumentsError("markerId is invalid or missing") + + val map = maps[id] + map ?: throw MapNotFoundError() + + map.removeMarker(markerId) { err -> + if (err != null) { + throw err + } + + call.resolve() + } + } catch (e: GoogleMapsError) { + handleError(call, e) + } catch (e: Exception) { + handleError(call, e) + } + } + + @PluginMethod + fun removeMarkers(call: PluginCall) { + try { + val id = call.getString("id") + id ?: throw InvalidMapIdError() + + val markerIdsArray = call.getArray("markerIds") + markerIdsArray ?: throw InvalidArgumentsError("markerIds are invalid or missing") + + if (markerIdsArray.length() == 0) { + throw InvalidArgumentsError("markerIds requires at least one marker id") + } + + val map = maps[id] + map ?: throw MapNotFoundError() + + val markerIds: MutableList = mutableListOf() + + for (i in 0 until markerIdsArray.length()) { + val markerId = markerIdsArray.getString(i) + markerIds.add(markerId) + } + + map.removeMarkers(markerIds) { err -> + if (err != null) { + throw err + } + + call.resolve() + } + } catch (e: GoogleMapsError) { + handleError(call, e) + } catch (e: Exception) { + handleError(call, e) + } + } + + @PluginMethod + fun setCamera(call: PluginCall) { + try { + val id = call.getString("id") + id ?: throw InvalidMapIdError() + + val map = maps[id] + map ?: throw MapNotFoundError() + + val cameraConfigObject = + call.getObject("config") + ?: throw InvalidArgumentsError("config object is missing") + + val config = GoogleMapCameraConfig(cameraConfigObject) + + map.setCamera(config) { err -> + if (err != null) { + throw err + } + + call.resolve() + } + } catch (e: GoogleMapsError) { + handleError(call, e) + } catch (e: Exception) { + handleError(call, e) + } + } + + @PluginMethod + fun setMapType(call: PluginCall) { + try { + val id = call.getString("id") + id ?: throw InvalidMapIdError() + + val map = maps[id] + map ?: throw MapNotFoundError() + + val mapType = + call.getString("mapType") ?: throw InvalidArgumentsError("mapType is missing") + + map.setMapType(mapType) { err -> + if (err != null) { + throw err + } + + call.resolve() + } + } catch (e: GoogleMapsError) { + handleError(call, e) + } catch (e: Exception) { + handleError(call, e) + } + } + + @PluginMethod + fun enableIndoorMaps(call: PluginCall) { + try { + val id = call.getString("id") + id ?: throw InvalidMapIdError() + + val map = maps[id] + map ?: throw MapNotFoundError() + + val enabled = + call.getBoolean("enabled") ?: throw InvalidArgumentsError("enabled is missing") + + map.enableIndoorMaps(enabled) { err -> + if (err != null) { + throw err + } + + call.resolve() + } + } catch (e: GoogleMapsError) { + handleError(call, e) + } catch (e: Exception) { + handleError(call, e) + } + } + + @PluginMethod + fun enableTrafficLayer(call: PluginCall) { + try { + val id = call.getString("id") + id ?: throw InvalidMapIdError() + + val map = maps[id] + map ?: throw MapNotFoundError() + + val enabled = + call.getBoolean("enabled") ?: throw InvalidArgumentsError("enabled is missing") + + map.enableTrafficLayer(enabled) { err -> + if (err != null) { + throw err + } + + call.resolve() + } + } catch (e: GoogleMapsError) { + handleError(call, e) + } catch (e: Exception) { + handleError(call, e) + } + } + + @PluginMethod + fun enableCurrentLocation(call: PluginCall) { + if (getPermissionState(LOCATION) != PermissionState.GRANTED) { + requestAllPermissions(call, "enableCurrentLocationCallback") + } else { + internalEnableCurrentLocation(call) + } + } + + @PermissionCallback + fun enableCurrentLocationCallback(call: PluginCall) { + if (getPermissionState(LOCATION) == PermissionState.GRANTED) { + internalEnableCurrentLocation(call) + } else { + call.reject("location permission was denied") + } + } + + @PluginMethod + fun setPadding(call: PluginCall) { + try { + val id = call.getString("id") + id ?: throw InvalidMapIdError() + + val map = maps[id] + map ?: throw MapNotFoundError() + + val paddingObj = + call.getObject("padding") ?: throw InvalidArgumentsError("padding is missing") + + val padding = GoogleMapPadding(paddingObj) + + map.setPadding(padding) { err -> + if (err != null) { + throw err + } + + call.resolve() + } + } catch (e: GoogleMapsError) { + handleError(call, e) + } catch (e: Exception) { + handleError(call, e) + } + } + + @PluginMethod + fun enableAccessibilityElements(call: PluginCall) { + call.unavailable("this call is not available on android") + } + + @PluginMethod + fun onScroll(call: PluginCall) { + try { + val id = call.getString("id") + id ?: throw InvalidMapIdError() + + val map = maps[id] + map ?: throw MapNotFoundError() + + val boundsObj = + call.getObject("mapBounds") + ?: throw InvalidArgumentsError("mapBounds object is missing") + + val bounds = boundsObjectToRect(boundsObj) + + map.updateRender(bounds) + + call.resolve() + } catch (e: GoogleMapsError) { + handleError(call, e) + } catch (e: Exception) { + handleError(call, e) + } + } + + @PluginMethod + fun dispatchMapEvent(call: PluginCall) { + try { + val id = call.getString("id") + id ?: throw InvalidMapIdError() + + val map = maps[id] + map ?: throw MapNotFoundError() + + val focus = call.getBoolean("focus", false)!! + + val events = cachedTouchEvents[id] + if (events != null) { + for (event in events) { + if (focus) { + map.dispatchTouchEvent(event) + } else { + event.source = -1 + this.bridge.webView.dispatchTouchEvent(event) + } + } + } + + cachedTouchEvents[id]?.clear() + + call.resolve() + } catch (e: GoogleMapsError) { + handleError(call, e) + } catch (e: Exception) { + handleError(call, e) + } + } + + @PluginMethod + fun getMapBounds(call: PluginCall) { + try { + val id = call.getString("id") + id ?: throw InvalidMapIdError() + + val map = maps[id] + map ?: throw MapNotFoundError() + + CoroutineScope(Dispatchers.Main).launch { + val bounds = map.getLatLngBounds() + val data = map.getLatLngBoundsJSObject(bounds) + call.resolve(data) + } + } catch (e: GoogleMapsError) { + handleError(call, e) + } catch (e: Exception) { + handleError(call, e) + } + } + + private fun internalEnableCurrentLocation(call: PluginCall) { + try { + val id = call.getString("id") + id ?: throw InvalidMapIdError() + + val map = maps[id] + map ?: throw MapNotFoundError() + + val enabled = + call.getBoolean("enabled") ?: throw InvalidArgumentsError("enabled is missing") + + map.enableCurrentLocation(enabled) { err -> + if (err != null) { + throw err + } + + call.resolve() + } + } catch (e: GoogleMapsError) { + handleError(call, e) + } catch (e: Exception) { + handleError(call, e) + } + } + + fun notify(event: String, data: JSObject) { + notifyListeners(event, data) + } + + private fun handleError(call: PluginCall, e: Exception) { + val error: GoogleMapErrorObject = getErrorObject(e) + Log.w(tag, error.toString()) + call.reject(error.message, error.code.toString(), e) + } + + private fun handleError(call: PluginCall, e: GoogleMapsError) { + val error: GoogleMapErrorObject = getErrorObject(e) + Log.w(tag, error.toString()) + call.reject(error.message, error.code.toString()) + } + + private fun boundsObjectToRect(jsonObject: JSONObject): RectF { + if (!jsonObject.has("width")) { + throw InvalidArgumentsError( + "GoogleMapConfig object is missing the required 'width' property" + ) + } + + if (!jsonObject.has("height")) { + throw InvalidArgumentsError( + "GoogleMapConfig object is missing the required 'height' property" + ) + } + + if (!jsonObject.has("x")) { + throw InvalidArgumentsError( + "GoogleMapConfig object is missing the required 'x' property" + ) + } + + if (!jsonObject.has("y")) { + throw InvalidArgumentsError( + "GoogleMapConfig object is missing the required 'y' property" + ) + } + + val width = jsonObject.getDouble("width") + val height = jsonObject.getDouble("height") + val x = jsonObject.getDouble("x") + val y = jsonObject.getDouble("y") + + return RectF(x.toFloat(), y.toFloat(), (x + width).toFloat(), (y + height).toFloat()) + } +} diff --git a/google-maps/android/src/main/java/com/capacitorjs/plugins/googlemaps/CapacitorGoogleMapsPoint.kt b/google-maps/android/src/main/java/com/capacitorjs/plugins/googlemaps/CapacitorGoogleMapsPoint.kt new file mode 100644 index 000000000..5234873f5 --- /dev/null +++ b/google-maps/android/src/main/java/com/capacitorjs/plugins/googlemaps/CapacitorGoogleMapsPoint.kt @@ -0,0 +1,23 @@ +package com.capacitorjs.plugins.googlemaps + +import org.json.JSONObject + +class CapacitorGoogleMapsPoint() { + var x: Float = 0.00f + var y: Float = 0.00f + + constructor(fromJSONObject: JSONObject) : this() { + if(fromJSONObject.has("x")) { + this.x = fromJSONObject.getDouble("x").toFloat() + } + + if(fromJSONObject.has("y")) { + this.x = fromJSONObject.getDouble("y").toFloat() + } + } + + constructor(x: Float, y: Float) : this() { + this.x = x; + this.y = y + } +} \ No newline at end of file diff --git a/google-maps/android/src/main/java/com/capacitorjs/plugins/googlemaps/GoogleMapCameraConfig.kt b/google-maps/android/src/main/java/com/capacitorjs/plugins/googlemaps/GoogleMapCameraConfig.kt new file mode 100644 index 000000000..b072b2c0f --- /dev/null +++ b/google-maps/android/src/main/java/com/capacitorjs/plugins/googlemaps/GoogleMapCameraConfig.kt @@ -0,0 +1,50 @@ +package com.capacitorjs.plugins.googlemaps + +import com.google.android.gms.maps.model.LatLng +import org.json.JSONObject + +class GoogleMapCameraConfig(fromJSONObject: JSONObject) { + var coordinate: LatLng? = null + var zoom: Double? = null + var angle: Double? = null + var bearing: Double? = null + var animate: Boolean? = null + var animationDuration: Double? = null + + init { + if (fromJSONObject.has("zoom")) { + zoom = fromJSONObject.getDouble("zoom") + } + + if(fromJSONObject.has("angle")) { + angle = fromJSONObject.getDouble("angle") + } + + if (fromJSONObject.has("bearing")) { + bearing = fromJSONObject.getDouble("bearing") + } + + if (fromJSONObject.has("animate")) { + animate = fromJSONObject.getBoolean("animate") + } + + if (fromJSONObject.has("animationDuration")) { + animationDuration = fromJSONObject.getDouble("animationDuration") + } + + if (fromJSONObject.has("coordinate")) { + val coordinateJSONObject = fromJSONObject.getJSONObject("coordinate") + if(!coordinateJSONObject.has("lat") || !coordinateJSONObject.has("lng")) { + throw InvalidArgumentsError("LatLng object is missing the required 'lat' and/or 'lng' property") + } + + val lat = coordinateJSONObject.getDouble("lat") + val lng = coordinateJSONObject.getDouble("lng") + coordinate = LatLng(lat, lng) + } else { + coordinate = null + } + } + + +} \ No newline at end of file diff --git a/google-maps/android/src/main/java/com/capacitorjs/plugins/googlemaps/GoogleMapConfig.kt b/google-maps/android/src/main/java/com/capacitorjs/plugins/googlemaps/GoogleMapConfig.kt new file mode 100644 index 000000000..6f27d10ab --- /dev/null +++ b/google-maps/android/src/main/java/com/capacitorjs/plugins/googlemaps/GoogleMapConfig.kt @@ -0,0 +1,88 @@ +package com.capacitorjs.plugins.googlemaps + +import com.google.android.gms.maps.GoogleMapOptions +import com.google.android.gms.maps.model.CameraPosition +import com.google.android.gms.maps.model.LatLng +import org.json.JSONObject + +class GoogleMapConfig(fromJSONObject: JSONObject) { + var width: Int = 0 + var height: Int = 0 + var x: Int = 0 + var y: Int = 0 + var center: LatLng = LatLng(0.0, 0.0) + var googleMapOptions: GoogleMapOptions? = null + var zoom: Int = 0 + var liteMode: Boolean = false + var devicePixelRatio: Float = 1.00f + var styles: String? = null + + init { + if (!fromJSONObject.has("width")) { + throw InvalidArgumentsError( + "GoogleMapConfig object is missing the required 'width' property" + ) + } + + if (!fromJSONObject.has("height")) { + throw InvalidArgumentsError( + "GoogleMapConfig object is missing the required 'height' property" + ) + } + + if (!fromJSONObject.has("x")) { + throw InvalidArgumentsError( + "GoogleMapConfig object is missing the required 'x' property" + ) + } + + if (!fromJSONObject.has("y")) { + throw InvalidArgumentsError( + "GoogleMapConfig object is missing the required 'y' property" + ) + } + + if (!fromJSONObject.has("zoom")) { + throw InvalidArgumentsError( + "GoogleMapConfig object is missing the required 'zoom' property" + ) + } + + if (fromJSONObject.has("devicePixelRatio")) { + devicePixelRatio = fromJSONObject.getDouble("devicePixelRatio").toFloat() + } + + if (!fromJSONObject.has("center")) { + throw InvalidArgumentsError( + "GoogleMapConfig object is missing the required 'center' property" + ) + } + + val centerJSONObject = fromJSONObject.getJSONObject("center") + + if (!centerJSONObject.has("lat") || !centerJSONObject.has("lng")) { + throw InvalidArgumentsError( + "LatLng object is missing the required 'lat' and/or 'lng' property" + ) + } + + liteMode = + fromJSONObject.has("androidLiteMode") && + fromJSONObject.getBoolean("androidLiteMode") + + width = fromJSONObject.getInt("width") + height = fromJSONObject.getInt("height") + x = fromJSONObject.getInt("x") + y = fromJSONObject.getInt("y") + zoom = fromJSONObject.getInt("zoom") + + val lat = centerJSONObject.getDouble("lat") + val lng = centerJSONObject.getDouble("lng") + center = LatLng(lat, lng) + + val cameraPosition = CameraPosition(center, zoom.toFloat(), 0.0F, 0.0F) + googleMapOptions = GoogleMapOptions().camera(cameraPosition).liteMode(liteMode) + + styles = fromJSONObject.getString("styles") + } +} diff --git a/google-maps/android/src/main/java/com/capacitorjs/plugins/googlemaps/GoogleMapErrors.kt b/google-maps/android/src/main/java/com/capacitorjs/plugins/googlemaps/GoogleMapErrors.kt new file mode 100644 index 000000000..b4fc86330 --- /dev/null +++ b/google-maps/android/src/main/java/com/capacitorjs/plugins/googlemaps/GoogleMapErrors.kt @@ -0,0 +1,105 @@ +package com.capacitorjs.plugins.googlemaps + +import org.json.JSONObject +import kotlin.Exception + +enum class GoogleMapErrors { + UNHANDLED_ERROR, INVALID_MAP_ID, MAP_NOT_FOUND, MARKER_NOT_FOUND, INVALID_ARGUMENTS, PERMISSIONS_DENIED_LOCATION, GOOGLE_MAP_NOT_AVAILABLE, BOUNDS_NOT_FOUND +} + +class GoogleMapErrorObject(val code: Int, val message: String, val extra: HashMap = HashMap()) { + private fun asJSONObject(): JSONObject { + val returnJSONObject = JSONObject() + + returnJSONObject.put("code", code) + returnJSONObject.put("message", message) + returnJSONObject.put("extra", extra) + + return returnJSONObject + } + + override fun toString(): String { + return this.asJSONObject().toString() + } +} + +fun getErrorObject(err: GoogleMapsError): GoogleMapErrorObject { + return when(err) { + is InvalidArgumentsError -> { + GoogleMapErrorObject(err.getErrorCode(), "Invalid Arguments Provided: ${err.message}.") + } + is InvalidMapIdError -> { + GoogleMapErrorObject(err.getErrorCode(), "Missing or invalid map id.") + } + is MapNotFoundError -> { + GoogleMapErrorObject(err.getErrorCode(), "Map not found for provided id.") + } + is MarkerNotFoundError -> { + GoogleMapErrorObject(err.getErrorCode(), "Marker not found for provided id.") + } + is PermissionDeniedLocation -> { + GoogleMapErrorObject(err.getErrorCode(), "Permissions denied for accessing device location.") + } + is GoogleMapNotAvailable -> { + GoogleMapErrorObject(err.getErrorCode(), "Google Map is not available.") + } + is BoundsNotFoundError -> { + GoogleMapErrorObject(err.getErrorCode(), "Google Map Bounds could not be found.") + } + else -> { + GoogleMapErrorObject(err.getErrorCode(), "Unhandled Error: ${err.message}.") + } + } +} + +fun getErrorObject(err: Exception): GoogleMapErrorObject { + return GoogleMapErrorObject(0, "Unhandled Error: ${err.message}.") +} + +open class GoogleMapsError(message: String? = ""): Throwable(message) { + open fun getErrorCode(): Int { + return GoogleMapErrors.UNHANDLED_ERROR.ordinal + } +} + +class InvalidMapIdError(message: String? = ""): GoogleMapsError(message) { + override fun getErrorCode(): Int { + return GoogleMapErrors.INVALID_MAP_ID.ordinal + } +} + +class MapNotFoundError(message: String? = ""): GoogleMapsError(message) { + override fun getErrorCode(): Int { + return GoogleMapErrors.MAP_NOT_FOUND.ordinal + } +} + +class MarkerNotFoundError(message: String? = ""): GoogleMapsError(message) { + override fun getErrorCode(): Int { + return GoogleMapErrors.MARKER_NOT_FOUND.ordinal + } +} + +class InvalidArgumentsError(message: String? = ""): GoogleMapsError(message) { + override fun getErrorCode(): Int { + return GoogleMapErrors.INVALID_ARGUMENTS.ordinal + } +} + +class PermissionDeniedLocation(message: String? = ""): GoogleMapsError(message) { + override fun getErrorCode(): Int { + return GoogleMapErrors.PERMISSIONS_DENIED_LOCATION.ordinal + } +} + +class GoogleMapNotAvailable(message: String? = ""): GoogleMapsError(message) { + override fun getErrorCode(): Int { + return GoogleMapErrors.GOOGLE_MAP_NOT_AVAILABLE.ordinal + } +} + +class BoundsNotFoundError(message: String? = ""): GoogleMapsError(message) { + override fun getErrorCode(): Int { + return GoogleMapErrors.BOUNDS_NOT_FOUND.ordinal + } +} diff --git a/google-maps/android/src/main/java/com/capacitorjs/plugins/googlemaps/GoogleMapPadding.kt b/google-maps/android/src/main/java/com/capacitorjs/plugins/googlemaps/GoogleMapPadding.kt new file mode 100644 index 000000000..c14dac52d --- /dev/null +++ b/google-maps/android/src/main/java/com/capacitorjs/plugins/googlemaps/GoogleMapPadding.kt @@ -0,0 +1,28 @@ +package com.capacitorjs.plugins.googlemaps + +import org.json.JSONObject + +class GoogleMapPadding(fromJSONObject: JSONObject) { + var top: Int = 0 + var bottom: Int = 0 + var left: Int = 0 + var right: Int = 0 + + init { + if(fromJSONObject.has("top")) { + top = fromJSONObject.getInt("top") + } + + if(fromJSONObject.has("bottom")) { + bottom = fromJSONObject.getInt("bottom") + } + + if(fromJSONObject.has("left")) { + left = fromJSONObject.getInt("left") + } + + if(fromJSONObject.has("right")) { + right = fromJSONObject.getInt("right") + } + } +} \ No newline at end of file diff --git a/google-maps/android/src/main/res/.gitkeep b/google-maps/android/src/main/res/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/google-maps/e2e-tests/.env.example b/google-maps/e2e-tests/.env.example new file mode 100644 index 000000000..f4f1a8439 --- /dev/null +++ b/google-maps/e2e-tests/.env.example @@ -0,0 +1 @@ +REACT_APP_GOOGLE_MAPS_API_KEY= \ No newline at end of file diff --git a/google-maps/e2e-tests/.gitignore b/google-maps/e2e-tests/.gitignore new file mode 100644 index 000000000..3b0b1aea6 --- /dev/null +++ b/google-maps/e2e-tests/.gitignore @@ -0,0 +1,32 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.env.local +.env.development.local +.env.test.local +.env.production.local +.vscode +.idea + +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Optional eslint cache +.eslintcache + +.ionic/* +!.ionic/e2e.env +!.ionic/wdio.config.ts diff --git a/google-maps/e2e-tests/.ionic/e2e.env b/google-maps/e2e-tests/.ionic/e2e.env new file mode 100644 index 000000000..e8b0746f9 --- /dev/null +++ b/google-maps/e2e-tests/.ionic/e2e.env @@ -0,0 +1,9 @@ +E2E_ANDROID_ACTIVITY=io.ionic.starter.MainActivity +E2E_IOS_SIMULATOR_DEVICE_NAME=iPhone 13 Pro Max +E2E_IOS_SIMULATOR_PLATFORM_VERSION=15.0 +E2E_IOS_DEVICE_NAME=iPhone 12 Pro Max +E2E_IOS_DEVICE_PLATFORM_VERSION=15.2 +E2E_ANDROID_EMULATOR_DEVICE_NAME=e2eDevice +E2E_ANDROID_EMULATOR_PLATFORM_VERSION=12 +E2E_ANDROID_DEVICE_NAME=G8X +E2E_ANDROID_DEVICE_PLATFORM_VERSION=11 \ No newline at end of file diff --git a/google-maps/e2e-tests/.ionic/wdio.config.ts b/google-maps/e2e-tests/.ionic/wdio.config.ts new file mode 100644 index 000000000..d0c57fedf --- /dev/null +++ b/google-maps/e2e-tests/.ionic/wdio.config.ts @@ -0,0 +1,174 @@ +exports.config = { + "autoCompileOpts": { + "autoCompile": true, + "tsNodeOpts": { + "transpileOnly": true + }, + "tsConfigPathsOpts": { + "paths": {}, + "baseUrl": "./" + } + }, + "runner": "local", + "specs": [ + [ + "./tests/specs/**/*.spec.ts" + ] + ], + "logLevel": "trace", + "bail": 0, + "waitforTimeout": 45000, + "connectionRetryTimeout": 120000, + "connectionRetryCount": 3, + "framework": "mocha", + "reporters": [ + "spec" + ], + "mochaOpts": { + "timeout": 1200000 + }, + "services": [ + [ + "appium", + { + "command": "appium", + "args": { + "relaxedSecurity": true + } + } + ], + [ + "chromedriver", + { + "args": [ + "--use-fake-ui-for-media-stream", + "--use-fake-device-for-media-stream" + ] + } + ] + ], + "port": 4723, + "ios:simulator": { + "platformName": "iOS", + "maxInstances": 1, + "appium:isHeadless": true, + "appium:deviceName": "iPhone 13 Pro Max", + "appium:platformVersion": "15.2", + "appium:orientation": "PORTRAIT", + "appium:automationName": "XCUITest", + "appium:app": "./.ionic/App-ios-simulator.zip", + "appium:newCommandTimeout": 240, + "appium:platformName": "iOS", + "appium:wdaLaunchTimeout": 600000 + }, + "ios:device": { + "platformName": "iOS", + "maxInstances": 1, + "appium:isHeadless": false, + "appium:deviceName": "iPhone 12 Pro Max", + "appium:platformVersion": "15.2", + "appium:orientation": "PORTRAIT", + "appium:automationName": "XCUITest", + "appium:app": "./.ionic/App-ios-simulator.zip", + "appium:newCommandTimeout": 240 + }, + "ios:browser": { + "browserName": "safari", + "platformName": "iOS", + "maxInstances": 1, + "appium:isHeadless": false, + "appium:deviceName": "iPhone 13 Pro Max", + "appium:platformVersion": "15.0", + "appium:orientation": "PORTRAIT", + "appium:automationName": "XCUITest", + "appium:newCommandTimeout": 240 + }, + "android:emulator": { + "platformName": "Android", + "maxInstances": 1, + "appium:isHeadless": true, + "appium:deviceName": "e2eDevice", + "appium:platformVersion": "11.0", + "appium:orientation": "PORTRAIT", + "appium:automationName": "UiAutomator2", + "appium:app": "./.ionic/app-debug.apk", + "appium:appWaitActivity": "io.ionic.starter.MainActivity", + "appium:newCommandTimeout": 300, + "appium:platformName": "Android", + "appium:avd": "e2eDevice", + "appium:appPackage": "io.ionic.starter", + "appium:autoGrantPermissions": true, + "appium:allowTestPackages": true, + "appium:appWaitDuration": 60000, + "appium:adbExecTimeout": 300000, + "appium:deviceReadyTimeout": 3000, + "appium:androidDeviceReadyTimeout": 3000, + "appium:avdLaunchTimeout": 300000, + "appium:avdReadyTimeout": 300000, + "appium:appWaitForLaunch": false, + "appium:avdArgs": "-no-window -noaudio -verbose -accel on -no-boot-anim -no-snapshot-save" + }, + "android:device": { + "platformName": "Android", + "maxInstances": 1, + "appium:isHeadless": false, + "appium:deviceName": "G8X", + "appium:platformVersion": "11", + "appium:orientation": "PORTRAIT", + "appium:automationName": "UiAutomator2", + "appium:app": "./.ionic/app-debug.apk", + "appium:appWaitActivity": "io.ionic.starter.MainActivity", + "appium:newCommandTimeout": 240 + }, + "android:browser": { + "platformName": "Android", + "browserName": "chrome", + "maxInstances": 1, + "appium:isHeadless": false, + "appium:deviceName": "e2eDevice", + "appium:platformVersion": "12", + "appium:orientation": "PORTRAIT", + "appium:newCommandTimeout": 240 + }, + "web:chrome": { + "maxInstances": 1, + "browserName": "chrome", + "wdio:devtoolsOptions": { + "headless": true + }, + "goog:chromeOptions": { + "prefs": { + "profile.default_content_setting_values.media_stream_camera": 1, + "profile.default_content_setting_values.media_stream_mic": 1, + "profile.default_content_setting_values.notifications": 1 + } + } + }, + "capabilities": [ + { + "platformName": "Android", + "maxInstances": 1, + "appium:isHeadless": true, + "appium:deviceName": "e2eDevice", + "appium:platformVersion": "11.0", + "appium:orientation": "PORTRAIT", + "appium:automationName": "UiAutomator2", + "appium:app": "./.ionic/app-debug.apk", + "appium:appWaitActivity": "io.ionic.starter.MainActivity", + "appium:newCommandTimeout": 300, + "appium:platformName": "Android", + "appium:avd": "e2eDevice", + "appium:appPackage": "io.ionic.starter", + "appium:autoGrantPermissions": true, + "appium:allowTestPackages": true, + "appium:appWaitDuration": 60000, + "appium:adbExecTimeout": 300000, + "appium:deviceReadyTimeout": 3000, + "appium:androidDeviceReadyTimeout": 3000, + "appium:avdLaunchTimeout": 300000, + "appium:avdReadyTimeout": 300000, + "appium:appWaitForLaunch": false, + "appium:avdArgs": "-no-window -noaudio -verbose -accel on -no-boot-anim -no-snapshot-save" + } + ] + } \ No newline at end of file diff --git a/google-maps/e2e-tests/.npmrc b/google-maps/e2e-tests/.npmrc new file mode 100644 index 000000000..9cf949503 --- /dev/null +++ b/google-maps/e2e-tests/.npmrc @@ -0,0 +1 @@ +package-lock=false \ No newline at end of file diff --git a/google-maps/e2e-tests/android/.gitignore b/google-maps/e2e-tests/android/.gitignore new file mode 100644 index 000000000..48354a3df --- /dev/null +++ b/google-maps/e2e-tests/android/.gitignore @@ -0,0 +1,101 @@ +# Using Android gitignore template: https://github.com/github/gitignore/blob/HEAD/Android.gitignore + +# Built application files +*.apk +*.aar +*.ap_ +*.aab + +# Files for the ART/Dalvik VM +*.dex + +# Java class files +*.class + +# Generated files +bin/ +gen/ +out/ +# Uncomment the following line in case you need and you don't have the release build type files in your app +# release/ + +# Gradle files +.gradle/ +build/ + +# Local configuration file (sdk path, etc) +local.properties + +# Proguard folder generated by Eclipse +proguard/ + +# Log Files +*.log + +# Android Studio Navigation editor temp files +.navigation/ + +# Android Studio captures folder +captures/ + +# IntelliJ +*.iml +.idea/workspace.xml +.idea/tasks.xml +.idea/gradle.xml +.idea/assetWizardSettings.xml +.idea/dictionaries +.idea/libraries +# Android Studio 3 in .gitignore file. +.idea/caches +.idea/modules.xml +# Comment next line if keeping position of elements in Navigation Editor is relevant for you +.idea/navEditor.xml + +# Keystore files +# Uncomment the following lines if you do not want to check your keystore files in. +#*.jks +#*.keystore + +# External native build folder generated in Android Studio 2.2 and later +.externalNativeBuild +.cxx/ + +# Google Services (e.g. APIs or Firebase) +# google-services.json + +# Freeline +freeline.py +freeline/ +freeline_project_description.json + +# fastlane +fastlane/report.xml +fastlane/Preview.html +fastlane/screenshots +fastlane/test_output +fastlane/readme.md + +# Version control +vcs.xml + +# lint +lint/intermediates/ +lint/generated/ +lint/outputs/ +lint/tmp/ +# lint/reports/ + +# Android Profiling +*.hprof + +# Cordova plugins for Capacitor +capacitor-cordova-android-plugins + +# Copied web assets +app/src/main/assets/public + +# Generated Config files +app/src/main/assets/capacitor.config.json +app/src/main/assets/capacitor.plugins.json +app/src/main/res/xml/config.xml diff --git a/google-maps/e2e-tests/android/app/.gitignore b/google-maps/e2e-tests/android/app/.gitignore new file mode 100644 index 000000000..043df802a --- /dev/null +++ b/google-maps/e2e-tests/android/app/.gitignore @@ -0,0 +1,2 @@ +/build/* +!/build/.npmkeep diff --git a/google-maps/e2e-tests/android/app/build.gradle b/google-maps/e2e-tests/android/app/build.gradle new file mode 100644 index 000000000..57aaa3040 --- /dev/null +++ b/google-maps/e2e-tests/android/app/build.gradle @@ -0,0 +1,71 @@ +plugins { + id 'com.google.android.libraries.mapsplatform.secrets-gradle-plugin' +} + +apply plugin: 'com.android.application' + +def getApiKey() { + Properties properties = new Properties() + if (project.rootProject.file('local.properties').canRead()) { + properties.load(project.rootProject.file('local.properties').newDataInputStream()) + + if(properties.containsKey("REACT_APP_GOOGLE_MAPS_API_KEY")) { + return properties['REACT_APP_GOOGLE_MAPS_API_KEY'] + } + } + return System.getenv('REACT_APP_GOOGLE_MAPS_API_KEY') + } + + +android { + compileSdkVersion rootProject.ext.compileSdkVersion + defaultConfig { + applicationId "io.ionic.starter" + minSdkVersion rootProject.ext.minSdkVersion + targetSdkVersion rootProject.ext.targetSdkVersion + versionCode 1 + versionName "1.0" + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + aaptOptions { + // Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps. + // Default: https://android.googlesource.com/platform/frameworks/base/+/282e181b58cf72b6ca770dc7ca5f91f135444502/tools/aapt/AaptAssets.cpp#61 + ignoreAssetsPattern '!.svn:!.git:!.ds_store:!*.scc:.*:!CVS:!thumbs.db:!picasa.ini:!*~' + } + manifestPlaceholders = [MAPS_API_KEY:"${getApiKey()}"] + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } +} + +repositories { + flatDir{ + dirs '../capacitor-cordova-android-plugins/src/main/libs', 'libs' + } +} + +dependencies { + implementation fileTree(include: ['*.jar'], dir: 'libs') + implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion" + implementation "androidx.coordinatorlayout:coordinatorlayout:$androidxCoordinatorLayoutVersion" + implementation "androidx.core:core-splashscreen:$coreSplashScreenVersion" + implementation project(':capacitor-android') + testImplementation "junit:junit:$junitVersion" + androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion" + androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion" + implementation project(':capacitor-cordova-android-plugins') +} + +apply from: 'capacitor.build.gradle' + +try { + def servicesJSON = file('google-services.json') + if (servicesJSON.text) { + apply plugin: 'com.google.gms.google-services' + } +} catch(Exception e) { + logger.info("google-services.json not found, google-services plugin not applied. Push Notifications won't work") +} diff --git a/google-maps/e2e-tests/android/app/capacitor.build.gradle b/google-maps/e2e-tests/android/app/capacitor.build.gradle new file mode 100644 index 000000000..8f79d5e32 --- /dev/null +++ b/google-maps/e2e-tests/android/app/capacitor.build.gradle @@ -0,0 +1,23 @@ +// DO NOT EDIT THIS FILE! IT IS GENERATED EACH TIME "capacitor update" IS RUN + +android { + compileOptions { + sourceCompatibility JavaVersion.VERSION_11 + targetCompatibility JavaVersion.VERSION_11 + } +} + +apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle" +dependencies { + implementation project(':capacitor-app') + implementation project(':capacitor-google-maps') + implementation project(':capacitor-haptics') + implementation project(':capacitor-keyboard') + implementation project(':capacitor-status-bar') + +} + + +if (hasProperty('postBuildExtras')) { + postBuildExtras() +} diff --git a/google-maps/e2e-tests/android/app/proguard-rules.pro b/google-maps/e2e-tests/android/app/proguard-rules.pro new file mode 100644 index 000000000..f1b424510 --- /dev/null +++ b/google-maps/e2e-tests/android/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/google-maps/e2e-tests/android/app/src/androidTest/java/com/getcapacitor/myapp/ExampleInstrumentedTest.java b/google-maps/e2e-tests/android/app/src/androidTest/java/com/getcapacitor/myapp/ExampleInstrumentedTest.java new file mode 100644 index 000000000..f2c2217ef --- /dev/null +++ b/google-maps/e2e-tests/android/app/src/androidTest/java/com/getcapacitor/myapp/ExampleInstrumentedTest.java @@ -0,0 +1,26 @@ +package com.getcapacitor.myapp; + +import static org.junit.Assert.*; + +import android.content.Context; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.platform.app.InstrumentationRegistry; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * Instrumented test, which will execute on an Android device. + * + * @see Testing documentation + */ +@RunWith(AndroidJUnit4.class) +public class ExampleInstrumentedTest { + + @Test + public void useAppContext() throws Exception { + // Context of the app under test. + Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); + + assertEquals("com.getcapacitor.app", appContext.getPackageName()); + } +} diff --git a/google-maps/e2e-tests/android/app/src/main/AndroidManifest.xml b/google-maps/e2e-tests/android/app/src/main/AndroidManifest.xml new file mode 100644 index 000000000..fdf347882 --- /dev/null +++ b/google-maps/e2e-tests/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/google-maps/e2e-tests/android/app/src/main/assets/capacitor.config.json b/google-maps/e2e-tests/android/app/src/main/assets/capacitor.config.json new file mode 100644 index 000000000..a22dfc2b9 --- /dev/null +++ b/google-maps/e2e-tests/android/app/src/main/assets/capacitor.config.json @@ -0,0 +1,6 @@ +{ + "appId": "io.ionic.starter", + "appName": "e2e-tests", + "webDir": "build", + "bundledWebRuntime": false +} diff --git a/google-maps/e2e-tests/android/app/src/main/assets/capacitor.plugins.json b/google-maps/e2e-tests/android/app/src/main/assets/capacitor.plugins.json new file mode 100644 index 000000000..08a494550 --- /dev/null +++ b/google-maps/e2e-tests/android/app/src/main/assets/capacitor.plugins.json @@ -0,0 +1,22 @@ +[ + { + "pkg": "@capacitor/app", + "classpath": "com.capacitorjs.plugins.app.AppPlugin" + }, + { + "pkg": "@capacitor/google-maps", + "classpath": "com.capacitorjs.plugins.googlemaps.CapacitorGoogleMapsPlugin" + }, + { + "pkg": "@capacitor/haptics", + "classpath": "com.capacitorjs.plugins.haptics.HapticsPlugin" + }, + { + "pkg": "@capacitor/keyboard", + "classpath": "com.capacitorjs.plugins.keyboard.KeyboardPlugin" + }, + { + "pkg": "@capacitor/status-bar", + "classpath": "com.capacitorjs.plugins.statusbar.StatusBarPlugin" + } +] diff --git a/google-maps/e2e-tests/android/app/src/main/java/io/ionic/starter/MainActivity.java b/google-maps/e2e-tests/android/app/src/main/java/io/ionic/starter/MainActivity.java new file mode 100644 index 000000000..73e3a98d4 --- /dev/null +++ b/google-maps/e2e-tests/android/app/src/main/java/io/ionic/starter/MainActivity.java @@ -0,0 +1,5 @@ +package io.ionic.starter; + +import com.getcapacitor.BridgeActivity; + +public class MainActivity extends BridgeActivity {} diff --git a/google-maps/e2e-tests/android/app/src/main/res/drawable-land-hdpi/splash.png b/google-maps/e2e-tests/android/app/src/main/res/drawable-land-hdpi/splash.png new file mode 100644 index 000000000..e31573b4f Binary files /dev/null and b/google-maps/e2e-tests/android/app/src/main/res/drawable-land-hdpi/splash.png differ diff --git a/google-maps/e2e-tests/android/app/src/main/res/drawable-land-mdpi/splash.png b/google-maps/e2e-tests/android/app/src/main/res/drawable-land-mdpi/splash.png new file mode 100644 index 000000000..f7a64923e Binary files /dev/null and b/google-maps/e2e-tests/android/app/src/main/res/drawable-land-mdpi/splash.png differ diff --git a/google-maps/e2e-tests/android/app/src/main/res/drawable-land-xhdpi/splash.png b/google-maps/e2e-tests/android/app/src/main/res/drawable-land-xhdpi/splash.png new file mode 100644 index 000000000..807725501 Binary files /dev/null and b/google-maps/e2e-tests/android/app/src/main/res/drawable-land-xhdpi/splash.png differ diff --git a/google-maps/e2e-tests/android/app/src/main/res/drawable-land-xxhdpi/splash.png b/google-maps/e2e-tests/android/app/src/main/res/drawable-land-xxhdpi/splash.png new file mode 100644 index 000000000..14c6c8fe3 Binary files /dev/null and b/google-maps/e2e-tests/android/app/src/main/res/drawable-land-xxhdpi/splash.png differ diff --git a/google-maps/e2e-tests/android/app/src/main/res/drawable-land-xxxhdpi/splash.png b/google-maps/e2e-tests/android/app/src/main/res/drawable-land-xxxhdpi/splash.png new file mode 100644 index 000000000..244ca2506 Binary files /dev/null and b/google-maps/e2e-tests/android/app/src/main/res/drawable-land-xxxhdpi/splash.png differ diff --git a/google-maps/e2e-tests/android/app/src/main/res/drawable-port-hdpi/splash.png b/google-maps/e2e-tests/android/app/src/main/res/drawable-port-hdpi/splash.png new file mode 100644 index 000000000..74faaa583 Binary files /dev/null and b/google-maps/e2e-tests/android/app/src/main/res/drawable-port-hdpi/splash.png differ diff --git a/google-maps/e2e-tests/android/app/src/main/res/drawable-port-mdpi/splash.png b/google-maps/e2e-tests/android/app/src/main/res/drawable-port-mdpi/splash.png new file mode 100644 index 000000000..e944f4ad4 Binary files /dev/null and b/google-maps/e2e-tests/android/app/src/main/res/drawable-port-mdpi/splash.png differ diff --git a/google-maps/e2e-tests/android/app/src/main/res/drawable-port-xhdpi/splash.png b/google-maps/e2e-tests/android/app/src/main/res/drawable-port-xhdpi/splash.png new file mode 100644 index 000000000..564a82ff9 Binary files /dev/null and b/google-maps/e2e-tests/android/app/src/main/res/drawable-port-xhdpi/splash.png differ diff --git a/google-maps/e2e-tests/android/app/src/main/res/drawable-port-xxhdpi/splash.png b/google-maps/e2e-tests/android/app/src/main/res/drawable-port-xxhdpi/splash.png new file mode 100644 index 000000000..bfabe6871 Binary files /dev/null and b/google-maps/e2e-tests/android/app/src/main/res/drawable-port-xxhdpi/splash.png differ diff --git a/google-maps/e2e-tests/android/app/src/main/res/drawable-port-xxxhdpi/splash.png b/google-maps/e2e-tests/android/app/src/main/res/drawable-port-xxxhdpi/splash.png new file mode 100644 index 000000000..692907126 Binary files /dev/null and b/google-maps/e2e-tests/android/app/src/main/res/drawable-port-xxxhdpi/splash.png differ diff --git a/google-maps/e2e-tests/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/google-maps/e2e-tests/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 000000000..c7bd21dbd --- /dev/null +++ b/google-maps/e2e-tests/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + diff --git a/google-maps/e2e-tests/android/app/src/main/res/drawable/ic_launcher_background.xml b/google-maps/e2e-tests/android/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 000000000..d5fccc538 --- /dev/null +++ b/google-maps/e2e-tests/android/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/google-maps/e2e-tests/android/app/src/main/res/drawable/splash.png b/google-maps/e2e-tests/android/app/src/main/res/drawable/splash.png new file mode 100644 index 000000000..f7a64923e Binary files /dev/null and b/google-maps/e2e-tests/android/app/src/main/res/drawable/splash.png differ diff --git a/google-maps/e2e-tests/android/app/src/main/res/layout/activity_main.xml b/google-maps/e2e-tests/android/app/src/main/res/layout/activity_main.xml new file mode 100644 index 000000000..b5ad13870 --- /dev/null +++ b/google-maps/e2e-tests/android/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,12 @@ + + + + + diff --git a/google-maps/e2e-tests/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/google-maps/e2e-tests/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 000000000..036d09bc5 --- /dev/null +++ b/google-maps/e2e-tests/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/google-maps/e2e-tests/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/google-maps/e2e-tests/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 000000000..036d09bc5 --- /dev/null +++ b/google-maps/e2e-tests/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/google-maps/e2e-tests/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/google-maps/e2e-tests/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 000000000..c023e5059 Binary files /dev/null and b/google-maps/e2e-tests/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/google-maps/e2e-tests/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png b/google-maps/e2e-tests/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png new file mode 100644 index 000000000..2127973b2 Binary files /dev/null and b/google-maps/e2e-tests/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png differ diff --git a/google-maps/e2e-tests/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/google-maps/e2e-tests/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png new file mode 100644 index 000000000..b441f37d6 Binary files /dev/null and b/google-maps/e2e-tests/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ diff --git a/google-maps/e2e-tests/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/google-maps/e2e-tests/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 000000000..72905b854 Binary files /dev/null and b/google-maps/e2e-tests/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/google-maps/e2e-tests/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png b/google-maps/e2e-tests/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png new file mode 100644 index 000000000..8ed0605c2 Binary files /dev/null and b/google-maps/e2e-tests/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png differ diff --git a/google-maps/e2e-tests/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/google-maps/e2e-tests/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png new file mode 100644 index 000000000..9502e47a2 Binary files /dev/null and b/google-maps/e2e-tests/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ diff --git a/google-maps/e2e-tests/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/google-maps/e2e-tests/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 000000000..4d1e07710 Binary files /dev/null and b/google-maps/e2e-tests/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/google-maps/e2e-tests/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png b/google-maps/e2e-tests/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png new file mode 100644 index 000000000..df0f15880 Binary files /dev/null and b/google-maps/e2e-tests/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png differ diff --git a/google-maps/e2e-tests/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/google-maps/e2e-tests/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 000000000..853db043d Binary files /dev/null and b/google-maps/e2e-tests/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ diff --git a/google-maps/e2e-tests/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/google-maps/e2e-tests/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 000000000..6cdf97c11 Binary files /dev/null and b/google-maps/e2e-tests/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/google-maps/e2e-tests/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png b/google-maps/e2e-tests/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png new file mode 100644 index 000000000..2960cbb61 Binary files /dev/null and b/google-maps/e2e-tests/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png differ diff --git a/google-maps/e2e-tests/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/google-maps/e2e-tests/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 000000000..8e3093a86 Binary files /dev/null and b/google-maps/e2e-tests/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/google-maps/e2e-tests/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/google-maps/e2e-tests/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 000000000..46de6e255 Binary files /dev/null and b/google-maps/e2e-tests/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/google-maps/e2e-tests/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/google-maps/e2e-tests/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png new file mode 100644 index 000000000..d2ea9abed Binary files /dev/null and b/google-maps/e2e-tests/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png differ diff --git a/google-maps/e2e-tests/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/google-maps/e2e-tests/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 000000000..a40d73e9c Binary files /dev/null and b/google-maps/e2e-tests/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ diff --git a/google-maps/e2e-tests/android/app/src/main/res/values/ic_launcher_background.xml b/google-maps/e2e-tests/android/app/src/main/res/values/ic_launcher_background.xml new file mode 100644 index 000000000..c5d5899fd --- /dev/null +++ b/google-maps/e2e-tests/android/app/src/main/res/values/ic_launcher_background.xml @@ -0,0 +1,4 @@ + + + #FFFFFF + \ No newline at end of file diff --git a/google-maps/e2e-tests/android/app/src/main/res/values/strings.xml b/google-maps/e2e-tests/android/app/src/main/res/values/strings.xml new file mode 100644 index 000000000..9128e1571 --- /dev/null +++ b/google-maps/e2e-tests/android/app/src/main/res/values/strings.xml @@ -0,0 +1,7 @@ + + + e2e-tests + e2e-tests + io.ionic.starter + io.ionic.starter + diff --git a/google-maps/e2e-tests/android/app/src/main/res/values/styles.xml b/google-maps/e2e-tests/android/app/src/main/res/values/styles.xml new file mode 100644 index 000000000..be874e54a --- /dev/null +++ b/google-maps/e2e-tests/android/app/src/main/res/values/styles.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/google-maps/e2e-tests/android/app/src/main/res/xml/config.xml b/google-maps/e2e-tests/android/app/src/main/res/xml/config.xml new file mode 100644 index 000000000..1b1b0e0dc --- /dev/null +++ b/google-maps/e2e-tests/android/app/src/main/res/xml/config.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/google-maps/e2e-tests/android/app/src/main/res/xml/file_paths.xml b/google-maps/e2e-tests/android/app/src/main/res/xml/file_paths.xml new file mode 100644 index 000000000..bd0c4d80d --- /dev/null +++ b/google-maps/e2e-tests/android/app/src/main/res/xml/file_paths.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/google-maps/e2e-tests/android/app/src/test/java/com/getcapacitor/myapp/ExampleUnitTest.java b/google-maps/e2e-tests/android/app/src/test/java/com/getcapacitor/myapp/ExampleUnitTest.java new file mode 100644 index 000000000..029732784 --- /dev/null +++ b/google-maps/e2e-tests/android/app/src/test/java/com/getcapacitor/myapp/ExampleUnitTest.java @@ -0,0 +1,18 @@ +package com.getcapacitor.myapp; + +import static org.junit.Assert.*; + +import org.junit.Test; + +/** + * Example local unit test, which will execute on the development machine (host). + * + * @see Testing documentation + */ +public class ExampleUnitTest { + + @Test + public void addition_isCorrect() throws Exception { + assertEquals(4, 2 + 2); + } +} diff --git a/google-maps/e2e-tests/android/build.gradle b/google-maps/e2e-tests/android/build.gradle new file mode 100644 index 000000000..802124099 --- /dev/null +++ b/google-maps/e2e-tests/android/build.gradle @@ -0,0 +1,30 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. + +buildscript { + + repositories { + google() + mavenCentral() + } + dependencies { + classpath 'com.android.tools.build:gradle:7.1.1' + classpath 'com.google.gms:google-services:4.3.5' + classpath "com.google.android.libraries.mapsplatform.secrets-gradle-plugin:secrets-gradle-plugin:2.0.0" + + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +apply from: "variables.gradle" + +allprojects { + repositories { + google() + mavenCentral() + } +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/google-maps/e2e-tests/android/capacitor.settings.gradle b/google-maps/e2e-tests/android/capacitor.settings.gradle new file mode 100644 index 000000000..a0346a2fb --- /dev/null +++ b/google-maps/e2e-tests/android/capacitor.settings.gradle @@ -0,0 +1,18 @@ +// DO NOT EDIT THIS FILE! IT IS GENERATED EACH TIME "capacitor update" IS RUN +include ':capacitor-android' +project(':capacitor-android').projectDir = new File('../node_modules/@capacitor/android/capacitor') + +include ':capacitor-app' +project(':capacitor-app').projectDir = new File('../node_modules/@capacitor/app/android') + +include ':capacitor-google-maps' +project(':capacitor-google-maps').projectDir = new File('../../android') + +include ':capacitor-haptics' +project(':capacitor-haptics').projectDir = new File('../node_modules/@capacitor/haptics/android') + +include ':capacitor-keyboard' +project(':capacitor-keyboard').projectDir = new File('../node_modules/@capacitor/keyboard/android') + +include ':capacitor-status-bar' +project(':capacitor-status-bar').projectDir = new File('../node_modules/@capacitor/status-bar/android') diff --git a/storage/android/gradle.properties b/google-maps/e2e-tests/android/gradle.properties similarity index 100% rename from storage/android/gradle.properties rename to google-maps/e2e-tests/android/gradle.properties diff --git a/google-maps/e2e-tests/android/gradle/wrapper/gradle-wrapper.jar b/google-maps/e2e-tests/android/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 000000000..41d9927a4 Binary files /dev/null and b/google-maps/e2e-tests/android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/google-maps/e2e-tests/android/gradle/wrapper/gradle-wrapper.properties b/google-maps/e2e-tests/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..92f06b50f --- /dev/null +++ b/google-maps/e2e-tests/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-all.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/google-maps/e2e-tests/android/gradlew b/google-maps/e2e-tests/android/gradlew new file mode 100755 index 000000000..1b6c78733 --- /dev/null +++ b/google-maps/e2e-tests/android/gradlew @@ -0,0 +1,234 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +APP_NAME="Gradle" +APP_BASE_NAME=${0##*/} + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/google-maps/e2e-tests/android/gradlew.bat b/google-maps/e2e-tests/android/gradlew.bat new file mode 100644 index 000000000..ac1b06f93 --- /dev/null +++ b/google-maps/e2e-tests/android/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/google-maps/e2e-tests/android/settings.gradle b/google-maps/e2e-tests/android/settings.gradle new file mode 100644 index 000000000..3b4431d77 --- /dev/null +++ b/google-maps/e2e-tests/android/settings.gradle @@ -0,0 +1,5 @@ +include ':app' +include ':capacitor-cordova-android-plugins' +project(':capacitor-cordova-android-plugins').projectDir = new File('./capacitor-cordova-android-plugins/') + +apply from: 'capacitor.settings.gradle' \ No newline at end of file diff --git a/google-maps/e2e-tests/android/variables.gradle b/google-maps/e2e-tests/android/variables.gradle new file mode 100644 index 000000000..777bd7e87 --- /dev/null +++ b/google-maps/e2e-tests/android/variables.gradle @@ -0,0 +1,16 @@ +ext { + minSdkVersion = 22 + compileSdkVersion = 32 + targetSdkVersion = 32 + androidxActivityVersion = '1.4.0' + androidxAppCompatVersion = '1.4.2' + androidxCoordinatorLayoutVersion = '1.2.0' + androidxCoreVersion = '1.8.0' + androidxFragmentVersion = '1.4.1' + coreSplashScreenVersion = '1.0.0-rc01' + androidxWebkitVersion = '1.4.0' + junitVersion = '4.13.2' + androidxJunitVersion = '1.1.3' + androidxEspressoCoreVersion = '3.4.0' + cordovaAndroidVersion = '10.1.1' +} \ No newline at end of file diff --git a/google-maps/e2e-tests/capacitor.config.json b/google-maps/e2e-tests/capacitor.config.json new file mode 100644 index 000000000..a22dfc2b9 --- /dev/null +++ b/google-maps/e2e-tests/capacitor.config.json @@ -0,0 +1,6 @@ +{ + "appId": "io.ionic.starter", + "appName": "e2e-tests", + "webDir": "build", + "bundledWebRuntime": false +} diff --git a/google-maps/e2e-tests/ionic.config.json b/google-maps/e2e-tests/ionic.config.json new file mode 100644 index 000000000..43bec2727 --- /dev/null +++ b/google-maps/e2e-tests/ionic.config.json @@ -0,0 +1,7 @@ +{ + "name": "e2e-tests", + "integrations": { + "capacitor": {} + }, + "type": "react" +} diff --git a/google-maps/e2e-tests/ionic.e2e.config.ts b/google-maps/e2e-tests/ionic.e2e.config.ts new file mode 100644 index 000000000..4912652cb --- /dev/null +++ b/google-maps/e2e-tests/ionic.e2e.config.ts @@ -0,0 +1,36 @@ +/* eslint-disable import/no-anonymous-default-export */ +export default { + appRootDir: '.', + wdio: { + logLevel: 'trace', // options are "trace" or "error" + 'ios:simulator': { + 'appium:platformName': 'iOS', + 'appium:deviceName': 'iPhone 13 Pro Max', + 'appium:platformVersion': '15.2', + 'appium:isHeadless': true, + 'appium:wdaLaunchTimeout': 600000, + }, + 'ios:device': {}, + 'android:emulator': { + 'appium:platformName': 'Android', + 'appium:deviceName': 'e2eDevice', + 'appium:avd': 'e2eDevice', + 'appium:isHeadless': true, + 'appium:platformVersion': '11.0', + 'appium:appPackage': 'io.ionic.starter', + 'appium:appWaitActivity': 'io.ionic.starter.MainActivity', + 'appium:autoGrantPermissions': true, + 'appium:allowTestPackages': true, + 'appium:appWaitDuration': 60000, + 'appium:adbExecTimeout': 300000, + 'appium:deviceReadyTimeout': 3000, + 'appium:androidDeviceReadyTimeout': 3000, + 'appium:avdLaunchTimeout': 300000, + 'appium:avdReadyTimeout': 300000, + 'appium:appWaitForLaunch': false, + 'appium:newCommandTimeout': 300, + 'appium:avdArgs': '-no-window -noaudio -verbose -accel on -no-boot-anim -no-snapshot-save', + }, + 'android:device': {}, + }, +}; diff --git a/google-maps/e2e-tests/ios/.gitignore b/google-maps/e2e-tests/ios/.gitignore new file mode 100644 index 000000000..75e8c5aec --- /dev/null +++ b/google-maps/e2e-tests/ios/.gitignore @@ -0,0 +1,9 @@ +App/build +App/Pods +App/Podfile.lock +App/App/public +DerivedData +xcuserdata + +# Cordova plugins for Capacitor +capacitor-cordova-ios-plugins diff --git a/google-maps/e2e-tests/ios/App/App.xcodeproj/project.pbxproj b/google-maps/e2e-tests/ios/App/App.xcodeproj/project.pbxproj new file mode 100644 index 000000000..0bd7aa926 --- /dev/null +++ b/google-maps/e2e-tests/ios/App/App.xcodeproj/project.pbxproj @@ -0,0 +1,420 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 48; + objects = { + +/* Begin PBXBuildFile section */ + 2FAD9763203C412B000D30F8 /* config.xml in Resources */ = {isa = PBXBuildFile; fileRef = 2FAD9762203C412B000D30F8 /* config.xml */; }; + 50379B232058CBB4000EE86E /* capacitor.config.json in Resources */ = {isa = PBXBuildFile; fileRef = 50379B222058CBB4000EE86E /* capacitor.config.json */; }; + 504EC3081FED79650016851F /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 504EC3071FED79650016851F /* AppDelegate.swift */; }; + 504EC30D1FED79650016851F /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 504EC30B1FED79650016851F /* Main.storyboard */; }; + 504EC30F1FED79650016851F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 504EC30E1FED79650016851F /* Assets.xcassets */; }; + 504EC3121FED79650016851F /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 504EC3101FED79650016851F /* LaunchScreen.storyboard */; }; + 50B271D11FEDC1A000F3C39B /* public in Resources */ = {isa = PBXBuildFile; fileRef = 50B271D01FEDC1A000F3C39B /* public */; }; + A084ECDBA7D38E1E42DFC39D /* Pods_App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AF277DCFFFF123FFC6DF26C7 /* Pods_App.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 2FAD9762203C412B000D30F8 /* config.xml */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = config.xml; sourceTree = ""; }; + 50379B222058CBB4000EE86E /* capacitor.config.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = capacitor.config.json; sourceTree = ""; }; + 504EC3041FED79650016851F /* App.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = App.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 504EC3071FED79650016851F /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 504EC30C1FED79650016851F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 504EC30E1FED79650016851F /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 504EC3111FED79650016851F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 504EC3131FED79650016851F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 50B271D01FEDC1A000F3C39B /* public */ = {isa = PBXFileReference; lastKnownFileType = folder; path = public; sourceTree = ""; }; + AF277DCFFFF123FFC6DF26C7 /* Pods_App.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_App.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + AF51FD2D460BCFE21FA515B2 /* Pods-App.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App.release.xcconfig"; path = "Pods/Target Support Files/Pods-App/Pods-App.release.xcconfig"; sourceTree = ""; }; + FC68EB0AF532CFC21C3344DD /* Pods-App.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App.debug.xcconfig"; path = "Pods/Target Support Files/Pods-App/Pods-App.debug.xcconfig"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 504EC3011FED79650016851F /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + A084ECDBA7D38E1E42DFC39D /* Pods_App.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 27E2DDA53C4D2A4D1A88CE4A /* Frameworks */ = { + isa = PBXGroup; + children = ( + AF277DCFFFF123FFC6DF26C7 /* Pods_App.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 504EC2FB1FED79650016851F = { + isa = PBXGroup; + children = ( + 504EC3061FED79650016851F /* App */, + 504EC3051FED79650016851F /* Products */, + 7F8756D8B27F46E3366F6CEA /* Pods */, + 27E2DDA53C4D2A4D1A88CE4A /* Frameworks */, + ); + sourceTree = ""; + }; + 504EC3051FED79650016851F /* Products */ = { + isa = PBXGroup; + children = ( + 504EC3041FED79650016851F /* App.app */, + ); + name = Products; + sourceTree = ""; + }; + 504EC3061FED79650016851F /* App */ = { + isa = PBXGroup; + children = ( + 50379B222058CBB4000EE86E /* capacitor.config.json */, + 504EC3071FED79650016851F /* AppDelegate.swift */, + 504EC30B1FED79650016851F /* Main.storyboard */, + 504EC30E1FED79650016851F /* Assets.xcassets */, + 504EC3101FED79650016851F /* LaunchScreen.storyboard */, + 504EC3131FED79650016851F /* Info.plist */, + 2FAD9762203C412B000D30F8 /* config.xml */, + 50B271D01FEDC1A000F3C39B /* public */, + ); + path = App; + sourceTree = ""; + }; + 7F8756D8B27F46E3366F6CEA /* Pods */ = { + isa = PBXGroup; + children = ( + FC68EB0AF532CFC21C3344DD /* Pods-App.debug.xcconfig */, + AF51FD2D460BCFE21FA515B2 /* Pods-App.release.xcconfig */, + ); + name = Pods; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 504EC3031FED79650016851F /* App */ = { + isa = PBXNativeTarget; + buildConfigurationList = 504EC3161FED79650016851F /* Build configuration list for PBXNativeTarget "App" */; + buildPhases = ( + 6634F4EFEBD30273BCE97C65 /* [CP] Check Pods Manifest.lock */, + 504EC3001FED79650016851F /* Sources */, + 504EC3011FED79650016851F /* Frameworks */, + 504EC3021FED79650016851F /* Resources */, + 9592DBEFFC6D2A0C8D5DEB22 /* [CP] Embed Pods Frameworks */, + 1EB4CF9A9223BA57362D699F /* [CP] Copy Pods Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = App; + productName = App; + productReference = 504EC3041FED79650016851F /* App.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 504EC2FC1FED79650016851F /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0920; + LastUpgradeCheck = 0920; + TargetAttributes = { + 504EC3031FED79650016851F = { + CreatedOnToolsVersion = 9.2; + LastSwiftMigration = 1100; + ProvisioningStyle = Automatic; + }; + }; + }; + buildConfigurationList = 504EC2FF1FED79650016851F /* Build configuration list for PBXProject "App" */; + compatibilityVersion = "Xcode 8.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 504EC2FB1FED79650016851F; + productRefGroup = 504EC3051FED79650016851F /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 504EC3031FED79650016851F /* App */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 504EC3021FED79650016851F /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 504EC3121FED79650016851F /* LaunchScreen.storyboard in Resources */, + 50B271D11FEDC1A000F3C39B /* public in Resources */, + 504EC30F1FED79650016851F /* Assets.xcassets in Resources */, + 50379B232058CBB4000EE86E /* capacitor.config.json in Resources */, + 504EC30D1FED79650016851F /* Main.storyboard in Resources */, + 2FAD9763203C412B000D30F8 /* config.xml in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 1EB4CF9A9223BA57362D699F /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Copy Pods Resources"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-App/Pods-App-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; + 6634F4EFEBD30273BCE97C65 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-App-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 9592DBEFFC6D2A0C8D5DEB22 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Embed Pods Frameworks"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-App/Pods-App-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 504EC3001FED79650016851F /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 504EC3081FED79650016851F /* AppDelegate.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 504EC30B1FED79650016851F /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 504EC30C1FED79650016851F /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 504EC3101FED79650016851F /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 504EC3111FED79650016851F /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 504EC3141FED79650016851F /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 504EC3151FED79650016851F /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 504EC3171FED79650016851F /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = FC68EB0AF532CFC21C3344DD /* Pods-App.debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 3HC6X87AYW; + INFOPLIST_FILE = App/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\""; + PRODUCT_BUNDLE_IDENTIFIER = io.ionic.googlemaps; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 504EC3181FED79650016851F /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = AF51FD2D460BCFE21FA515B2 /* Pods-App.release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 3HC6X87AYW; + INFOPLIST_FILE = App/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = io.ionic.googlemaps; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = ""; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 504EC2FF1FED79650016851F /* Build configuration list for PBXProject "App" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 504EC3141FED79650016851F /* Debug */, + 504EC3151FED79650016851F /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 504EC3161FED79650016851F /* Build configuration list for PBXNativeTarget "App" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 504EC3171FED79650016851F /* Debug */, + 504EC3181FED79650016851F /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 504EC2FC1FED79650016851F /* Project object */; +} diff --git a/google-maps/e2e-tests/ios/App/App.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/google-maps/e2e-tests/ios/App/App.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..42daef8a1 --- /dev/null +++ b/google-maps/e2e-tests/ios/App/App.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/google-maps/e2e-tests/ios/App/App.xcworkspace/contents.xcworkspacedata b/google-maps/e2e-tests/ios/App/App.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..b301e824b --- /dev/null +++ b/google-maps/e2e-tests/ios/App/App.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/storage/ios/Plugin.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/google-maps/e2e-tests/ios/App/App.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist similarity index 100% rename from storage/ios/Plugin.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist rename to google-maps/e2e-tests/ios/App/App.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/google-maps/e2e-tests/ios/App/App/AppDelegate.swift b/google-maps/e2e-tests/ios/App/App/AppDelegate.swift new file mode 100644 index 000000000..53e376039 --- /dev/null +++ b/google-maps/e2e-tests/ios/App/App/AppDelegate.swift @@ -0,0 +1,60 @@ +import UIKit +import Capacitor + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + + var window: UIWindow? + + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + // Override point for customization after application launch. + return true + } + + func applicationWillResignActive(_ application: UIApplication) { + // 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. + // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. + } + + func applicationDidEnterBackground(_ application: UIApplication) { + // 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. + // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. + } + + func applicationWillEnterForeground(_ application: UIApplication) { + // 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. + } + + func applicationDidBecomeActive(_ application: UIApplication) { + // 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. + } + + func applicationWillTerminate(_ application: UIApplication) { + // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. + } + + func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool { + // Called when the app was launched with a url. Feel free to add additional processing here, + // but if you want the App API to support tracking app url opens, make sure to keep this call + return ApplicationDelegateProxy.shared.application(app, open: url, options: options) + } + + func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool { + // Called when the app was launched with an activity, including Universal Links. + // Feel free to add additional processing here, but if you want the App API to support + // tracking app url opens, make sure to keep this call + return ApplicationDelegateProxy.shared.application(application, continue: userActivity, restorationHandler: restorationHandler) + } + + override func touchesBegan(_ touches: Set, with event: UIEvent?) { + super.touchesBegan(touches, with: event) + + let statusBarRect = UIApplication.shared.statusBarFrame + guard let touchPoint = event?.allTouches?.first?.location(in: self.window) else { return } + + if statusBarRect.contains(touchPoint) { + NotificationCenter.default.post(name: .capacitorStatusBarTapped, object: nil) + } + } + +} diff --git a/google-maps/e2e-tests/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@1x.png b/google-maps/e2e-tests/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@1x.png new file mode 100644 index 000000000..2f503741c Binary files /dev/null and b/google-maps/e2e-tests/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@1x.png differ diff --git a/google-maps/e2e-tests/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@2x-1.png b/google-maps/e2e-tests/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@2x-1.png new file mode 100644 index 000000000..dd72c1ce8 Binary files /dev/null and b/google-maps/e2e-tests/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@2x-1.png differ diff --git a/google-maps/e2e-tests/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@2x.png b/google-maps/e2e-tests/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@2x.png new file mode 100644 index 000000000..dd72c1ce8 Binary files /dev/null and b/google-maps/e2e-tests/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@2x.png differ diff --git a/google-maps/e2e-tests/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@3x.png b/google-maps/e2e-tests/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@3x.png new file mode 100644 index 000000000..7fbf0a84a Binary files /dev/null and b/google-maps/e2e-tests/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@3x.png differ diff --git a/google-maps/e2e-tests/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@1x.png b/google-maps/e2e-tests/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@1x.png new file mode 100644 index 000000000..f996ea18f Binary files /dev/null and b/google-maps/e2e-tests/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@1x.png differ diff --git a/google-maps/e2e-tests/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@2x-1.png b/google-maps/e2e-tests/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@2x-1.png new file mode 100644 index 000000000..bb2935fb7 Binary files /dev/null and b/google-maps/e2e-tests/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@2x-1.png differ diff --git a/google-maps/e2e-tests/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@2x.png b/google-maps/e2e-tests/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@2x.png new file mode 100644 index 000000000..bb2935fb7 Binary files /dev/null and b/google-maps/e2e-tests/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@2x.png differ diff --git a/google-maps/e2e-tests/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@3x.png b/google-maps/e2e-tests/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@3x.png new file mode 100644 index 000000000..21d16e5b1 Binary files /dev/null and b/google-maps/e2e-tests/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@3x.png differ diff --git a/google-maps/e2e-tests/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@1x.png b/google-maps/e2e-tests/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@1x.png new file mode 100644 index 000000000..dd72c1ce8 Binary files /dev/null and b/google-maps/e2e-tests/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@1x.png differ diff --git a/google-maps/e2e-tests/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@2x-1.png b/google-maps/e2e-tests/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@2x-1.png new file mode 100644 index 000000000..ff0754519 Binary files /dev/null and b/google-maps/e2e-tests/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@2x-1.png differ diff --git a/google-maps/e2e-tests/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@2x.png b/google-maps/e2e-tests/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@2x.png new file mode 100644 index 000000000..ff0754519 Binary files /dev/null and b/google-maps/e2e-tests/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@2x.png differ diff --git a/google-maps/e2e-tests/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@3x.png b/google-maps/e2e-tests/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@3x.png new file mode 100644 index 000000000..3401fa887 Binary files /dev/null and b/google-maps/e2e-tests/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@3x.png differ diff --git a/google-maps/e2e-tests/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-512@2x.png b/google-maps/e2e-tests/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-512@2x.png new file mode 100644 index 000000000..adf6ba01d Binary files /dev/null and b/google-maps/e2e-tests/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-512@2x.png differ diff --git a/google-maps/e2e-tests/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-60x60@2x.png b/google-maps/e2e-tests/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-60x60@2x.png new file mode 100644 index 000000000..ffd0da781 Binary files /dev/null and b/google-maps/e2e-tests/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-60x60@2x.png differ diff --git a/google-maps/e2e-tests/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-60x60@3x.png b/google-maps/e2e-tests/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-60x60@3x.png new file mode 100644 index 000000000..90aea7cd2 Binary files /dev/null and b/google-maps/e2e-tests/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-60x60@3x.png differ diff --git a/google-maps/e2e-tests/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-76x76@1x.png b/google-maps/e2e-tests/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-76x76@1x.png new file mode 100644 index 000000000..2f5eafb6b Binary files /dev/null and b/google-maps/e2e-tests/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-76x76@1x.png differ diff --git a/google-maps/e2e-tests/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-76x76@2x.png b/google-maps/e2e-tests/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-76x76@2x.png new file mode 100644 index 000000000..89c8d0448 Binary files /dev/null and b/google-maps/e2e-tests/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-76x76@2x.png differ diff --git a/google-maps/e2e-tests/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-83.5x83.5@2x.png b/google-maps/e2e-tests/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-83.5x83.5@2x.png new file mode 100644 index 000000000..ef541c90a Binary files /dev/null and b/google-maps/e2e-tests/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-83.5x83.5@2x.png differ diff --git a/google-maps/e2e-tests/ios/App/App/Assets.xcassets/AppIcon.appiconset/Contents.json b/google-maps/e2e-tests/ios/App/App/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 000000000..90eea7ec7 --- /dev/null +++ b/google-maps/e2e-tests/ios/App/App/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,116 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "AppIcon-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "AppIcon-20x20@3x.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "AppIcon-29x29@2x-1.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "AppIcon-29x29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "AppIcon-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "AppIcon-40x40@3x.png", + "scale" : "3x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "AppIcon-60x60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "AppIcon-60x60@3x.png", + "scale" : "3x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "AppIcon-20x20@1x.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "AppIcon-20x20@2x-1.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "AppIcon-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "AppIcon-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "AppIcon-40x40@1x.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "AppIcon-40x40@2x-1.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "AppIcon-76x76@1x.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "AppIcon-76x76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "AppIcon-83.5x83.5@2x.png", + "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "AppIcon-512@2x.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/google-maps/e2e-tests/ios/App/App/Assets.xcassets/Contents.json b/google-maps/e2e-tests/ios/App/App/Assets.xcassets/Contents.json new file mode 100644 index 000000000..da4a164c9 --- /dev/null +++ b/google-maps/e2e-tests/ios/App/App/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/google-maps/e2e-tests/ios/App/App/Assets.xcassets/Splash.imageset/Contents.json b/google-maps/e2e-tests/ios/App/App/Assets.xcassets/Splash.imageset/Contents.json new file mode 100644 index 000000000..d7d96a67c --- /dev/null +++ b/google-maps/e2e-tests/ios/App/App/Assets.xcassets/Splash.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "splash-2732x2732-2.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "splash-2732x2732-1.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "splash-2732x2732.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/google-maps/e2e-tests/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732-1.png b/google-maps/e2e-tests/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732-1.png new file mode 100644 index 000000000..33ea6c970 Binary files /dev/null and b/google-maps/e2e-tests/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732-1.png differ diff --git a/google-maps/e2e-tests/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732-2.png b/google-maps/e2e-tests/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732-2.png new file mode 100644 index 000000000..33ea6c970 Binary files /dev/null and b/google-maps/e2e-tests/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732-2.png differ diff --git a/google-maps/e2e-tests/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732.png b/google-maps/e2e-tests/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732.png new file mode 100644 index 000000000..33ea6c970 Binary files /dev/null and b/google-maps/e2e-tests/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732.png differ diff --git a/google-maps/e2e-tests/ios/App/App/Base.lproj/LaunchScreen.storyboard b/google-maps/e2e-tests/ios/App/App/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 000000000..e7ae5d780 --- /dev/null +++ b/google-maps/e2e-tests/ios/App/App/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/google-maps/e2e-tests/ios/App/App/Base.lproj/Main.storyboard b/google-maps/e2e-tests/ios/App/App/Base.lproj/Main.storyboard new file mode 100644 index 000000000..b44df7be8 --- /dev/null +++ b/google-maps/e2e-tests/ios/App/App/Base.lproj/Main.storyboard @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/google-maps/e2e-tests/ios/App/App/Info.plist b/google-maps/e2e-tests/ios/App/App/Info.plist new file mode 100644 index 000000000..578b0a476 --- /dev/null +++ b/google-maps/e2e-tests/ios/App/App/Info.plist @@ -0,0 +1,56 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleDisplayName + e2e-tests + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + + NSLocationWhenInUseUsageDescription + Using Test App Location + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIViewControllerBasedStatusBarAppearance + + + diff --git a/google-maps/e2e-tests/ios/App/App/capacitor.config.json b/google-maps/e2e-tests/ios/App/App/capacitor.config.json new file mode 100644 index 000000000..a22dfc2b9 --- /dev/null +++ b/google-maps/e2e-tests/ios/App/App/capacitor.config.json @@ -0,0 +1,6 @@ +{ + "appId": "io.ionic.starter", + "appName": "e2e-tests", + "webDir": "build", + "bundledWebRuntime": false +} diff --git a/google-maps/e2e-tests/ios/App/App/config.xml b/google-maps/e2e-tests/ios/App/App/config.xml new file mode 100644 index 000000000..1b1b0e0dc --- /dev/null +++ b/google-maps/e2e-tests/ios/App/App/config.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/google-maps/e2e-tests/ios/App/Podfile b/google-maps/e2e-tests/ios/App/Podfile new file mode 100644 index 000000000..a67b0a85f --- /dev/null +++ b/google-maps/e2e-tests/ios/App/Podfile @@ -0,0 +1,22 @@ +platform :ios, '13.0' +use_frameworks! + +# workaround to avoid Xcode caching of Pods that requires +# Product -> Clean Build Folder after new Cordova plugins installed +# Requires CocoaPods 1.6 or newer +install! 'cocoapods', :disable_input_output_paths => true + +def capacitor_pods + pod 'Capacitor', :path => '../../node_modules/@capacitor/ios' + pod 'CapacitorCordova', :path => '../../node_modules/@capacitor/ios' + pod 'CapacitorApp', :path => '../../node_modules/@capacitor/app' + pod 'CapacitorGoogleMaps', :path => '../../..' + pod 'CapacitorHaptics', :path => '../../node_modules/@capacitor/haptics' + pod 'CapacitorKeyboard', :path => '../../node_modules/@capacitor/keyboard' + pod 'CapacitorStatusBar', :path => '../../node_modules/@capacitor/status-bar' +end + +target 'App' do + capacitor_pods + # Add your Pods here +end diff --git a/google-maps/e2e-tests/package.json b/google-maps/e2e-tests/package.json new file mode 100644 index 000000000..d819b540e --- /dev/null +++ b/google-maps/e2e-tests/package.json @@ -0,0 +1,86 @@ +{ + "name": "e2e-tests", + "version": "0.0.1", + "private": true, + "dependencies": { + "@capacitor/android": "^4.0.1", + "@capacitor/app": "4.0.1", + "@capacitor/core": "^4.0.1", + "@capacitor/google-maps": "file:../", + "@capacitor/haptics": "4.0.1", + "@capacitor/ios": "^4.0.1", + "@capacitor/keyboard": "4.0.1", + "@capacitor/status-bar": "4.0.1", + "@ionic/react": "^6.0.0", + "@ionic/react-router": "^6.0.0", + "@testing-library/jest-dom": "^5.11.9", + "@testing-library/react": "^11.2.5", + "@testing-library/user-event": "^12.6.3", + "@types/jest": "^26.0.20", + "@types/node": "^12.19.15", + "@types/react": "^16.14.3", + "@types/react-dom": "^16.9.10", + "@types/react-router": "^5.1.11", + "@types/react-router-dom": "^5.1.7", + "ionicons": "^5.4.0", + "react": "^17.0.1", + "react-dom": "^17.0.1", + "react-router": "^5.2.0", + "react-router-dom": "^5.2.0", + "react-scripts": "^5.0.0", + "typescript": "^4.1.3", + "web-vitals": "^0.2.4", + "workbox-background-sync": "^5.1.4", + "workbox-broadcast-update": "^5.1.4", + "workbox-cacheable-response": "^5.1.4", + "workbox-core": "^5.1.4", + "workbox-expiration": "^5.1.4", + "workbox-google-analytics": "^5.1.4", + "workbox-navigation-preload": "^5.1.4", + "workbox-precaching": "^5.1.4", + "workbox-range-requests": "^5.1.4", + "workbox-routing": "^5.1.4", + "workbox-strategies": "^5.1.4", + "workbox-streams": "^5.1.4" + }, + "scripts": { + "start": "react-scripts start", + "build": "react-scripts build", + "test": "react-scripts test --transformIgnorePatterns 'node_modules/(?!(@ionic/react|@ionic/react-router|@ionic/core|@stencil/core|ionicons)/)'", + "eject": "react-scripts eject", + "sync": "npm run build && npx cap sync", + "ionic-e2e": "ionic-e2e", + "e2e:ios:build": "npm run ionic-e2e build ios:simulator", + "e2e:ios:run": "npm run ionic-e2e run ios:simulator", + "e2e:ios": "E2E_MODE=simulator && npm run sync && npm run e2e:ios:build && npm run e2e:ios:run", + "e2e:android:build": "npm run ionic-e2e build android:emulator", + "e2e:android:run": "npm run ionic-e2e run android:emulator", + "e2e:android": "./scripts/run_Android_E2E.sh", + "e2e:prepare": "./scripts/build_local_package.sh" + }, + "eslintConfig": { + "extends": [ + "react-app", + "react-app/jest" + ] + }, + "browserslist": { + "production": [ + ">0.2%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + }, + "devDependencies": { + "@capacitor/cli": "^4.0.0", + "@ionic/e2e": "0.2.0-next.6", + "@ionic/e2e-components-ionic": "0.2.0-next.6", + "appium": "^1.22.1" + }, + "description": "An Ionic project" +} \ No newline at end of file diff --git a/google-maps/e2e-tests/public/assets/icon/favicon.png b/google-maps/e2e-tests/public/assets/icon/favicon.png new file mode 100644 index 000000000..51888a7bb Binary files /dev/null and b/google-maps/e2e-tests/public/assets/icon/favicon.png differ diff --git a/google-maps/e2e-tests/public/assets/icon/icon.png b/google-maps/e2e-tests/public/assets/icon/icon.png new file mode 100644 index 000000000..a7f63748a Binary files /dev/null and b/google-maps/e2e-tests/public/assets/icon/icon.png differ diff --git a/google-maps/e2e-tests/public/assets/icon/marker.svg b/google-maps/e2e-tests/public/assets/icon/marker.svg new file mode 100644 index 000000000..d935e94c4 --- /dev/null +++ b/google-maps/e2e-tests/public/assets/icon/marker.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/google-maps/e2e-tests/public/assets/icon/pin.png b/google-maps/e2e-tests/public/assets/icon/pin.png new file mode 100644 index 000000000..adc3a413c Binary files /dev/null and b/google-maps/e2e-tests/public/assets/icon/pin.png differ diff --git a/google-maps/e2e-tests/public/assets/shapes.svg b/google-maps/e2e-tests/public/assets/shapes.svg new file mode 100644 index 000000000..d370b4dcc --- /dev/null +++ b/google-maps/e2e-tests/public/assets/shapes.svg @@ -0,0 +1 @@ + diff --git a/google-maps/e2e-tests/public/index.html b/google-maps/e2e-tests/public/index.html new file mode 100644 index 000000000..25b753b06 --- /dev/null +++ b/google-maps/e2e-tests/public/index.html @@ -0,0 +1,31 @@ + + + + + Ionic App + + + + + + + + + + + + + + + + + + + +
+ + + diff --git a/google-maps/e2e-tests/public/manifest.json b/google-maps/e2e-tests/public/manifest.json new file mode 100644 index 000000000..580870547 --- /dev/null +++ b/google-maps/e2e-tests/public/manifest.json @@ -0,0 +1,21 @@ +{ + "short_name": "Ionic App", + "name": "My Ionic App", + "icons": [ + { + "src": "assets/icon/favicon.png", + "sizes": "64x64 32x32 24x24 16x16", + "type": "image/x-icon" + }, + { + "src": "assets/icon/icon.png", + "type": "image/png", + "sizes": "512x512", + "purpose": "maskable" + } + ], + "start_url": ".", + "display": "standalone", + "theme_color": "#ffffff", + "background_color": "#ffffff" +} diff --git a/google-maps/e2e-tests/scripts/build_local_package.sh b/google-maps/e2e-tests/scripts/build_local_package.sh new file mode 100755 index 000000000..bb97fa3b8 --- /dev/null +++ b/google-maps/e2e-tests/scripts/build_local_package.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +cd ../ && npm install && npm run pack-local +cd ./e2e-tests && npm install ../capacitor-google-maps.tgz \ No newline at end of file diff --git a/google-maps/e2e-tests/scripts/create_E2E_AVD.sh b/google-maps/e2e-tests/scripts/create_E2E_AVD.sh new file mode 100755 index 000000000..3cbbb5c24 --- /dev/null +++ b/google-maps/e2e-tests/scripts/create_E2E_AVD.sh @@ -0,0 +1,55 @@ +#!/bin/bash + +CPU_ARCH=`uname -p`"" + +SDKMANAGER=$ANDROID_SDK_ROOT/cmdline-tools/latest/bin/sdkmanager +AVDMANAGER=$ANDROID_SDK_ROOT/cmdline-tools/latest/bin/avdmanager +ABD=$ANDROID_SDK_ROOT/platform-tools/adb +EMU=$ANDROID_SDK_ROOT/emulator/emulator + +E2E_DEVICE_EXISTS=`${EMU} -list-avds | grep -c e2eDevice` + +if [[ $E2E_DEVICE_EXISTS -lt 1 ]]; then + echo "Creating e2eDevice AVD..." + echo "" + + echo "CPU_ARCH: $CPU_ARCH" + echo "JAVA_HOME: $JAVA_HOME" + echo "ANDROID_SDK_ROOT: $ANDROID_SDK_ROOT" + echo "" + echo "--------------------------" + echo "" + + echo "Accepting Lics..." + sh -c \yes | ${SDKMANAGER} --licenses > /dev/null + + echo "Installing build-tools..." + ${SDKMANAGER} --install 'build-tools;31.0.0' platform-tools 'platforms;android-31' + echo "Installing emulator..." + ${SDKMANAGER} --install emulator --channel=0 + echo "Installing sys-image..." + + # If we are on arm (m1 mac) use arm images, else use x86_64 + if [ "$CPU_ARCH" = "arm" ]; then + ${SDKMANAGER} --install 'system-images;android-31;google_apis;arm64-v8a' --channel=0 + else + ${SDKMANAGER} --install 'system-images;android-31;google_apis;x86_64' --channel=0 + fi + + echo "Killing all running emulators..." + ${ABD} devices | grep emulator | cut -f1 | while read line; do ${ABD} -s $line emu kill; done; + + echo "Creating AVD..." + if [ "$CPU_ARCH" = "arm" ]; then + ${AVDMANAGER} --verbose create avd -n e2eDevice -k "system-images;android-31;google_apis;arm64-v8a" --device "pixel_3a" + else + ${AVDMANAGER} --verbose create avd -n e2eDevice -k "system-images;android-31;google_apis;x86_64" --device "pixel_3a" + fi + +else + echo "e2eDevice AVD exists!" +fi + +echo "" + + diff --git a/google-maps/e2e-tests/scripts/run_Android_E2E.sh b/google-maps/e2e-tests/scripts/run_Android_E2E.sh new file mode 100755 index 000000000..b61184b1e --- /dev/null +++ b/google-maps/e2e-tests/scripts/run_Android_E2E.sh @@ -0,0 +1,63 @@ +#!/bin/bash + +set -e + +if [[ -z "$ANDROID_SDK_ROOT" ]]; then + export ANDROID_SDK_ROOT=~/Library/Android/sdk +fi +if [[ -n "$JAVA_HOME_11_X64" ]]; then + export JAVA_HOME=$JAVA_HOME_11_X64 +else + export JAVA_HOME=/Applications/Android\ Studio.app/Contents/jre/Contents/Home +fi + +# Check to see if we are not in a Github Action +if [[ -z $GITHUB_ACTION ]]; then + + ABD=$ANDROID_SDK_ROOT/platform-tools/adb + EMU=$ANDROID_SDK_ROOT/emulator/emulator + + echo "Not in GH Action. Checking for e2eDevice Emulator..." + $PWD/scripts/create_E2E_AVD.sh + + set +e + + echo 'Searching for e2eDevice...' + devicesCount=`${ABD} devices | grep -c emulator` + + if [[ $devicesCount =~ 0 ]]; then + echo 'Starting emulator...' + ${EMU} -avd "e2eDevice" -no-window -noaudio -accel on -no-boot-anim -no-snapshot-save & + fi + + bootanim="" + failcounter=0 + timeout_in_sec=360 + + until [[ "$bootanim" =~ "stopped" ]]; do + bootanim=`${ABD} -e shell getprop init.svc.bootanim 2>&1 &` + if [[ "$bootanim" =~ "device not found" || "$bootanim" =~ "device offline" + || "$bootanim" =~ "running" ]]; then + let "failcounter += 1" + echo "Waiting for emulator to start" + if [[ $failcounter -gt timeout_in_sec ]]; then + echo "Timeout ($timeout_in_sec seconds) reached; failed to start emulator" + exit 1 + fi + fi + sleep 1 + done + + echo "Emulator is ready" + + sleep 4 + + set -e + +fi + +E2E_MODE=simulator + +npm run sync +npm run e2e:android:build +npm run e2e:android:run diff --git a/google-maps/e2e-tests/src/App.test.tsx b/google-maps/e2e-tests/src/App.test.tsx new file mode 100644 index 000000000..8c927a8d7 --- /dev/null +++ b/google-maps/e2e-tests/src/App.test.tsx @@ -0,0 +1,8 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import App from './App'; + +test('renders without crashing', () => { + const { baseElement } = render(); + expect(baseElement).toBeDefined(); +}); diff --git a/google-maps/e2e-tests/src/App.tsx b/google-maps/e2e-tests/src/App.tsx new file mode 100644 index 000000000..43cd30b4e --- /dev/null +++ b/google-maps/e2e-tests/src/App.tsx @@ -0,0 +1,59 @@ +import { IonApp, IonRouterOutlet, IonSplitPane, setupIonicReact } from '@ionic/react'; +import { IonReactRouter } from '@ionic/react-router'; +import { Redirect, Route } from 'react-router-dom'; +import Menu from './components/Menu'; + +/* Core CSS required for Ionic components to work properly */ +import '@ionic/react/css/core.css'; + +/* Basic CSS for apps built with Ionic */ +import '@ionic/react/css/normalize.css'; +import '@ionic/react/css/structure.css'; +import '@ionic/react/css/typography.css'; + +/* Optional CSS utils that can be commented out */ +import '@ionic/react/css/padding.css'; +import '@ionic/react/css/float-elements.css'; +import '@ionic/react/css/text-alignment.css'; +import '@ionic/react/css/text-transformation.css'; +import '@ionic/react/css/flex-utils.css'; +import '@ionic/react/css/display.css'; + +/* Theme variables */ +import './theme/variables.css'; + +import { getRouterSetup } from './routes'; +import Home from './pages/Home'; + +setupIonicReact(); + +const App: React.FC = () => { + const routes = getRouterSetup(); + + return ( + + + + + + + + + + + + {routes.map((route, idx) => { + return ( + + + + ); + })} + + + + + ); +}; + +export default App; diff --git a/google-maps/e2e-tests/src/components/BaseTestingPage.tsx b/google-maps/e2e-tests/src/components/BaseTestingPage.tsx new file mode 100644 index 000000000..cce706faa --- /dev/null +++ b/google-maps/e2e-tests/src/components/BaseTestingPage.tsx @@ -0,0 +1,26 @@ +import { IonButtons, IonContent, IonHeader, IonMenuButton, IonPage, IonTitle, IonToolbar } from '@ionic/react'; + +const BaseTestingPage: React.FC<{ children?: React.ReactNode; pageTitle: string }> = ({ children, pageTitle }) => { + return ( + + + + + + + {pageTitle} + + + + + + {pageTitle} + + + {children} + + + ); +}; + +export default BaseTestingPage; diff --git a/google-maps/e2e-tests/src/components/Menu.css b/google-maps/e2e-tests/src/components/Menu.css new file mode 100644 index 000000000..f435049ab --- /dev/null +++ b/google-maps/e2e-tests/src/components/Menu.css @@ -0,0 +1,114 @@ +ion-menu ion-content { + --background: var(--ion-item-background, var(--ion-background-color, #fff)); +} + +ion-menu.md ion-content { + --padding-start: 8px; + --padding-end: 8px; + --padding-top: 20px; + --padding-bottom: 20px; +} + +ion-menu.md ion-list { + padding: 20px 0; +} + +ion-menu.md ion-note { + margin-bottom: 30px; +} + +ion-menu.md ion-list-header, +ion-menu.md ion-note { + padding-left: 10px; +} + +ion-menu.md ion-list#inbox-list { + border-bottom: 1px solid var(--ion-color-step-150, #d7d8da); +} + +ion-menu.md ion-list#inbox-list ion-list-header { + font-size: 22px; + font-weight: 600; + min-height: 20px; +} + +ion-menu.md ion-list#labels-list ion-list-header { + font-size: 16px; + margin-bottom: 18px; + color: #757575; + min-height: 26px; +} + +ion-menu.md ion-item { + --padding-start: 10px; + --padding-end: 10px; + border-radius: 4px; +} + +ion-menu.md ion-item.selected { + --background: rgba(var(--ion-color-primary-rgb), 0.14); +} + +ion-menu.md ion-item.selected ion-icon { + color: var(--ion-color-primary); +} + +ion-menu.md ion-item ion-icon { + color: #616e7e; +} + +ion-menu.md ion-item ion-label { + font-weight: 500; +} + +ion-menu.ios ion-content { + --padding-bottom: 20px; +} + +ion-menu.ios ion-list { + padding: 20px 0 0 0; +} + +ion-menu.ios ion-note { + line-height: 24px; + margin-bottom: 20px; +} + +ion-menu.ios ion-item { + --padding-start: 16px; + --padding-end: 16px; + --min-height: 50px; +} + +ion-menu.ios ion-item ion-icon { + font-size: 24px; + color: #73849a; +} + +ion-menu.ios ion-item .selected ion-icon { + color: var(--ion-color-primary); +} + +ion-menu.ios ion-list#labels-list ion-list-header { + margin-bottom: 8px; +} + +ion-menu.ios ion-list-header, +ion-menu.ios ion-note { + padding-left: 16px; + padding-right: 16px; +} + +ion-menu.ios ion-note { + margin-bottom: 8px; +} + +ion-note { + display: inline-block; + font-size: 16px; + color: var(--ion-color-medium-shade); +} + +ion-item.selected { + --color: var(--ion-color-primary); +} diff --git a/google-maps/e2e-tests/src/components/Menu.tsx b/google-maps/e2e-tests/src/components/Menu.tsx new file mode 100644 index 000000000..92351ff0f --- /dev/null +++ b/google-maps/e2e-tests/src/components/Menu.tsx @@ -0,0 +1,61 @@ +import { IonContent, IonIcon, IonItem, IonLabel, IonList, IonListHeader, IonMenu, IonMenuToggle } from '@ionic/react'; +import { useLocation } from 'react-router-dom'; +import './Menu.css'; +import { useEffect, useState } from 'react'; +import { getMenuList, RouteGroup } from '../routes'; +import { homeOutline } from 'ionicons/icons'; + +const Menu: React.FC = () => { + const location = useLocation(); + const [menu, setMenu] = useState([]); + + useEffect(() => { + setMenu(getMenuList()); + }, []); + + return ( + + + + + + + Home + + + + {menu.map((routeGroup, indx) => { + return ( + + {routeGroup.groupName} + {routeGroup.pages.map((routeDescription, index) => { + return ( + + + + {routeDescription.title} + + + ); + })} + + ); + })} + + + ); +}; + +export default Menu; diff --git a/google-maps/e2e-tests/src/index.tsx b/google-maps/e2e-tests/src/index.tsx new file mode 100644 index 000000000..c421f457b --- /dev/null +++ b/google-maps/e2e-tests/src/index.tsx @@ -0,0 +1,22 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import App from './App'; +import * as serviceWorkerRegistration from './serviceWorkerRegistration'; +import reportWebVitals from './reportWebVitals'; + +ReactDOM.render( + + + , + document.getElementById('root') +); + +// If you want your app to work offline and load faster, you can change +// unregister() to register() below. Note this comes with some pitfalls. +// Learn more about service workers: https://cra.link/PWA +serviceWorkerRegistration.unregister(); + +// If you want to start measuring performance in your app, pass a function +// to log results (for example: reportWebVitals(console.log)) +// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals +reportWebVitals(); diff --git a/google-maps/e2e-tests/src/pages/Home.tsx b/google-maps/e2e-tests/src/pages/Home.tsx new file mode 100644 index 000000000..ff61c2ff4 --- /dev/null +++ b/google-maps/e2e-tests/src/pages/Home.tsx @@ -0,0 +1,13 @@ +import BaseTestingPage from '../components/BaseTestingPage'; + +const Home: React.FC = () => { + return ( + +

+ Choose a testing page from the menu to get started! +

+
+ ); +}; + +export default Home; diff --git a/google-maps/e2e-tests/src/pages/Map/ConfigMap.tsx b/google-maps/e2e-tests/src/pages/Map/ConfigMap.tsx new file mode 100644 index 000000000..b73b65e2f --- /dev/null +++ b/google-maps/e2e-tests/src/pages/Map/ConfigMap.tsx @@ -0,0 +1,267 @@ +import { useState } from 'react'; +import { GoogleMap } from '@capacitor/google-maps'; +import { MapType } from '@capacitor/google-maps'; +import { IonButton, IonTextarea } from '@ionic/react'; +import BaseTestingPage from '../../components/BaseTestingPage'; + +const ConfigMapPage: React.FC = () => { + const [maps, setMaps] = useState([]); + const [commandOutput, setCommandOutput] = useState(''); + const apiKey = process.env.REACT_APP_GOOGLE_MAPS_API_KEY; + + + async function createMaps() { + setCommandOutput(""); + setMaps([]); + try { + const mapRef1 = document.getElementById("config_map1")! + const mapRef2 = document.getElementById("config_map2")! + + const newMap1 = await GoogleMap.create({ + element: mapRef1, + id: "test-map", + apiKey: apiKey!, + config: { + center: { + lat: 33.6, + lng: -117.9, + }, + zoom: 8 + } + }); + + const newMap2 = await GoogleMap.create({ + element: mapRef2, + id: "test-map2", + apiKey: apiKey!, + config: { + center: { + lat: -33.6, + lng: 117.9, + }, + zoom: 6, + } + }); + + setMaps([newMap1, newMap2]); + setCommandOutput('Maps created'); + } catch(err: any) { + setCommandOutput(err.message); + } + } + + async function moveCameras() { + setCommandOutput(""); + try { + const map1 = maps[0]; + await map1.setCamera({ + coordinate: { + lat: 36.716871, + lng: -119.767456 + }, + angle: 45, + bearing: 200, + zoom: 12, + animate: true, + animationDuration: 50, + }) + + const map2 = maps[1]; + await map2.setCamera({ + coordinate: { + lat: -31.931186, + lng: 115.856323 + }, + angle: 45, + bearing: 200, + zoom: 12, + animate: true, + animationDuration: 50, + }) + } catch(err: any) { + setCommandOutput(err.message); + } + } + + async function setMapType() { + setCommandOutput(""); + try { + const map1 = maps[0]; + await map1.setMapType(MapType.Terrain) + + const map2 = maps[1]; + await map2.setMapType(MapType.Satellite) + } catch(err: any) { + setCommandOutput(err.message); + } + } + + async function enableIndoorMaps() { + setCommandOutput(""); + try { + const map1 = maps[0]; + await map1.setCamera({ + coordinate: { + lat: 44.854682, + lng: -93.241997 + }, + angle: 0, + bearing: 0, + zoom: 17, + animate: true, + animationDuration: 50, + }) + await map1.enableIndoorMaps(true); + } catch(err: any) { + setCommandOutput(err.message); + } + } + + async function enableTrafficLayer() { + setCommandOutput(""); + try { + const map1 = maps[0]; + await map1.enableTrafficLayer(true); + await map1.setCamera({ + zoom: 10, + animate: true, + animationDuration: 50, + }) + + const map2 = maps[0]; + await map2.enableTrafficLayer(true); + } catch(err: any) { + setCommandOutput(err.message); + } + } + + async function disableTrafficLayer() { + setCommandOutput(""); + try { + const map1 = maps[0]; + await map1.enableTrafficLayer(false); + + const map2 = maps[0]; + await map2.enableTrafficLayer(false); + } catch(err: any) { + setCommandOutput(err.message); + } + } + + async function destroyMaps() { + setCommandOutput(""); + try { + if (maps) { + for (let map of maps) { + await map.destroy(); + } + setCommandOutput('Maps destroyed'); + } + } catch (err: any) { + setCommandOutput(err.message); + } + } + + async function showCurrentLocation() { + setCommandOutput(""); + try { + const map1 = maps[0]; + await map1.setCamera({ + zoom: 1, + animate: true, + animationDuration: 50, + }) + await map1.enableCurrentLocation(true); + + const map2 = maps[1]; + await map2.setCamera({ + zoom: 1, + animate: true, + animationDuration: 50, + }); + await map2.enableCurrentLocation(true); + } catch(err: any) { + setCommandOutput(err.message); + } + } + + async function hideCurrentLocation() { + setCommandOutput(""); + try { + const map1 = maps[0]; + await map1.enableCurrentLocation(false); + + const map2 = maps[1]; + await map2.enableCurrentLocation(false); + } catch(err: any) { + setCommandOutput(err.message); + } + } + + async function showAccessibilityElements() { + setCommandOutput(""); + try { + const map1 = maps[0]; + await map1.enableAccessibilityElements(true); + + const map2 = maps[1]; + await map2.enableAccessibilityElements(true); + } catch(err: any) { + setCommandOutput(err.message); + } + } + + async function hideAccessibilityElements() { + setCommandOutput(""); + try { + const map1 = maps[0]; + await map1.enableAccessibilityElements(false); + + const map2 = maps[1]; + await map2.enableAccessibilityElements(false); + } catch(err: any) { + setCommandOutput(err.message); + } + } + + return ( + +
+ + Create Maps + + + Destroy Maps + + Move Camera + Set Map Type + Enable Indoor Maps + Enable Traffic Layer + Disable Traffic Layer + Show Current Location + Hide Current Location + Show Acc. Elements + Hide Acc. Elements +
+
+ +
+ + +
+ ) +} + +export default ConfigMapPage; \ No newline at end of file diff --git a/google-maps/e2e-tests/src/pages/Map/CreateAndDestroyMap.tsx b/google-maps/e2e-tests/src/pages/Map/CreateAndDestroyMap.tsx new file mode 100644 index 000000000..7eb613029 --- /dev/null +++ b/google-maps/e2e-tests/src/pages/Map/CreateAndDestroyMap.tsx @@ -0,0 +1,204 @@ +import { useState } from 'react'; +import { GoogleMap } from '@capacitor/google-maps'; +import { IonButton, IonTextarea } from '@ionic/react'; +import BaseTestingPage from '../../components/BaseTestingPage'; + +const CreateAndDestroyMapPage: React.FC = () => { + const [maps, setMaps] = useState([]); + const [commandOutput, setCommandOutput] = useState(''); + const apiKey = process.env.REACT_APP_GOOGLE_MAPS_API_KEY; + + const onMapReady = (data: any) => { + setCommandOutput(`MAP (${data.mapId}) IS READY`); + }; + + const onMapClick = (data: any) => { + setCommandOutput( + `MAP (${data.mapId}) CLICKED @ (${data.latitude}, ${data.longitude})`, + ); + }; + + const onMapBoundsChanged = (data: any) => { + setCommandOutput( + `MAP (${data.mapId}) BOUNDS CHANGED @ (${JSON.stringify(data.bounds)})`, + ); + } + + async function createMaps() { + setCommandOutput(''); + setMaps([]); + try { + const mapRef1 = document.getElementById('map1')!; + const mapRef2 = document.getElementById('map2')!; + + const newMap1 = await GoogleMap.create( + { + element: mapRef1, + id: 'test-map', + apiKey: apiKey!, + config: { + center: { + lat: 33.6, + lng: -117.9, + }, + zoom: 8, + }, + forceCreate: true, + }, + onMapReady, + ); + + const newMap2 = await GoogleMap.create( + { + element: mapRef2, + id: 'test-map2', + apiKey: apiKey!, + config: { + center: { + lat: -33.6, + lng: 117.9, + }, + zoom: 6, + }, + forceCreate: true, + }, + onMapReady, + ); + + setMaps([newMap1, newMap2]); + setCommandOutput('Maps created'); + } catch (err: any) { + setCommandOutput(err.message); + } + } + + async function setOnMapClickListeners() { + setCommandOutput(''); + try { + if (maps) { + for (let map of maps) { + map.setOnMapClickListener(onMapClick); + } + setCommandOutput('Map Click Listeners Set'); + } + } catch (err: any) { + setCommandOutput(err.message); + } + } + + async function setOnMapBoundsChangedListeners() { + setCommandOutput(''); + try { + if (maps) { + for (let map of maps) { + map.setOnBoundsChangedListener(onMapBoundsChanged); + } + setCommandOutput('Map Bounds Changed Listeners Set'); + } + } catch (err: any) { + setCommandOutput(err.message); + } + } + + async function removeOnMapClickListeners() { + setCommandOutput(''); + try { + if (maps) { + for (let map of maps) { + map.removeAllMapListeners(); + } + + setCommandOutput('Map Click Listeners Destroyed'); + } + } catch (err: any) { + setCommandOutput(err.message); + } + } + + async function destroyMaps() { + setCommandOutput(''); + try { + if (maps) { + for (let map of maps) { + await map.destroy(); + } + setMaps([]); + setCommandOutput('Maps destroyed'); + } + } catch (err: any) { + setCommandOutput(err.message); + } + } + + async function getBounds() { + setCommandOutput(''); + try { + const bounds = await maps[0].getMapBounds(); + setCommandOutput(JSON.stringify(bounds)); + } catch (err: any) { + setCommandOutput(err.message); + } + } + + return ( + +
+ + Create Maps + + + Set On Map Click Listeners + + + Set On Map Bounds Changed Listeners + + + Get Current Bounds + + + Remove On Map Click Listeners + + + Destroy Maps + +
+
+ +
+ + +
+ ); +}; + +export default CreateAndDestroyMapPage; diff --git a/google-maps/e2e-tests/src/pages/Markers/AddAndRemoveMarkers.tsx b/google-maps/e2e-tests/src/pages/Markers/AddAndRemoveMarkers.tsx new file mode 100644 index 000000000..ffa8ac0cf --- /dev/null +++ b/google-maps/e2e-tests/src/pages/Markers/AddAndRemoveMarkers.tsx @@ -0,0 +1,164 @@ +import { useState } from 'react'; +import { GoogleMap } from '@capacitor/google-maps'; +import { IonButton, IonTextarea } from '@ionic/react'; +import BaseTestingPage from '../../components/BaseTestingPage'; + +const AddAndRemoveMarkers: React.FC = () => { + const [map, setMap] = useState(null); + const [markerId, setMarkerId] = useState(""); + const [commandOutput, setCommandOutput] = useState(''); + const apiKey = process.env.REACT_APP_GOOGLE_MAPS_API_KEY; + + const onMarkerClick = (data: any) => { + setCommandOutput(`MARKER (${data.markerId}) WAS CLICKED ON MAP (${data.mapId})`); + } + + const onMarkerDragStart = (data: any) => { + setCommandOutput(`MARKER (${data.markerId}) DRAG STARTED ON MAP (${data.mapId})`); + } + + const onMarkerDrag = (data: any) => { + setCommandOutput(`MARKER (${data.markerId}) IS BEING DRAGGED ON MAP (${data.mapId})`); + } + + const onMarkerDragEnd = (data: any) => { + setCommandOutput(`MARKER (${data.markerId}) DRAG ENDED ON MAP (${data.mapId})`); + } + + + const onInfoWindowClick = (data: any) => { + setCommandOutput(`INFO WINDOW (${data.markerId}) WAS CLICKED ON MAP (${data.mapId})`); + } + + async function createMap() { + try { + const mapRef1 = document.getElementById("markers_map1")! + const newMap = await GoogleMap.create({ + element: mapRef1, + id: "test-map", + apiKey: apiKey!, + config: { + center: { + lat: 33.6, + lng: -117.9, + }, + zoom: 8, + }, + }); + setMap(newMap); + + setCommandOutput("Map created"); + + } catch (err: any) { + setCommandOutput(err.message); + } + } + + async function setOnMarkerClickListener() { + map?.setOnMarkerClickListener(onMarkerClick); + map?.setOnMarkerDragStartListener(onMarkerDragStart); + map?.setOnMarkerDragListener(onMarkerDrag); + map?.setOnMarkerDragEndListener(onMarkerDragEnd); + map?.setOnInfoWindowClickListener(onInfoWindowClick); + setCommandOutput('Set On Marker Click / Drag Listeners!'); + } + + async function removeOnMarkerClickListener() { + map?.setOnMarkerClickListener(); + map?.setOnMarkerDragStartListener(); + map?.setOnMarkerDragListener(); + map?.setOnMarkerDragEndListener(); + map?.setOnInfoWindowClickListener(); + setCommandOutput('Removed On Marker Click / Drag Listeners!'); + } + + async function addMarker() { + try { + if (!map) { + throw new Error("map not created"); + } + + const id = await map.addMarker({ + coordinate: { + lat: 33.6, + lng: -117.9, + }, + title: "Hello world", + snippet: "Hola Mundo", + draggable: true, + }); + + setMarkerId(id); + setCommandOutput(`Marker added: ${id}`) + + } catch (err: any) { + setCommandOutput(err.message); + } + } + + async function removeMarker() { + try { + if (markerId === "") { + throw new Error("marker id not set"); + } + + if (!map) { + throw new Error("map not created"); + } + + await map.removeMarker(markerId); + setCommandOutput(`Marker removed: ${markerId}`) + } catch (err: any) { + setCommandOutput(err.message); + } + } + + async function destroyMap() { + setCommandOutput(""); + try { + if (map) { + await map.destroy(); + setCommandOutput('Map destroyed'); + } + } catch (err: any) { + setCommandOutput(err.message); + } + } + + return ( + +
+ + Create Map + + + Set On Marker Click / Drag Listeners + + + Remove On Marker Click / Drag Listeners + + + Add 1 Marker + + + Remove Marker + + + Destroy Map + +
+
+ +
+ +
+ ) +} + +export default AddAndRemoveMarkers; \ No newline at end of file diff --git a/google-maps/e2e-tests/src/pages/Markers/MarkerCustomizations.tsx b/google-maps/e2e-tests/src/pages/Markers/MarkerCustomizations.tsx new file mode 100644 index 000000000..ac86bd778 --- /dev/null +++ b/google-maps/e2e-tests/src/pages/Markers/MarkerCustomizations.tsx @@ -0,0 +1,389 @@ +import { useState } from 'react'; +import { GoogleMap, Marker } from '@capacitor/google-maps'; +import { IonButton, IonTextarea } from '@ionic/react'; + +import BaseTestingPage from '../../components/BaseTestingPage'; + +const MarkerCustomizations: React.FC = () => { + const [map, setMap] = useState(null); + const [markerIds, setMarkerIds] = useState([]); + const [commandOutput, setCommandOutput] = useState(''); + + const apiKey = process.env.REACT_APP_GOOGLE_MAPS_API_KEY; + + const getRandom = (): number => { + return Math.floor(Math.random() * 256); + }; + + async function createMap() { + try { + const element = document.getElementById('map_marker_custom'); + if (element !== null) { + const newMap = await GoogleMap.create({ + element: element, + id: 'test-map', + apiKey: apiKey!, + config: { + center: { + lat: 43.547302, + lng: -96.728333, + }, + zoom: 9, + }, + }); + + setMap(newMap); + + setCommandOutput('Map created'); + } + } catch (err: any) { + setCommandOutput(err.message); + } + } + + const addMarkerColor = async () => { + try { + if (!map) { + throw new Error('map not created'); + } + + const id = await map.addMarker({ + coordinate: { + lat: 43.581386, + lng: -96.739025, + }, + tintColor: { + r: 41, + g: 71, + b: 157, + a: 1, + }, + }); + + map.setCamera({ + coordinate: { + lat: 43.547302, + lng: -96.728333, + }, + zoom: 9, + }); + setMarkerIds(markerIds.concat([id])); + setCommandOutput('1 color marker added'); + } catch (err: any) { + setCommandOutput(err.message); + } + }; + + const addMarkerImage = async () => { + try { + if (!map) { + throw new Error('map not created'); + } + + const id = await map.addMarker({ + coordinate: { + lat: 43.512098, + lng: -96.739352, + }, + iconUrl: 'assets/icon/pin.png', + iconSize: { + width: 30, + height: 30, + }, + iconOrigin: { x: 0, y: 0 }, + iconAnchor: { x: 15, y: 30 }, + }); + + map.setCamera({ + coordinate: { + lat: 43.547302, + lng: -96.728333, + }, + zoom: 9, + }); + + setMarkerIds(markerIds.concat([id])); + setCommandOutput('1 image marker added'); + } catch (err: any) { + setCommandOutput(err.message); + } + }; + + const addMarkerSVG = async () => { + try { + if (!map) { + throw new Error('map not created'); + } + + const id = await map.addMarker({ + coordinate: { + lat: 43.512098, + lng: -96.739352, + }, + iconUrl: 'assets/icon/marker.svg', + iconSize: { + width: 30, + height: 30, + }, + iconOrigin: { x: 0, y: 0 }, + iconAnchor: { x: 15, y: 30 }, + }); + + map.setCamera({ + coordinate: { + lat: 43.547302, + lng: -96.728333, + }, + zoom: 9, + }); + + setMarkerIds(markerIds.concat([id])); + setCommandOutput('1 image marker added'); + } catch (err: any) { + setCommandOutput(err.message); + } + }; + + const addMultipleImageMarkers = async () => { + try { + if (!map) { + throw new Error('map not created'); + } + const markers: Marker[] = [ + { + coordinate: { + lat: 47.6, + lng: -122.33, + }, + title: 'Title 1', + snippet: 'Snippet 1', + iconUrl: 'assets/icon/pin.png', + iconSize: { + width: 30, + height: 30, + }, + }, + { + coordinate: { + lat: 47.6, + lng: -122.46, + }, + title: 'Title 2', + snippet: 'Snippet 2', + iconUrl: 'assets/icon/pin.png', + iconSize: { + width: 30, + height: 30, + }, + }, + { + coordinate: { + lat: 47.3, + lng: -122.46, + }, + title: 'Title 3', + snippet: 'Snippet 3', + iconUrl: 'assets/icon/pin.png', + iconSize: { + width: 30, + height: 30, + }, + }, + { + coordinate: { + lat: 47.2, + lng: -122.23, + }, + title: 'Title 4', + snippet: 'Snippet 4', + iconUrl: 'assets/icon/pin.png', + iconSize: { + width: 30, + height: 30, + }, + }, + ]; + + const ids = await map.addMarkers(markers); + map.setCamera({ + animate: true, + coordinate: { + lat: 47.6, + lng: -122.33, + }, + zoom: 7, + }); + setMarkerIds(markerIds.concat(ids)); + setCommandOutput(`${ids.length} image markers added`); + } catch (err: any) { + setCommandOutput(err.message); + } + }; + + const addMultipleColorMarkers = async () => { + try { + if (!map) { + throw new Error('map not created'); + } + const markers: Marker[] = [ + { + coordinate: { + lat: 47.6, + lng: -122.33, + }, + title: 'Title 1', + snippet: 'Snippet 1', + tintColor: { + r: getRandom(), + g: getRandom(), + b: getRandom(), + a: 1, + }, + }, + { + coordinate: { + lat: 47.6, + lng: -122.46, + }, + title: 'Title 2', + snippet: 'Snippet 2', + tintColor: { + r: getRandom(), + g: getRandom(), + b: getRandom(), + a: 1, + }, + }, + { + coordinate: { + lat: 47.3, + lng: -122.46, + }, + title: 'Title 3', + snippet: 'Snippet 3', + tintColor: { + r: getRandom(), + g: getRandom(), + b: getRandom(), + a: 1, + }, + }, + { + coordinate: { + lat: 47.2, + lng: -122.23, + }, + title: 'Title 4', + snippet: 'Snippet 4', + tintColor: { + r: getRandom(), + g: getRandom(), + b: getRandom(), + a: 1, + }, + }, + ]; + + const ids = await map.addMarkers(markers); + map.setCamera({ + animate: true, + coordinate: { + lat: 47.6, + lng: -122.33, + }, + zoom: 7, + }); + setMarkerIds(markerIds.concat(ids)); + setCommandOutput(`${ids.length} color markers added`); + } catch (err: any) { + setCommandOutput(err.message); + } + }; + + const removeAllMarkers = async () => { + try { + if (!map) { + throw new Error('map not created'); + } + + let count = markerIds.length; + + await map.removeMarkers(markerIds); + setMarkerIds([]); + + setCommandOutput(`${count} markers removed`); + } catch (err: any) { + setCommandOutput(err.message); + } + }; + + async function destroyMap() { + setCommandOutput(''); + try { + if (map) { + await map.destroy(); + setCommandOutput('Map destroyed'); + } + } catch (err: any) { + setCommandOutput(err.message); + } + } + + return ( + +
+ + Create Map + + + Add Marker with Image + + + Add Marker with SVG + + + Add Marker with Color + + + Add Multiple Image Markers + + + Add Multiple Color Markers + + + Remove All Markers + + + Destroy Map + +
+
+ +
+ +
+ ); +}; + +export default MarkerCustomizations; diff --git a/google-maps/e2e-tests/src/pages/Markers/MultipleMarkers.tsx b/google-maps/e2e-tests/src/pages/Markers/MultipleMarkers.tsx new file mode 100644 index 000000000..0928b8ffd --- /dev/null +++ b/google-maps/e2e-tests/src/pages/Markers/MultipleMarkers.tsx @@ -0,0 +1,266 @@ +import { useState } from 'react'; +import { GoogleMap, Marker } from '@capacitor/google-maps'; +import { IonButton, IonTextarea } from '@ionic/react'; +import BaseTestingPage from '../../components/BaseTestingPage'; + + +const MultipleMarkers: React.FC = () => { + const [map, setMap] = useState(null); + const [markerIds, setMarkerIds] = useState([]); + const [commandOutput, setCommandOutput] = useState(''); + const [commandOutput2, setCommandOutput2] = useState(''); + const apiKey = process.env.REACT_APP_GOOGLE_MAPS_API_KEY; + + const onBoundsChanged = (data: any) => { + setCommandOutput(`BOUNDS CHANGED: ${JSON.stringify(data)}`); + } + + const onCameraIdle = (data: any) => { + setCommandOutput(`CAMERA IDLE: ${JSON.stringify(data)}`); + } + + const onCameraMoveStarted = (data: any) => { + setCommandOutput(`CAMERA MOVE STARTED: ${JSON.stringify(data)}`); + } + + const onClusterClick = (data: any) => { + setCommandOutput2(`CLUSTER CLICKED: ${JSON.stringify(data)}`); + } + + const onClusterInfoWindowClick = (data: any) => { + setCommandOutput2(`CLUSTER INFO WINDOW CLICKED: ${JSON.stringify(data)}`); + } + + const onInfoWindowClick = (data: any) => { + setCommandOutput2(`INFO WINDOW CLICKED: ${JSON.stringify(data)}`); + } + + const onMapClick = (data: any) => { + setCommandOutput(`MAP CLICKED: ${JSON.stringify(data)}`); + setCommandOutput2(""); + } + + const onMarkerClick = (data: any) => { + setCommandOutput2(`MARKER CLICKED: ${JSON.stringify(data)}`); + } + + const onMyLocationButtonClick = (data: any) => { + setCommandOutput2(`MY LOCATION BUTTON CLICKED: ${JSON.stringify(data)}`); + } + + const onMyLocationClick = (data: any) => { + setCommandOutput2(`MY LOCATION CLICKED: ${JSON.stringify(data)}`); + } + + async function createMap() { + try { + const element = document.getElementById('multipleMarkers_map1'); + if (element !== null) { + const newMap = await GoogleMap.create({ + element: element, + id: "test-map", + apiKey: apiKey!, + config: { + center: { + lat: 47.60, + lng: -122.33, + }, + zoom: 5, + } + }); + + setMap(newMap); + + setCommandOutput("Map created"); + setCommandOutput2(""); + } + } catch (err: any) { + setCommandOutput(err.message); + setCommandOutput2(""); + } + } + + async function setEventListeners() { + map?.setOnBoundsChangedListener(onBoundsChanged); + map?.setOnCameraIdleListener(onCameraIdle); + map?.setOnCameraMoveStartedListener(onCameraMoveStarted); + map?.setOnClusterClickListener(onClusterClick); + map?.setOnClusterInfoWindowClickListener(onClusterInfoWindowClick); + map?.setOnInfoWindowClickListener(onInfoWindowClick); + map?.setOnMapClickListener(onMapClick); + map?.setOnMarkerClickListener(onMarkerClick); + map?.setOnMyLocationButtonClickListener(onMyLocationButtonClick); + map?.setOnMyLocationClickListener(onMyLocationClick); + setCommandOutput('Set Event Listeners!'); + setCommandOutput2(""); + } + + async function removeEventListeners() { + map?.removeAllMapListeners(); + setCommandOutput('Removed Event Listeners!'); + setCommandOutput2(""); + } + + async function enableClustering() { + try { + if (map) { + await map.enableClustering(); + setCommandOutput("marker clustering enabled") + setCommandOutput2(""); + } + } catch (err: any) { + setCommandOutput(err.message); + setCommandOutput2(""); + } + } + + async function addMultipleMarkers() { + try { + if (map) { + const markers: Marker[] = [{ + coordinate: { + lat: 47.60, + lng: -122.33, + }, + title: "Title 1", + snippet: "Snippet 1", + }, { + coordinate: { + lat: 47.60, + lng: -122.46, + }, + title: "Title 2", + snippet: "Snippet 2", + }, { + coordinate: { + lat: 47.30, + lng: -122.46, + }, + title: "Title 3", + snippet: "Snippet 3", + }, { + coordinate: { + lat: 47.20, + lng: -122.23, + }, + title: "Title 4", + snippet: "Snippet 4", + }]; + + const ids = await map.addMarkers(markers); + console.log("@@IDS: ", ids); + setMarkerIds(ids) + setCommandOutput(`${ids.length} markers added`) + setCommandOutput2(""); + } + } catch (err: any) { + setCommandOutput(err.message); + setCommandOutput2(""); + } + } + + async function removeAllMarkers() { + try { + if (map) { + await map.removeMarkers(markerIds) + setCommandOutput(`${markerIds.length} markers removed`) + setCommandOutput2(""); + setMarkerIds([]) + } + } catch (err: any) { + setCommandOutput(err.message); + setCommandOutput2(""); + } + } + + async function disableClustering() { + try { + if (map) { + await map.disableClustering(); + setCommandOutput("marker clustering disabled") + setCommandOutput2(""); + } + } catch (err: any) { + setCommandOutput(err.message); + setCommandOutput2(""); + } + } + + async function destroyMap() { + setCommandOutput(""); + try { + if (map) { + await map.destroy(); + setCommandOutput('Map destroyed'); + setCommandOutput2(""); + } + } catch (err: any) { + setCommandOutput(err.message); + setCommandOutput2(""); + } + } + + async function showCurrentLocation() { + await map?.setCamera({ + zoom: 1, + animate: true, + animationDuration: 50, + }) + await map?.enableCurrentLocation(true); + } + + async function showCurrentBounds() { + const bounds = await map?.getMapBounds(); + setCommandOutput(JSON.stringify(bounds)); + } + + return ( + +
+ + Create Map + + + Set Event Listeners + + + Remove Event Listeners + + + Show Current Location + + + Show Current Bounds + + + Add Multiple Markers + + + Enable Clustering + + + Disable Clustering + + + Remove Markers + + + Destroy Map + +
+
+ + +
+ +
+ ) +} + +export default MultipleMarkers; \ No newline at end of file diff --git a/google-maps/e2e-tests/src/pages/Scrolling/SimpleScrolling.tsx b/google-maps/e2e-tests/src/pages/Scrolling/SimpleScrolling.tsx new file mode 100644 index 000000000..010ef0c98 --- /dev/null +++ b/google-maps/e2e-tests/src/pages/Scrolling/SimpleScrolling.tsx @@ -0,0 +1,191 @@ +import { useState } from 'react'; +import { GoogleMap } from '@capacitor/google-maps'; +import { IonButton, IonContent, IonTextarea } from '@ionic/react'; +import BaseTestingPage from '../../components/BaseTestingPage'; + +const SimpleScrollingPage: React.FC = () => { + const [map, setMap] = useState(null); + const [commandOutput, setCommandOutput] = useState(''); + const apiKey = process.env.REACT_APP_GOOGLE_MAPS_API_KEY; + + async function createMaps() { + const mapRef = document.getElementById('map')!; + setCommandOutput(''); + setMap(null); + try { + const newMap1 = await GoogleMap.create({ + element: mapRef, + id: 'test-map', + apiKey: apiKey!, + config: { + center: { + lat: 33.6, + lng: -117.9, + }, + zoom: 8, + } + }); + + setMap(newMap1); + setCommandOutput('Maps created'); + console.log('Maps created'); + } catch (err: any) { + console.log(err.message); + } + } + + async function destroyMaps() { + setCommandOutput(''); + try { + if (map) { + await map.destroy(); + console.log('map destroyed'); + } + } catch (err: any) { + console.log(err.message); + } + } + + return ( + +
+ + Create Maps + + + Destroy Maps + +
+ +
+

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla + vulputate eget ipsum vel venenatis. Ut dui enim, elementum vel + convallis a, malesuada a nibh. Etiam sit amet purus orci. Sed sit amet + sapien non libero mollis tempus eget non lacus. Proin vel nisi sit + amet neque luctus hendrerit ac at nisi. Maecenas malesuada neque dui, + a ornare neque efficitur id. Duis a quam ut lacus euismod ultrices sed + non libero. +

+

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla + vulputate eget ipsum vel venenatis. Ut dui enim, elementum vel + convallis a, malesuada a nibh. Etiam sit amet purus orci. Sed sit amet + sapien non libero mollis tempus eget non lacus. Proin vel nisi sit + amet neque luctus hendrerit ac at nisi. Maecenas malesuada neque dui, + a ornare neque efficitur id. Duis a quam ut lacus euismod ultrices sed + non libero. +

+

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla + vulputate eget ipsum vel venenatis. Ut dui enim, elementum vel + convallis a, malesuada a nibh. Etiam sit amet purus orci. Sed sit amet + sapien non libero mollis tempus eget non lacus. Proin vel nisi sit + amet neque luctus hendrerit ac at nisi. Maecenas malesuada neque dui, + a ornare neque efficitur id. Duis a quam ut lacus euismod ultrices sed + non libero. +

+

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla + vulputate eget ipsum vel venenatis. Ut dui enim, elementum vel + convallis a, malesuada a nibh. Etiam sit amet purus orci. Sed sit amet + sapien non libero mollis tempus eget non lacus. Proin vel nisi sit + amet neque luctus hendrerit ac at nisi. Maecenas malesuada neque dui, + a ornare neque efficitur id. Duis a quam ut lacus euismod ultrices sed + non libero. +

+

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla + vulputate eget ipsum vel venenatis. Ut dui enim, elementum vel + convallis a, malesuada a nibh. Etiam sit amet purus orci. Sed sit amet + sapien non libero mollis tempus eget non lacus. Proin vel nisi sit + amet neque luctus hendrerit ac at nisi. Maecenas malesuada neque dui, + a ornare neque efficitur id. Duis a quam ut lacus euismod ultrices sed + non libero. +

+ + + +
+

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla + vulputate eget ipsum vel venenatis. Ut dui enim, elementum vel + convallis a, malesuada a nibh. Etiam sit amet purus orci. Sed sit amet + sapien non libero mollis tempus eget non lacus. Proin vel nisi sit + amet neque luctus hendrerit ac at nisi. Maecenas malesuada neque dui, + a ornare neque efficitur id. Duis a quam ut lacus euismod ultrices sed + non libero. +

+

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla + vulputate eget ipsum vel venenatis. Ut dui enim, elementum vel + convallis a, malesuada a nibh. Etiam sit amet purus orci. Sed sit amet + sapien non libero mollis tempus eget non lacus. Proin vel nisi sit + amet neque luctus hendrerit ac at nisi. Maecenas malesuada neque dui, + a ornare neque efficitur id. Duis a quam ut lacus euismod ultrices sed + non libero. +

+

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla + vulputate eget ipsum vel venenatis. Ut dui enim, elementum vel + convallis a, malesuada a nibh. Etiam sit amet purus orci. Sed sit amet + sapien non libero mollis tempus eget non lacus. Proin vel nisi sit + amet neque luctus hendrerit ac at nisi. Maecenas malesuada neque dui, + a ornare neque efficitur id. Duis a quam ut lacus euismod ultrices sed + non libero. +

+

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla + vulputate eget ipsum vel venenatis. Ut dui enim, elementum vel + convallis a, malesuada a nibh. Etiam sit amet purus orci. Sed sit amet + sapien non libero mollis tempus eget non lacus. Proin vel nisi sit + amet neque luctus hendrerit ac at nisi. Maecenas malesuada neque dui, + a ornare neque efficitur id. Duis a quam ut lacus euismod ultrices sed + non libero. +

+

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla + vulputate eget ipsum vel venenatis. Ut dui enim, elementum vel + convallis a, malesuada a nibh. Etiam sit amet purus orci. Sed sit amet + sapien non libero mollis tempus eget non lacus. Proin vel nisi sit + amet neque luctus hendrerit ac at nisi. Maecenas malesuada neque dui, + a ornare neque efficitur id. Duis a quam ut lacus euismod ultrices sed + non libero. +

+

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla + vulputate eget ipsum vel venenatis. Ut dui enim, elementum vel + convallis a, malesuada a nibh. Etiam sit amet purus orci. Sed sit amet + sapien non libero mollis tempus eget non lacus. Proin vel nisi sit + amet neque luctus hendrerit ac at nisi. Maecenas malesuada neque dui, + a ornare neque efficitur id. Duis a quam ut lacus euismod ultrices sed + non libero. +

+
+
+
+ ); +}; + +export default SimpleScrollingPage; diff --git a/google-maps/e2e-tests/src/react-app-env.d.ts b/google-maps/e2e-tests/src/react-app-env.d.ts new file mode 100644 index 000000000..6431bc5fc --- /dev/null +++ b/google-maps/e2e-tests/src/react-app-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/google-maps/e2e-tests/src/reportWebVitals.ts b/google-maps/e2e-tests/src/reportWebVitals.ts new file mode 100644 index 000000000..49a2a16e0 --- /dev/null +++ b/google-maps/e2e-tests/src/reportWebVitals.ts @@ -0,0 +1,15 @@ +import { ReportHandler } from 'web-vitals'; + +const reportWebVitals = (onPerfEntry?: ReportHandler) => { + if (onPerfEntry && onPerfEntry instanceof Function) { + import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { + getCLS(onPerfEntry); + getFID(onPerfEntry); + getFCP(onPerfEntry); + getLCP(onPerfEntry); + getTTFB(onPerfEntry); + }); + } +}; + +export default reportWebVitals; diff --git a/google-maps/e2e-tests/src/routes.ts b/google-maps/e2e-tests/src/routes.ts new file mode 100644 index 000000000..ff6d5b197 --- /dev/null +++ b/google-maps/e2e-tests/src/routes.ts @@ -0,0 +1,88 @@ +import { triangleOutline, triangleSharp } from 'ionicons/icons'; +import React from 'react'; +import ConfigMapPage from './pages/Map/ConfigMap'; +import CreateAndDestroyMapPage from './pages/Map/CreateAndDestroyMap'; +import AddAndRemoveMarkers from './pages/Markers/AddAndRemoveMarkers'; +import MarkerCustomizations from './pages/Markers/MarkerCustomizations'; +import MultipleMarkers from './pages/Markers/MultipleMarkers'; +import SimpleScrollingPage from './pages/Scrolling/SimpleScrolling'; + +export type RouteDescription = { + title: string; + url: string; + iosIcon: string; + mdIcon: string; + component: React.FC; +}; + +export type RouteGroup = { + groupName: string; + pages: RouteDescription[]; +}; + +const routesList: RouteGroup[] = [ + { + groupName: 'Maps', + pages: [ + { + title: 'Create and Destroy Maps', + url: '/maps/create-and-destroy', + iosIcon: triangleOutline, + mdIcon: triangleSharp, + component: CreateAndDestroyMapPage, + }, + { + title: 'Config Maps', + url: '/maps/config', + iosIcon: triangleOutline, + mdIcon: triangleSharp, + component: ConfigMapPage, + },{ + title: 'Simple Scrolling', + url: '/maps/scrolling', + iosIcon: triangleOutline, + mdIcon: triangleSharp, + component: SimpleScrollingPage, + } + ], + }, + { + groupName: "Markers", + pages: [ + { + title: "Add and Remove Marker", + url: "/markers/add-and-remove", + iosIcon: triangleOutline, + mdIcon: triangleSharp, + component: AddAndRemoveMarkers + }, + { + title: "Multiple Markers", + url: "/markers/multiple-markers", + iosIcon: triangleOutline, + mdIcon: triangleSharp, + component: MultipleMarkers + }, + { + title: "Marker Customization", + url: "/markers/customization", + iosIcon: triangleOutline, + mdIcon: triangleSharp, + component: MarkerCustomizations, + } + ] + } +]; + +export function getRouterSetup(): RouteDescription[] { + let allPages: RouteDescription[] = []; + for (const routeGroup of routesList) { + allPages = [...allPages, ...routeGroup.pages]; + } + + return allPages; +} + +export function getMenuList(): RouteGroup[] { + return routesList; +} diff --git a/google-maps/e2e-tests/src/service-worker.ts b/google-maps/e2e-tests/src/service-worker.ts new file mode 100644 index 000000000..652a8a4af --- /dev/null +++ b/google-maps/e2e-tests/src/service-worker.ts @@ -0,0 +1,80 @@ +/// +/* eslint-disable no-restricted-globals */ + +// This service worker can be customized! +// See https://developers.google.com/web/tools/workbox/modules +// for the list of available Workbox modules, or add any other +// code you'd like. +// You can also remove this file if you'd prefer not to use a +// service worker, and the Workbox build step will be skipped. + +import { clientsClaim } from 'workbox-core'; +import { ExpirationPlugin } from 'workbox-expiration'; +import { precacheAndRoute, createHandlerBoundToURL } from 'workbox-precaching'; +import { registerRoute } from 'workbox-routing'; +import { StaleWhileRevalidate } from 'workbox-strategies'; + +declare const self: ServiceWorkerGlobalScope; + +clientsClaim(); + +// Precache all of the assets generated by your build process. +// Their URLs are injected into the manifest variable below. +// This variable must be present somewhere in your service worker file, +// even if you decide not to use precaching. See https://cra.link/PWA +precacheAndRoute(self.__WB_MANIFEST); + +// Set up App Shell-style routing, so that all navigation requests +// are fulfilled with your index.html shell. Learn more at +// https://developers.google.com/web/fundamentals/architecture/app-shell +const fileExtensionRegexp = new RegExp('/[^/?]+\\.[^/]+$'); +registerRoute( + // Return false to exempt requests from being fulfilled by index.html. + ({ request, url }: { request: Request; url: URL }) => { + // If this isn't a navigation, skip. + if (request.mode !== 'navigate') { + return false; + } + + // If this is a URL that starts with /_, skip. + if (url.pathname.startsWith('/_')) { + return false; + } + + // If this looks like a URL for a resource, because it contains + // a file extension, skip. + if (url.pathname.match(fileExtensionRegexp)) { + return false; + } + + // Return true to signal that we want to use the handler. + return true; + }, + createHandlerBoundToURL(process.env.PUBLIC_URL + '/index.html') +); + +// An example runtime caching route for requests that aren't handled by the +// precache, in this case same-origin .png requests like those from in public/ +registerRoute( + // Add in any other file extensions or routing criteria as needed. + ({ url }) => url.origin === self.location.origin && url.pathname.endsWith('.png'), + // Customize this strategy as needed, e.g., by changing to CacheFirst. + new StaleWhileRevalidate({ + cacheName: 'images', + plugins: [ + // Ensure that once this runtime cache reaches a maximum size the + // least-recently used images are removed. + new ExpirationPlugin({ maxEntries: 50 }), + ], + }) +); + +// This allows the web app to trigger skipWaiting via +// registration.waiting.postMessage({type: 'SKIP_WAITING'}) +self.addEventListener('message', (event) => { + if (event.data && event.data.type === 'SKIP_WAITING') { + self.skipWaiting(); + } +}); + +// Any other custom service worker logic can go here. diff --git a/google-maps/e2e-tests/src/serviceWorkerRegistration.ts b/google-maps/e2e-tests/src/serviceWorkerRegistration.ts new file mode 100644 index 000000000..efbf2ac42 --- /dev/null +++ b/google-maps/e2e-tests/src/serviceWorkerRegistration.ts @@ -0,0 +1,142 @@ +// This optional code is used to register a service worker. +// register() is not called by default. + +// This lets the app load faster on subsequent visits in production, and gives +// it offline capabilities. However, it also means that developers (and users) +// will only see deployed updates on subsequent visits to a page, after all the +// existing tabs open on the page have been closed, since previously cached +// resources are updated in the background. + +// To learn more about the benefits of this model and instructions on how to +// opt-in, read https://cra.link/PWA + +const isLocalhost = Boolean( + window.location.hostname === 'localhost' || + // [::1] is the IPv6 localhost address. + window.location.hostname === '[::1]' || + // 127.0.0.0/8 are considered localhost for IPv4. + window.location.hostname.match(/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/) +); + +type Config = { + onSuccess?: (registration: ServiceWorkerRegistration) => void; + onUpdate?: (registration: ServiceWorkerRegistration) => void; +}; + +export function register(config?: Config) { + if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { + // The URL constructor is available in all browsers that support SW. + const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href); + if (publicUrl.origin !== window.location.origin) { + // Our service worker won't work if PUBLIC_URL is on a different origin + // from what our page is served on. This might happen if a CDN is used to + // serve assets; see https://github.com/facebook/create-react-app/issues/2374 + return; + } + + window.addEventListener('load', () => { + const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; + + if (isLocalhost) { + // This is running on localhost. Let's check if a service worker still exists or not. + checkValidServiceWorker(swUrl, config); + + // Add some additional logging to localhost, pointing developers to the + // service worker/PWA documentation. + navigator.serviceWorker.ready.then(() => { + console.log( + 'This web app is being served cache-first by a service ' + + 'worker. To learn more, visit https://cra.link/PWA' + ); + }); + } else { + // Is not localhost. Just register service worker + registerValidSW(swUrl, config); + } + }); + } +} + +function registerValidSW(swUrl: string, config?: Config) { + navigator.serviceWorker + .register(swUrl) + .then((registration) => { + registration.onupdatefound = () => { + const installingWorker = registration.installing; + if (installingWorker == null) { + return; + } + installingWorker.onstatechange = () => { + if (installingWorker.state === 'installed') { + if (navigator.serviceWorker.controller) { + // At this point, the updated precached content has been fetched, + // but the previous service worker will still serve the older + // content until all client tabs are closed. + console.log( + 'New content is available and will be used when all ' + + 'tabs for this page are closed. See https://cra.link/PWA.' + ); + + // Execute callback + if (config && config.onUpdate) { + config.onUpdate(registration); + } + } else { + // At this point, everything has been precached. + // It's the perfect time to display a + // "Content is cached for offline use." message. + console.log('Content is cached for offline use.'); + + // Execute callback + if (config && config.onSuccess) { + config.onSuccess(registration); + } + } + } + }; + }; + }) + .catch((error) => { + console.error('Error during service worker registration:', error); + }); +} + +function checkValidServiceWorker(swUrl: string, config?: Config) { + // Check if the service worker can be found. If it can't reload the page. + fetch(swUrl, { + headers: { 'Service-Worker': 'script' }, + }) + .then((response) => { + // Ensure service worker exists, and that we really are getting a JS file. + const contentType = response.headers.get('content-type'); + if ( + response.status === 404 || + (contentType != null && contentType.indexOf('javascript') === -1) + ) { + // No service worker found. Probably a different app. Reload the page. + navigator.serviceWorker.ready.then((registration) => { + registration.unregister().then(() => { + window.location.reload(); + }); + }); + } else { + // Service worker found. Proceed as normal. + registerValidSW(swUrl, config); + } + }) + .catch(() => { + console.log('No internet connection found. App is running in offline mode.'); + }); +} + +export function unregister() { + if ('serviceWorker' in navigator) { + navigator.serviceWorker.ready + .then((registration) => { + registration.unregister(); + }) + .catch((error) => { + console.error(error.message); + }); + } +} diff --git a/google-maps/e2e-tests/src/setupTests.ts b/google-maps/e2e-tests/src/setupTests.ts new file mode 100644 index 000000000..87988d6bd --- /dev/null +++ b/google-maps/e2e-tests/src/setupTests.ts @@ -0,0 +1,14 @@ +// jest-dom adds custom jest matchers for asserting on DOM nodes. +// allows you to do things like: +// expect(element).toHaveTextContent(/react/i) +// learn more: https://github.com/testing-library/jest-dom +import '@testing-library/jest-dom/extend-expect'; + +// Mock matchmedia +window.matchMedia = window.matchMedia || function() { + return { + matches: false, + addListener: function() {}, + removeListener: function() {} + }; +}; diff --git a/google-maps/e2e-tests/src/theme/variables.css b/google-maps/e2e-tests/src/theme/variables.css new file mode 100644 index 000000000..9b1948ec9 --- /dev/null +++ b/google-maps/e2e-tests/src/theme/variables.css @@ -0,0 +1,244 @@ +/* Ionic Variables and Theming. For more info, please see: +http://ionicframework.com/docs/theming/ */ + +ion-content { + --background: transparent; +} + +body { + background: transparent; +} + +/** Ionic CSS Variables **/ +:root { + /** primary **/ + --ion-color-primary: #3880ff; + --ion-color-primary-rgb: 56, 128, 255; + --ion-color-primary-contrast: #ffffff; + --ion-color-primary-contrast-rgb: 255, 255, 255; + --ion-color-primary-shade: #3171e0; + --ion-color-primary-tint: #4c8dff; + + /** secondary **/ + --ion-color-secondary: #3dc2ff; + --ion-color-secondary-rgb: 61, 194, 255; + --ion-color-secondary-contrast: #ffffff; + --ion-color-secondary-contrast-rgb: 255, 255, 255; + --ion-color-secondary-shade: #36abe0; + --ion-color-secondary-tint: #50c8ff; + + /** tertiary **/ + --ion-color-tertiary: #5260ff; + --ion-color-tertiary-rgb: 82, 96, 255; + --ion-color-tertiary-contrast: #ffffff; + --ion-color-tertiary-contrast-rgb: 255, 255, 255; + --ion-color-tertiary-shade: #4854e0; + --ion-color-tertiary-tint: #6370ff; + + /** success **/ + --ion-color-success: #2dd36f; + --ion-color-success-rgb: 45, 211, 111; + --ion-color-success-contrast: #ffffff; + --ion-color-success-contrast-rgb: 255, 255, 255; + --ion-color-success-shade: #28ba62; + --ion-color-success-tint: #42d77d; + + /** warning **/ + --ion-color-warning: #ffc409; + --ion-color-warning-rgb: 255, 196, 9; + --ion-color-warning-contrast: #000000; + --ion-color-warning-contrast-rgb: 0, 0, 0; + --ion-color-warning-shade: #e0ac08; + --ion-color-warning-tint: #ffca22; + + /** danger **/ + --ion-color-danger: #eb445a; + --ion-color-danger-rgb: 235, 68, 90; + --ion-color-danger-contrast: #ffffff; + --ion-color-danger-contrast-rgb: 255, 255, 255; + --ion-color-danger-shade: #cf3c4f; + --ion-color-danger-tint: #ed576b; + + /** dark **/ + --ion-color-dark: #222428; + --ion-color-dark-rgb: 34, 36, 40; + --ion-color-dark-contrast: #ffffff; + --ion-color-dark-contrast-rgb: 255, 255, 255; + --ion-color-dark-shade: #1e2023; + --ion-color-dark-tint: #383a3e; + + /** medium **/ + --ion-color-medium: #92949c; + --ion-color-medium-rgb: 146, 148, 156; + --ion-color-medium-contrast: #ffffff; + --ion-color-medium-contrast-rgb: 255, 255, 255; + --ion-color-medium-shade: #808289; + --ion-color-medium-tint: #9d9fa6; + + /** light **/ + --ion-color-light: #f4f5f8; + --ion-color-light-rgb: 244, 245, 248; + --ion-color-light-contrast: #000000; + --ion-color-light-contrast-rgb: 0, 0, 0; + --ion-color-light-shade: #d7d8da; + --ion-color-light-tint: #f5f6f9; +} + +@media (prefers-color-scheme: dark) { + /* + * Dark Colors + * ------------------------------------------- + */ + + body { + --ion-color-primary: #428cff; + --ion-color-primary-rgb: 66,140,255; + --ion-color-primary-contrast: #ffffff; + --ion-color-primary-contrast-rgb: 255,255,255; + --ion-color-primary-shade: #3a7be0; + --ion-color-primary-tint: #5598ff; + + --ion-color-secondary: #50c8ff; + --ion-color-secondary-rgb: 80,200,255; + --ion-color-secondary-contrast: #ffffff; + --ion-color-secondary-contrast-rgb: 255,255,255; + --ion-color-secondary-shade: #46b0e0; + --ion-color-secondary-tint: #62ceff; + + --ion-color-tertiary: #6a64ff; + --ion-color-tertiary-rgb: 106,100,255; + --ion-color-tertiary-contrast: #ffffff; + --ion-color-tertiary-contrast-rgb: 255,255,255; + --ion-color-tertiary-shade: #5d58e0; + --ion-color-tertiary-tint: #7974ff; + + --ion-color-success: #2fdf75; + --ion-color-success-rgb: 47,223,117; + --ion-color-success-contrast: #000000; + --ion-color-success-contrast-rgb: 0,0,0; + --ion-color-success-shade: #29c467; + --ion-color-success-tint: #44e283; + + --ion-color-warning: #ffd534; + --ion-color-warning-rgb: 255,213,52; + --ion-color-warning-contrast: #000000; + --ion-color-warning-contrast-rgb: 0,0,0; + --ion-color-warning-shade: #e0bb2e; + --ion-color-warning-tint: #ffd948; + + --ion-color-danger: #ff4961; + --ion-color-danger-rgb: 255,73,97; + --ion-color-danger-contrast: #ffffff; + --ion-color-danger-contrast-rgb: 255,255,255; + --ion-color-danger-shade: #e04055; + --ion-color-danger-tint: #ff5b71; + + --ion-color-dark: #f4f5f8; + --ion-color-dark-rgb: 244,245,248; + --ion-color-dark-contrast: #000000; + --ion-color-dark-contrast-rgb: 0,0,0; + --ion-color-dark-shade: #d7d8da; + --ion-color-dark-tint: #f5f6f9; + + --ion-color-medium: #989aa2; + --ion-color-medium-rgb: 152,154,162; + --ion-color-medium-contrast: #000000; + --ion-color-medium-contrast-rgb: 0,0,0; + --ion-color-medium-shade: #86888f; + --ion-color-medium-tint: #a2a4ab; + + --ion-color-light: #222428; + --ion-color-light-rgb: 34,36,40; + --ion-color-light-contrast: #ffffff; + --ion-color-light-contrast-rgb: 255,255,255; + --ion-color-light-shade: #1e2023; + --ion-color-light-tint: #383a3e; + } + + /* + * iOS Dark Theme + * ------------------------------------------- + */ + + .ios body { + --ion-background-color: #000000; + --ion-background-color-rgb: 0,0,0; + + --ion-text-color: #ffffff; + --ion-text-color-rgb: 255,255,255; + + --ion-color-step-50: #0d0d0d; + --ion-color-step-100: #1a1a1a; + --ion-color-step-150: #262626; + --ion-color-step-200: #333333; + --ion-color-step-250: #404040; + --ion-color-step-300: #4d4d4d; + --ion-color-step-350: #595959; + --ion-color-step-400: #666666; + --ion-color-step-450: #737373; + --ion-color-step-500: #808080; + --ion-color-step-550: #8c8c8c; + --ion-color-step-600: #999999; + --ion-color-step-650: #a6a6a6; + --ion-color-step-700: #b3b3b3; + --ion-color-step-750: #bfbfbf; + --ion-color-step-800: #cccccc; + --ion-color-step-850: #d9d9d9; + --ion-color-step-900: #e6e6e6; + --ion-color-step-950: #f2f2f2; + + --ion-item-background: #000000; + + --ion-card-background: #1c1c1d; + } + + .ios ion-modal { + --ion-background-color: var(--ion-color-step-100); + --ion-toolbar-background: var(--ion-color-step-150); + --ion-toolbar-border-color: var(--ion-color-step-250); + } + + + /* + * Material Design Dark Theme + * ------------------------------------------- + */ + + .md body { + --ion-background-color: #121212; + --ion-background-color-rgb: 18,18,18; + + --ion-text-color: #ffffff; + --ion-text-color-rgb: 255,255,255; + + --ion-border-color: #222222; + + --ion-color-step-50: #1e1e1e; + --ion-color-step-100: #2a2a2a; + --ion-color-step-150: #363636; + --ion-color-step-200: #414141; + --ion-color-step-250: #4d4d4d; + --ion-color-step-300: #595959; + --ion-color-step-350: #656565; + --ion-color-step-400: #717171; + --ion-color-step-450: #7d7d7d; + --ion-color-step-500: #898989; + --ion-color-step-550: #949494; + --ion-color-step-600: #a0a0a0; + --ion-color-step-650: #acacac; + --ion-color-step-700: #b8b8b8; + --ion-color-step-750: #c4c4c4; + --ion-color-step-800: #d0d0d0; + --ion-color-step-850: #dbdbdb; + --ion-color-step-900: #e7e7e7; + --ion-color-step-950: #f3f3f3; + + --ion-item-background: #1e1e1e; + + --ion-toolbar-background: #1f1f1f; + + --ion-tab-bar-background: #1f1f1f; + + --ion-card-background: #1e1e1e; + } +} diff --git a/google-maps/e2e-tests/tests/pageobjects/basic-echo/basic-echo.page.ts b/google-maps/e2e-tests/tests/pageobjects/basic-echo/basic-echo.page.ts new file mode 100644 index 000000000..a41920e4e --- /dev/null +++ b/google-maps/e2e-tests/tests/pageobjects/basic-echo/basic-echo.page.ts @@ -0,0 +1,14 @@ +import { IonicButton, IonicInput } from '@ionic/e2e-components-ionic'; + +import Page from '../page'; + +class BasicEchoPage extends Page { + get runEchoButton() { + return new IonicButton('#runEchoButton'); + } + get commandOutputTextarea() { + return new IonicInput('#commandOutput'); + } +} + +export default new BasicEchoPage(); diff --git a/google-maps/e2e-tests/tests/pageobjects/map/create-and-destroy.page.ts b/google-maps/e2e-tests/tests/pageobjects/map/create-and-destroy.page.ts new file mode 100644 index 000000000..e207d9e93 --- /dev/null +++ b/google-maps/e2e-tests/tests/pageobjects/map/create-and-destroy.page.ts @@ -0,0 +1,17 @@ +import { IonicButton, IonicTextarea } from '@ionic/e2e-components-ionic'; + +import Page from '../page'; + +class CreateAndDestroyMapPage extends Page { + get createMapButton() { + return new IonicButton("#createMapButton"); + } + get destroyMapButton() { + return new IonicButton("#destroyMapButton"); + } + get commandOutputTextarea() { + return new IonicTextarea('#commandOutput'); + } +} + +export default new CreateAndDestroyMapPage(); \ No newline at end of file diff --git a/google-maps/e2e-tests/tests/pageobjects/markers/add-and-remove.page.ts b/google-maps/e2e-tests/tests/pageobjects/markers/add-and-remove.page.ts new file mode 100644 index 000000000..7f6c47d33 --- /dev/null +++ b/google-maps/e2e-tests/tests/pageobjects/markers/add-and-remove.page.ts @@ -0,0 +1,21 @@ +import { IonicButton, IonicTextarea } from '@ionic/e2e-components-ionic'; + +import Page from "../page"; + +class AddAndRemoveMarkers extends Page { + get createMapButton() { + return new IonicButton("#createMapButton") + } + get addMarkerButton() { + return new IonicButton("#addMarkerButton") + } + get removeMarkerButton() { + return new IonicButton("#removeMarkerButton") + } + get commandOutputTextarea() { + return new IonicTextarea('#commandOutput'); + } +} + + +export default new AddAndRemoveMarkers(); \ No newline at end of file diff --git a/google-maps/e2e-tests/tests/pageobjects/markers/marker-customization.page.ts b/google-maps/e2e-tests/tests/pageobjects/markers/marker-customization.page.ts new file mode 100644 index 000000000..96925a375 --- /dev/null +++ b/google-maps/e2e-tests/tests/pageobjects/markers/marker-customization.page.ts @@ -0,0 +1,39 @@ +import { IonicButton, IonicTextarea } from '@ionic/e2e-components-ionic'; + +import Page from '../page'; + +class MarkerCustomizations extends Page { + get createMapButton() { + return new IonicButton('#createMapButton'); + } + + get addMarkerImageButton() { + return new IonicButton('#addMarkerImageButton'); + } + + get addMarkerColorButton() { + return new IonicButton('#addMarkerColorButton'); + } + + get addMultipleImageMarkersButton() { + return new IonicButton('#addMultipleImageMarkersButton'); + } + + get addMultipleColorMarkersButton() { + return new IonicButton('#addMultipleColorMarkersButton'); + } + + get removeAllMarkersButton() { + return new IonicButton('#removeAllMarkersButton'); + } + + get destroyMapButton() { + return new IonicButton('#destroyMapButton'); + } + + get commandOutputTextarea() { + return new IonicTextarea('#commandOutput'); +} +} + +export default new MarkerCustomizations(); diff --git a/google-maps/e2e-tests/tests/pageobjects/markers/multiple-markers.page.ts b/google-maps/e2e-tests/tests/pageobjects/markers/multiple-markers.page.ts new file mode 100644 index 000000000..79f237cde --- /dev/null +++ b/google-maps/e2e-tests/tests/pageobjects/markers/multiple-markers.page.ts @@ -0,0 +1,26 @@ +import { IonicButton, IonicTextarea } from '@ionic/e2e-components-ionic'; + +import Page from "../page"; + +class MultipleMarkers extends Page { + get createMapButton() { + return new IonicButton("#createMapButton") + } + get addMarkersButton() { + return new IonicButton("#addMarkersButton") + } + get enableClusteringButton() { + return new IonicButton("#enableClusteringButton") + } + get disableClusteringButton() { + return new IonicButton("#disableClusteringButton") + } + get removeMarkersButton() { + return new IonicButton("#removeMarkersButton") + } + get commandOutputTextarea() { + return new IonicTextarea('#commandOutput'); + } +} + +export default new MultipleMarkers(); \ No newline at end of file diff --git a/google-maps/e2e-tests/tests/pageobjects/page.ts b/google-maps/e2e-tests/tests/pageobjects/page.ts new file mode 100644 index 000000000..137bf5b54 --- /dev/null +++ b/google-maps/e2e-tests/tests/pageobjects/page.ts @@ -0,0 +1,23 @@ +export default class Page { + public async hideToolBars() { + await driver.execute(() => { + for (let i = 0; i < document.getElementsByTagName('ion-toolbar').length; i++) { + const toolbar: HTMLElement | null = document.getElementsByTagName('ion-toolbar').item(i) as HTMLElement; + if (toolbar !== null) { + toolbar.style.display = 'none'; + } + } + }); + } + + public async showToolBars() { + await driver.execute(() => { + for (let i = 0; i < document.getElementsByTagName('ion-toolbar').length; i++) { + const toolbar: HTMLElement | null = document.getElementsByTagName('ion-toolbar').item(i) as HTMLElement; + if (toolbar !== null) { + toolbar.style.display = ''; + } + } + }); + } +} diff --git a/google-maps/e2e-tests/tests/specs/basic-echo/basic-echo.spec.ts b/google-maps/e2e-tests/tests/specs/basic-echo/basic-echo.spec.ts new file mode 100644 index 000000000..e810261f0 --- /dev/null +++ b/google-maps/e2e-tests/tests/specs/basic-echo/basic-echo.spec.ts @@ -0,0 +1,33 @@ +import * as IonicE2E from '@ionic/e2e'; +import { waitForLoad, pause, setDevice, switchToWeb, url } from '@ionic/e2e'; + +import SetAndGetValuePage from '../../pageobjects/basic-echo/basic-echo.page'; + +describe.skip('Google Maps - Basic Echo', function () { + before(async function () { + await waitForLoad(); + await switchToWeb(); + await url('/basic-echo/run-basic-echo'); + await pause(500); + }); + + beforeEach(async function () { + await setDevice(IonicE2E.Device.Mobile); + await switchToWeb(); + await SetAndGetValuePage.hideToolBars(); + }); + + after(async function () { + await switchToWeb(); + await SetAndGetValuePage.showToolBars(); + await pause(500); + }); + + it('should run a basic echo from plugin.', async () => { + const runEchoButton = await SetAndGetValuePage.runEchoButton; + const commandOutput = await $((await SetAndGetValuePage.commandOutputTextarea).selector).$('textarea'); + + await runEchoButton.tap(); + await expect(commandOutput).toHaveValue('WOW!'); + }); +}); diff --git a/google-maps/e2e-tests/tests/specs/map/create-and-destroy.spec.ts b/google-maps/e2e-tests/tests/specs/map/create-and-destroy.spec.ts new file mode 100644 index 000000000..13aaf26bc --- /dev/null +++ b/google-maps/e2e-tests/tests/specs/map/create-and-destroy.spec.ts @@ -0,0 +1,55 @@ +import * as IonicE2E from '@ionic/e2e'; +import { waitForLoad, pause, setDevice, switchToWeb, url } from '@ionic/e2e'; + +import CreateAndDestroyMapPage from '../../pageobjects/map/create-and-destroy.page'; + + +describe('Google Maps - Create and Destroy Map', function () { + before(async function () { + await waitForLoad(); + await switchToWeb(); + await url('/maps/create-and-destroy'); + await pause(500); + }); + + beforeEach(async function () { + await setDevice(IonicE2E.Device.Mobile); + await switchToWeb(); + await CreateAndDestroyMapPage.hideToolBars(); + }); + + after(async function () { + await switchToWeb(); + await CreateAndDestroyMapPage.showToolBars(); + await pause(500); + }); + + it('should create and destroy a map', async function() { + const createMapButton = await CreateAndDestroyMapPage.createMapButton; + const destroyMapButton = await CreateAndDestroyMapPage.destroyMapButton; + const getCommandOutputText = async function() { + return (await CreateAndDestroyMapPage.commandOutputTextarea).getValue(); + } + + await createMapButton.tap(); + await pause(500); + await expect(await getCommandOutputText()).toBe('Maps created'); + + await destroyMapButton.tap(); + await pause(500); + await expect(await getCommandOutputText()).toBe('Maps destroyed'); + }); + + it('should throw when attempting to destroy a non-existent map', async function() { + const destroyMapButton = await CreateAndDestroyMapPage.destroyMapButton; + const getCommandOutputText = async function() { + return (await CreateAndDestroyMapPage.commandOutputTextarea).getValue(); + } + + await destroyMapButton.tap(); + await pause(100); + await expect(await getCommandOutputText()).toBe('Map not found for provided id.'); + }); + + +}); diff --git a/google-maps/e2e-tests/tests/specs/markers/add-and-remove.spec.ts b/google-maps/e2e-tests/tests/specs/markers/add-and-remove.spec.ts new file mode 100644 index 000000000..7b398cc5a --- /dev/null +++ b/google-maps/e2e-tests/tests/specs/markers/add-and-remove.spec.ts @@ -0,0 +1,67 @@ +import * as IonicE2E from '@ionic/e2e'; +import { waitForLoad, pause, setDevice, switchToWeb, url } from '@ionic/e2e'; + +import AddAndRemoveMarkers from '../../pageobjects/markers/add-and-remove.page'; + + +describe('Google Maps - Add and Remove Marker', function () { + let createdMarkerId = ""; + + before(async function () { + await waitForLoad(); + await switchToWeb(); + await url('/markers/add-and-remove'); + await pause(500); + }); + + beforeEach(async function () { + await setDevice(IonicE2E.Device.Mobile); + await switchToWeb(); + await AddAndRemoveMarkers.hideToolBars(); + }); + + after(async function () { + await switchToWeb(); + await AddAndRemoveMarkers.showToolBars(); + await pause(500); + }); + + it("should create a map and add a marker", async function() { + const createMapButton = await AddAndRemoveMarkers.createMapButton; + const addMarkerButton = await AddAndRemoveMarkers.addMarkerButton; + const getCommandOutputText = async function() { + return (await AddAndRemoveMarkers.commandOutputTextarea).getValue(); + } + + await createMapButton.tap(); + await pause(500); + await expect(await getCommandOutputText()).toBe('Map created'); + + await addMarkerButton.tap(); + await pause(500); + await expect(await getCommandOutputText()).toContain('Marker added: '); + + const markerId = (await getCommandOutputText()).replace("Marker added: ", ""); + await expect(markerId).not.toBeFalsy(); + + createdMarkerId = markerId; + }); + + it("should remove the created marker", async function() { + const removeMarkerButton = await AddAndRemoveMarkers.removeMarkerButton; + const commandOutput = await $((await AddAndRemoveMarkers.commandOutputTextarea).selector).$('textarea'); + + await removeMarkerButton.tap(); + await pause(500); + await expect(commandOutput).toHaveValueContaining(`Marker removed: ${createdMarkerId}`); + }); + + it("should throw when attempting to remove a non-existent marker", async function() { + const removeMarkerButton = await AddAndRemoveMarkers.removeMarkerButton; + const commandOutput = await $((await AddAndRemoveMarkers.commandOutputTextarea).selector).$('textarea'); + + await removeMarkerButton.tap(); + await pause(500); + await expect(commandOutput).toHaveValueContaining(`Marker not found for provided id.`); + }); +}); \ No newline at end of file diff --git a/google-maps/e2e-tests/tests/specs/markers/marker-customization.spec.ts b/google-maps/e2e-tests/tests/specs/markers/marker-customization.spec.ts new file mode 100644 index 000000000..4d4a80c11 --- /dev/null +++ b/google-maps/e2e-tests/tests/specs/markers/marker-customization.spec.ts @@ -0,0 +1,125 @@ +import * as IonicE2E from '@ionic/e2e'; +import { waitForLoad, pause, setDevice, switchToWeb, url } from '@ionic/e2e'; + +import MarkerCustomizations from '../../pageobjects/markers/marker-customization.page'; + +describe('Google Maps - Marker Customization', function () { + before(async function () { + await waitForLoad(); + await switchToWeb(); + await url('/markers/customizations'); + await pause(500); + }); + + beforeEach(async function () { + await setDevice(IonicE2E.Device.Mobile); + await switchToWeb(); + await MarkerCustomizations.hideToolBars(); + }); + + after(async function () { + await switchToWeb(); + await MarkerCustomizations.showToolBars(); + await pause(500); + }); + + it('should create a map and add 1 color marker', async function () { + const createMapButton = await MarkerCustomizations.createMapButton; + const removeAllMarkersButton = await MarkerCustomizations.removeAllMarkersButton; + const addColorMarkerButton = await MarkerCustomizations.addMarkerColorButton; + const commandOutput = await $( + ( + await MarkerCustomizations.commandOutputTextarea + ).selector, + ).$('textarea'); + + await createMapButton.tap(); + await pause(500); + await expect(commandOutput).toHaveValue('Map created'); + + await addColorMarkerButton.tap(); + await pause(500); + await expect(commandOutput).toHaveValueContaining('1 color marker added'); + + await removeAllMarkersButton.tap(); + await pause(500); + await expect(commandOutput).toHaveValueContaining('1 markers removed'); + }); + + it('should create a map and add 1 image marker', async function () { + const createMapButton = await MarkerCustomizations.createMapButton; + const removeAllMarkersButton = await MarkerCustomizations.removeAllMarkersButton; + const addImageMarkerButton = await MarkerCustomizations.addMarkerImageButton; + const commandOutput = await $( + ( + await MarkerCustomizations.commandOutputTextarea + ).selector, + ).$('textarea'); + + await createMapButton.tap(); + await pause(500); + await expect(commandOutput).toHaveValue('Map created'); + + await addImageMarkerButton.tap(); + await pause(500); + await expect(commandOutput).toHaveValueContaining('1 image marker added'); + + await removeAllMarkersButton.tap(); + await pause(500); + await expect(commandOutput).toHaveValueContaining('1 markers removed'); + }); + + it('should add 1 image marker', async function () { + const removeAllMarkersButton = await MarkerCustomizations.removeAllMarkersButton; + const addImageMarkerButton = await MarkerCustomizations.addMarkerImageButton; + const commandOutput = await $( + ( + await MarkerCustomizations.commandOutputTextarea + ).selector, + ).$('textarea'); + + await addImageMarkerButton.tap(); + await pause(500); + await expect(commandOutput).toHaveValueContaining('1 image marker added'); + + await removeAllMarkersButton.tap(); + await pause(500); + await expect(commandOutput).toHaveValueContaining('1 markers removed'); + }); + + it('should add 4 image markers', async function () { + const removeAllMarkersButton = await MarkerCustomizations.removeAllMarkersButton; + const addMultipleImageMarkersButton = await MarkerCustomizations.addMultipleImageMarkersButton; + const commandOutput = await $( + ( + await MarkerCustomizations.commandOutputTextarea + ).selector, + ).$('textarea'); + + await addMultipleImageMarkersButton.tap(); + await pause(500); + await expect(commandOutput).toHaveValueContaining('4 image markers added'); + + await removeAllMarkersButton.tap(); + await pause(500); + await expect(commandOutput).toHaveValueContaining('4 markers removed'); + }); + + it('should add 4 color markers', async function () { + const removeAllMarkersButton = await MarkerCustomizations.removeAllMarkersButton; + const addMultipleColorMarkersButton = await MarkerCustomizations.addMultipleColorMarkersButton; + const commandOutput = await $( + ( + await MarkerCustomizations.commandOutputTextarea + ).selector, + ).$('textarea'); + + await addMultipleColorMarkersButton.tap(); + await pause(500); + await expect(commandOutput).toHaveValueContaining('4 color markers added'); + + await removeAllMarkersButton.tap(); + await pause(500); + await expect(commandOutput).toHaveValueContaining('4 markers removed'); + }); +}); diff --git a/google-maps/e2e-tests/tests/specs/markers/multiple-markers.spec.ts b/google-maps/e2e-tests/tests/specs/markers/multiple-markers.spec.ts new file mode 100644 index 000000000..f1d2b3e56 --- /dev/null +++ b/google-maps/e2e-tests/tests/specs/markers/multiple-markers.spec.ts @@ -0,0 +1,71 @@ +import * as IonicE2E from '@ionic/e2e'; +import { waitForLoad, pause, setDevice, switchToWeb, url } from '@ionic/e2e'; + +import MultipleMarkers from '../../pageobjects/markers/multiple-markers.page'; + +describe('Google Maps - Multiple Markers', function () { + before(async function () { + await waitForLoad(); + await switchToWeb(); + await url('/markers/multiple-markers'); + await pause(500); + }); + + beforeEach(async function () { + await setDevice(IonicE2E.Device.Mobile); + await switchToWeb(); + await MultipleMarkers.hideToolBars(); + }); + + after(async function () { + await switchToWeb(); + await MultipleMarkers.showToolBars(); + await pause(500); + }); + + it("should create a map and add 4 markers", async function() { + const createMapButton = await MultipleMarkers.createMapButton; + const addMarkersButton = await MultipleMarkers.addMarkersButton; + const commandOutput = await $((await MultipleMarkers.commandOutputTextarea).selector).$('textarea'); + + await createMapButton.tap(); + await pause(500); + await expect(commandOutput).toHaveValue('Map created'); + + await addMarkersButton.tap(); + await pause(500); + await expect(commandOutput).toHaveValueContaining('4 markers added'); + }) + + it("should enable and disable clustering", async function() { + const enableClusteringButton = await MultipleMarkers.enableClusteringButton; + const disableClusteringButton = await MultipleMarkers.disableClusteringButton; + const commandOutput = await $((await MultipleMarkers.commandOutputTextarea).selector).$('textarea'); + + await enableClusteringButton.tap(); + await pause(500); + await expect(commandOutput).toHaveValue('marker clustering enabled'); + + await disableClusteringButton.tap(); + await pause(500); + await expect(commandOutput).toHaveValue('marker clustering disabled'); + }) + + it("should remove 4 markers", async function() { + const removeMarkersButton = await MultipleMarkers.removeMarkersButton; + const commandOutput = await $((await MultipleMarkers.commandOutputTextarea).selector).$('textarea'); + + await removeMarkersButton.tap() + await pause(500); + await expect(commandOutput).toHaveValue('4 markers removed'); + }) + + it("should throw error when attempting to remove no markers", async function() { + const removeMarkersButton = await MultipleMarkers.removeMarkersButton; + const commandOutput = await $((await MultipleMarkers.commandOutputTextarea).selector).$('textarea'); + + await removeMarkersButton.tap() + await pause(500); + await expect(commandOutput).toHaveValue('Invalid Arguments Provided: markerIds requires at least one marker id.'); + }) +}) \ No newline at end of file diff --git a/google-maps/e2e-tests/tsconfig.json b/google-maps/e2e-tests/tsconfig.json new file mode 100644 index 000000000..a273b0cfc --- /dev/null +++ b/google-maps/e2e-tests/tsconfig.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "target": "es5", + "lib": [ + "dom", + "dom.iterable", + "esnext" + ], + "allowJs": true, + "skipLibCheck": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "noFallthroughCasesInSwitch": true, + "module": "esnext", + "moduleResolution": "node", + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx" + }, + "include": [ + "src" + ] +} diff --git a/google-maps/ios/Plugin.xcodeproj/project.pbxproj b/google-maps/ios/Plugin.xcodeproj/project.pbxproj new file mode 100644 index 000000000..d67f0e78b --- /dev/null +++ b/google-maps/ios/Plugin.xcodeproj/project.pbxproj @@ -0,0 +1,627 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 48; + objects = { + +/* Begin PBXBuildFile section */ + 0238AED727C931A40012930B /* GoogleMapCameraConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0238AED627C931A40012930B /* GoogleMapCameraConfig.swift */; }; + 0238AED927C945840012930B /* GoogleMapPadding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0238AED827C945840012930B /* GoogleMapPadding.swift */; }; + 02404C8D279F408800CEF8C8 /* GoogleMapErrors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02404C8C279F408800CEF8C8 /* GoogleMapErrors.swift */; }; + 02404C8F279F43E900CEF8C8 /* GoogleMapConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02404C8E279F43E900CEF8C8 /* GoogleMapConfig.swift */; }; + 02C012C327A9D20200FAAE78 /* Marker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02C012C227A9D20200FAAE78 /* Marker.swift */; }; + 02C6EDF22798803E00D51BF6 /* Map.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02C6EDF12798803E00D51BF6 /* Map.swift */; }; + 03FC29A292ACC40490383A1F /* Pods_Plugin.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B2A61DA5A1F2DD4F959604D /* Pods_Plugin.framework */; }; + 20C0B05DCFC8E3958A738AF2 /* Pods_PluginTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F6753A823D3815DB436415E3 /* Pods_PluginTests.framework */; }; + 50ADFF92201F53D600D50D53 /* Plugin.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 50ADFF88201F53D600D50D53 /* Plugin.framework */; }; + 50ADFF97201F53D600D50D53 /* CapacitorGoogleMapsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50ADFF96201F53D600D50D53 /* CapacitorGoogleMapsTests.swift */; }; + 50ADFF99201F53D600D50D53 /* CapacitorGoogleMapsPlugin.h in Headers */ = {isa = PBXBuildFile; fileRef = 50ADFF8B201F53D600D50D53 /* CapacitorGoogleMapsPlugin.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 50ADFFA42020D75100D50D53 /* Capacitor.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 50ADFFA52020D75100D50D53 /* Capacitor.framework */; }; + 50ADFFA82020EE4F00D50D53 /* CapacitorGoogleMapsPlugin.m in Sources */ = {isa = PBXBuildFile; fileRef = 50ADFFA72020EE4F00D50D53 /* CapacitorGoogleMapsPlugin.m */; }; + 50E1A94820377CB70090CE1A /* CapacitorGoogleMapsPlugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50E1A94720377CB70090CE1A /* CapacitorGoogleMapsPlugin.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 50ADFF93201F53D600D50D53 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 50ADFF7F201F53D600D50D53 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 50ADFF87201F53D600D50D53; + remoteInfo = Plugin; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 0238AED627C931A40012930B /* GoogleMapCameraConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GoogleMapCameraConfig.swift; sourceTree = ""; }; + 0238AED827C945840012930B /* GoogleMapPadding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GoogleMapPadding.swift; sourceTree = ""; }; + 02404C8C279F408800CEF8C8 /* GoogleMapErrors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GoogleMapErrors.swift; sourceTree = ""; }; + 02404C8E279F43E900CEF8C8 /* GoogleMapConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GoogleMapConfig.swift; sourceTree = ""; }; + 02C012C227A9D20200FAAE78 /* Marker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Marker.swift; sourceTree = ""; }; + 02C6EDF12798803E00D51BF6 /* Map.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Map.swift; sourceTree = ""; }; + 3B2A61DA5A1F2DD4F959604D /* Pods_Plugin.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Plugin.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 50ADFF88201F53D600D50D53 /* Plugin.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Plugin.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 50ADFF8B201F53D600D50D53 /* CapacitorGoogleMapsPlugin.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CapacitorGoogleMapsPlugin.h; sourceTree = ""; }; + 50ADFF8C201F53D600D50D53 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 50ADFF91201F53D600D50D53 /* PluginTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PluginTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 50ADFF96201F53D600D50D53 /* CapacitorGoogleMapsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CapacitorGoogleMapsTests.swift; sourceTree = ""; }; + 50ADFF98201F53D600D50D53 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 50ADFFA52020D75100D50D53 /* Capacitor.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Capacitor.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 50ADFFA72020EE4F00D50D53 /* CapacitorGoogleMapsPlugin.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CapacitorGoogleMapsPlugin.m; sourceTree = ""; }; + 50E1A94720377CB70090CE1A /* CapacitorGoogleMapsPlugin.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CapacitorGoogleMapsPlugin.swift; sourceTree = ""; }; + 5E23F77F099397094342571A /* Pods-Plugin.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Plugin.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Plugin/Pods-Plugin.debug.xcconfig"; sourceTree = ""; }; + 91781294A431A2A7CC6EB714 /* Pods-Plugin.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Plugin.release.xcconfig"; path = "Pods/Target Support Files/Pods-Plugin/Pods-Plugin.release.xcconfig"; sourceTree = ""; }; + 96ED1B6440D6672E406C8D19 /* Pods-PluginTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PluginTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-PluginTests/Pods-PluginTests.debug.xcconfig"; sourceTree = ""; }; + F65BB2953ECE002E1EF3E424 /* Pods-PluginTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PluginTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-PluginTests/Pods-PluginTests.release.xcconfig"; sourceTree = ""; }; + F6753A823D3815DB436415E3 /* Pods_PluginTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_PluginTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 50ADFF84201F53D600D50D53 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 50ADFFA42020D75100D50D53 /* Capacitor.framework in Frameworks */, + 03FC29A292ACC40490383A1F /* Pods_Plugin.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 50ADFF8E201F53D600D50D53 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 50ADFF92201F53D600D50D53 /* Plugin.framework in Frameworks */, + 20C0B05DCFC8E3958A738AF2 /* Pods_PluginTests.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 50ADFF7E201F53D600D50D53 = { + isa = PBXGroup; + children = ( + 50ADFF8A201F53D600D50D53 /* Plugin */, + 50ADFF95201F53D600D50D53 /* PluginTests */, + 50ADFF89201F53D600D50D53 /* Products */, + 8C8E7744173064A9F6D438E3 /* Pods */, + A797B9EFA3DCEFEA1FBB66A9 /* Frameworks */, + ); + sourceTree = ""; + }; + 50ADFF89201F53D600D50D53 /* Products */ = { + isa = PBXGroup; + children = ( + 50ADFF88201F53D600D50D53 /* Plugin.framework */, + 50ADFF91201F53D600D50D53 /* PluginTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 50ADFF8A201F53D600D50D53 /* Plugin */ = { + isa = PBXGroup; + children = ( + 50E1A94720377CB70090CE1A /* CapacitorGoogleMapsPlugin.swift */, + 02C6EDF12798803E00D51BF6 /* Map.swift */, + 50ADFF8B201F53D600D50D53 /* CapacitorGoogleMapsPlugin.h */, + 50ADFFA72020EE4F00D50D53 /* CapacitorGoogleMapsPlugin.m */, + 50ADFF8C201F53D600D50D53 /* Info.plist */, + 02404C8C279F408800CEF8C8 /* GoogleMapErrors.swift */, + 02404C8E279F43E900CEF8C8 /* GoogleMapConfig.swift */, + 02C012C227A9D20200FAAE78 /* Marker.swift */, + 0238AED627C931A40012930B /* GoogleMapCameraConfig.swift */, + 0238AED827C945840012930B /* GoogleMapPadding.swift */, + ); + path = Plugin; + sourceTree = ""; + }; + 50ADFF95201F53D600D50D53 /* PluginTests */ = { + isa = PBXGroup; + children = ( + 50ADFF96201F53D600D50D53 /* CapacitorGoogleMapsTests.swift */, + 50ADFF98201F53D600D50D53 /* Info.plist */, + ); + path = PluginTests; + sourceTree = ""; + }; + 8C8E7744173064A9F6D438E3 /* Pods */ = { + isa = PBXGroup; + children = ( + 5E23F77F099397094342571A /* Pods-Plugin.debug.xcconfig */, + 91781294A431A2A7CC6EB714 /* Pods-Plugin.release.xcconfig */, + 96ED1B6440D6672E406C8D19 /* Pods-PluginTests.debug.xcconfig */, + F65BB2953ECE002E1EF3E424 /* Pods-PluginTests.release.xcconfig */, + ); + name = Pods; + sourceTree = ""; + }; + A797B9EFA3DCEFEA1FBB66A9 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 50ADFFA52020D75100D50D53 /* Capacitor.framework */, + 3B2A61DA5A1F2DD4F959604D /* Pods_Plugin.framework */, + F6753A823D3815DB436415E3 /* Pods_PluginTests.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 50ADFF85201F53D600D50D53 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 50ADFF99201F53D600D50D53 /* CapacitorGoogleMapsPlugin.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 50ADFF87201F53D600D50D53 /* Plugin */ = { + isa = PBXNativeTarget; + buildConfigurationList = 50ADFF9C201F53D600D50D53 /* Build configuration list for PBXNativeTarget "Plugin" */; + buildPhases = ( + AB5B3E54B4E897F32C2279DA /* [CP] Check Pods Manifest.lock */, + 50ADFF83201F53D600D50D53 /* Sources */, + 50ADFF84201F53D600D50D53 /* Frameworks */, + 50ADFF85201F53D600D50D53 /* Headers */, + 50ADFF86201F53D600D50D53 /* Resources */, + 27D2989C782FE41D4C77DB9C /* [CP] Copy Pods Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Plugin; + productName = Plugin; + productReference = 50ADFF88201F53D600D50D53 /* Plugin.framework */; + productType = "com.apple.product-type.framework"; + }; + 50ADFF90201F53D600D50D53 /* PluginTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 50ADFF9F201F53D600D50D53 /* Build configuration list for PBXNativeTarget "PluginTests" */; + buildPhases = ( + 0596884F929ED6F1DE134961 /* [CP] Check Pods Manifest.lock */, + 50ADFF8D201F53D600D50D53 /* Sources */, + 50ADFF8E201F53D600D50D53 /* Frameworks */, + 50ADFF8F201F53D600D50D53 /* Resources */, + 8E97F58B69A94C6503FC9C85 /* [CP] Embed Pods Frameworks */, + 387C5C3A5D666D8067A600EA /* [CP] Copy Pods Resources */, + ); + buildRules = ( + ); + dependencies = ( + 50ADFF94201F53D600D50D53 /* PBXTargetDependency */, + ); + name = PluginTests; + productName = PluginTests; + productReference = 50ADFF91201F53D600D50D53 /* PluginTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 50ADFF7F201F53D600D50D53 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0920; + LastUpgradeCheck = 1160; + ORGANIZATIONNAME = "Max Lynch"; + TargetAttributes = { + 50ADFF87201F53D600D50D53 = { + CreatedOnToolsVersion = 9.2; + LastSwiftMigration = 1100; + ProvisioningStyle = Automatic; + }; + 50ADFF90201F53D600D50D53 = { + CreatedOnToolsVersion = 9.2; + LastSwiftMigration = 1100; + ProvisioningStyle = Automatic; + }; + }; + }; + buildConfigurationList = 50ADFF82201F53D600D50D53 /* Build configuration list for PBXProject "Plugin" */; + compatibilityVersion = "Xcode 8.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 50ADFF7E201F53D600D50D53; + productRefGroup = 50ADFF89201F53D600D50D53 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 50ADFF87201F53D600D50D53 /* Plugin */, + 50ADFF90201F53D600D50D53 /* PluginTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 50ADFF86201F53D600D50D53 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 50ADFF8F201F53D600D50D53 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 0596884F929ED6F1DE134961 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-PluginTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 27D2989C782FE41D4C77DB9C /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Plugin/Pods-Plugin-resources.sh", + "${PODS_ROOT}/GoogleMaps/Maps/Frameworks/GoogleMaps.framework/Resources/GoogleMaps.bundle", + ); + name = "[CP] Copy Pods Resources"; + outputPaths = ( + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/GoogleMaps.bundle", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Plugin/Pods-Plugin-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; + 387C5C3A5D666D8067A600EA /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-PluginTests/Pods-PluginTests-resources.sh", + "${PODS_ROOT}/GoogleMaps/Maps/Frameworks/GoogleMaps.framework/Resources/GoogleMaps.bundle", + ); + name = "[CP] Copy Pods Resources"; + outputPaths = ( + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/GoogleMaps.bundle", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-PluginTests/Pods-PluginTests-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; + 8E97F58B69A94C6503FC9C85 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-PluginTests/Pods-PluginTests-frameworks.sh", + "${BUILT_PRODUCTS_DIR}/Capacitor/Capacitor.framework", + "${BUILT_PRODUCTS_DIR}/CapacitorCordova/Cordova.framework", + ); + name = "[CP] Embed Pods Frameworks"; + outputPaths = ( + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Capacitor.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Cordova.framework", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-PluginTests/Pods-PluginTests-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + AB5B3E54B4E897F32C2279DA /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Plugin-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 50ADFF83201F53D600D50D53 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 02404C8D279F408800CEF8C8 /* GoogleMapErrors.swift in Sources */, + 50E1A94820377CB70090CE1A /* CapacitorGoogleMapsPlugin.swift in Sources */, + 0238AED727C931A40012930B /* GoogleMapCameraConfig.swift in Sources */, + 0238AED927C945840012930B /* GoogleMapPadding.swift in Sources */, + 02404C8F279F43E900CEF8C8 /* GoogleMapConfig.swift in Sources */, + 02C6EDF22798803E00D51BF6 /* Map.swift in Sources */, + 50ADFFA82020EE4F00D50D53 /* CapacitorGoogleMapsPlugin.m in Sources */, + 02C012C327A9D20200FAAE78 /* Marker.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 50ADFF8D201F53D600D50D53 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 50ADFF97201F53D600D50D53 /* CapacitorGoogleMapsTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 50ADFF94201F53D600D50D53 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 50ADFF87201F53D600D50D53 /* Plugin */; + targetProxy = 50ADFF93201F53D600D50D53 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 50ADFF9A201F53D600D50D53 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + FRAMEWORK_SEARCH_PATHS = ( + "\"${BUILT_PRODUCTS_DIR}/Capacitor\"", + "\"${BUILT_PRODUCTS_DIR}/CapacitorCordova\"", + ); + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 50ADFF9B201F53D600D50D53 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + FRAMEWORK_SEARCH_PATHS = ( + "\"${BUILT_PRODUCTS_DIR}/Capacitor\"", + "\"${BUILT_PRODUCTS_DIR}/CapacitorCordova\"", + ); + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 50ADFF9D201F53D600D50D53 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 5E23F77F099397094342571A /* Pods-Plugin.debug.xcconfig */; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_IDENTITY = ""; + CODE_SIGN_STYLE = Automatic; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = Plugin/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks $(FRAMEWORK_SEARCH_PATHS)\n$(FRAMEWORK_SEARCH_PATHS)\n$(FRAMEWORK_SEARCH_PATHS)"; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_BUNDLE_IDENTIFIER = com.getcapacitor.Plugin; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 50ADFF9E201F53D600D50D53 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 91781294A431A2A7CC6EB714 /* Pods-Plugin.release.xcconfig */; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_IDENTITY = ""; + CODE_SIGN_STYLE = Automatic; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = Plugin/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks $(FRAMEWORK_SEARCH_PATHS)"; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_BUNDLE_IDENTIFIER = com.getcapacitor.Plugin; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; + 50ADFFA0201F53D600D50D53 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 96ED1B6440D6672E406C8D19 /* Pods-PluginTests.debug.xcconfig */; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + INFOPLIST_FILE = PluginTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.getcapacitor.PluginTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 50ADFFA1201F53D600D50D53 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = F65BB2953ECE002E1EF3E424 /* Pods-PluginTests.release.xcconfig */; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + INFOPLIST_FILE = PluginTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.getcapacitor.PluginTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 50ADFF82201F53D600D50D53 /* Build configuration list for PBXProject "Plugin" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 50ADFF9A201F53D600D50D53 /* Debug */, + 50ADFF9B201F53D600D50D53 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 50ADFF9C201F53D600D50D53 /* Build configuration list for PBXNativeTarget "Plugin" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 50ADFF9D201F53D600D50D53 /* Debug */, + 50ADFF9E201F53D600D50D53 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 50ADFF9F201F53D600D50D53 /* Build configuration list for PBXNativeTarget "PluginTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 50ADFFA0201F53D600D50D53 /* Debug */, + 50ADFFA1201F53D600D50D53 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 50ADFF7F201F53D600D50D53 /* Project object */; +} diff --git a/storage/ios/Plugin.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/google-maps/ios/Plugin.xcodeproj/project.xcworkspace/contents.xcworkspacedata similarity index 100% rename from storage/ios/Plugin.xcodeproj/project.xcworkspace/contents.xcworkspacedata rename to google-maps/ios/Plugin.xcodeproj/project.xcworkspace/contents.xcworkspacedata diff --git a/storage/ios/Plugin.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/google-maps/ios/Plugin.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist similarity index 100% rename from storage/ios/Plugin.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist rename to google-maps/ios/Plugin.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/storage/ios/Plugin.xcodeproj/xcshareddata/xcschemes/Plugin.xcscheme b/google-maps/ios/Plugin.xcodeproj/xcshareddata/xcschemes/Plugin.xcscheme similarity index 100% rename from storage/ios/Plugin.xcodeproj/xcshareddata/xcschemes/Plugin.xcscheme rename to google-maps/ios/Plugin.xcodeproj/xcshareddata/xcschemes/Plugin.xcscheme diff --git a/storage/ios/Plugin.xcodeproj/xcshareddata/xcschemes/PluginTests.xcscheme b/google-maps/ios/Plugin.xcodeproj/xcshareddata/xcschemes/PluginTests.xcscheme similarity index 100% rename from storage/ios/Plugin.xcodeproj/xcshareddata/xcschemes/PluginTests.xcscheme rename to google-maps/ios/Plugin.xcodeproj/xcshareddata/xcschemes/PluginTests.xcscheme diff --git a/storage/ios/Plugin.xcworkspace/contents.xcworkspacedata b/google-maps/ios/Plugin.xcworkspace/contents.xcworkspacedata similarity index 100% rename from storage/ios/Plugin.xcworkspace/contents.xcworkspacedata rename to google-maps/ios/Plugin.xcworkspace/contents.xcworkspacedata diff --git a/google-maps/ios/Plugin.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/google-maps/ios/Plugin.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/google-maps/ios/Plugin.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/storage/ios/Plugin/StoragePlugin.h b/google-maps/ios/Plugin/CapacitorGoogleMapsPlugin.h similarity index 100% rename from storage/ios/Plugin/StoragePlugin.h rename to google-maps/ios/Plugin/CapacitorGoogleMapsPlugin.h diff --git a/google-maps/ios/Plugin/CapacitorGoogleMapsPlugin.m b/google-maps/ios/Plugin/CapacitorGoogleMapsPlugin.m new file mode 100644 index 000000000..165cf022c --- /dev/null +++ b/google-maps/ios/Plugin/CapacitorGoogleMapsPlugin.m @@ -0,0 +1,24 @@ +#import +#import + +// Define the plugin using the CAP_PLUGIN Macro, and +// each method the plugin supports using the CAP_PLUGIN_METHOD macro. +CAP_PLUGIN(CapacitorGoogleMapsPlugin, "CapacitorGoogleMaps", + CAP_PLUGIN_METHOD(create, CAPPluginReturnPromise); + CAP_PLUGIN_METHOD(addMarker, CAPPluginReturnPromise); + CAP_PLUGIN_METHOD(addMarkers, CAPPluginReturnPromise); + CAP_PLUGIN_METHOD(removeMarker, CAPPluginReturnPromise); + CAP_PLUGIN_METHOD(removeMarkers, CAPPluginReturnPromise); + CAP_PLUGIN_METHOD(enableClustering, CAPPluginReturnPromise); + CAP_PLUGIN_METHOD(disableClustering, CAPPluginReturnPromise); + CAP_PLUGIN_METHOD(destroy, CAPPluginReturnPromise); + CAP_PLUGIN_METHOD(setCamera, CAPPluginReturnPromise); + CAP_PLUGIN_METHOD(setMapType, CAPPluginReturnPromise); + CAP_PLUGIN_METHOD(enableIndoorMaps, CAPPluginReturnPromise); + CAP_PLUGIN_METHOD(enableTrafficLayer, CAPPluginReturnPromise); + CAP_PLUGIN_METHOD(enableAccessibilityElements, CAPPluginReturnPromise); + CAP_PLUGIN_METHOD(enableCurrentLocation, CAPPluginReturnPromise); + CAP_PLUGIN_METHOD(setPadding, CAPPluginReturnPromise); + CAP_PLUGIN_METHOD(onScroll, CAPPluginReturnPromise); + CAP_PLUGIN_METHOD(getMapBounds, CAPPluginReturnPromise); +) diff --git a/google-maps/ios/Plugin/CapacitorGoogleMapsPlugin.swift b/google-maps/ios/Plugin/CapacitorGoogleMapsPlugin.swift new file mode 100644 index 000000000..368399622 --- /dev/null +++ b/google-maps/ios/Plugin/CapacitorGoogleMapsPlugin.swift @@ -0,0 +1,678 @@ +import Foundation +import Capacitor +import GoogleMaps +import GoogleMapsUtils + +extension GMSMapViewType { + static func fromString(mapType: String) -> GMSMapViewType { + switch mapType { + case "Normal": + return .normal + case "Hybrid": + return .hybrid + case "Satellite": + return .satellite + case "Terrain": + return .terrain + case "None": + return .none + default: + print("CapacitorGoogleMaps Warning: unknown mapView type '\(mapType)'. Defaulting to normal.") + return .normal + } + } +} + +extension CGRect { + static func fromJSObject(_ jsObject: JSObject) throws -> CGRect { + guard let width = jsObject["width"] as? Double else { + throw GoogleMapErrors.invalidArguments("bounds object is missing the required 'width' property") + } + + guard let height = jsObject["height"] as? Double else { + throw GoogleMapErrors.invalidArguments("bounds object is missing the required 'height' property") + } + + guard let x = jsObject["x"] as? Double else { + throw GoogleMapErrors.invalidArguments("bounds object is missing the required 'x' property") + } + + guard let y = jsObject["y"] as? Double else { + throw GoogleMapErrors.invalidArguments("bounds object is missing the required 'y' property") + } + + return CGRect(x: x, y: y, width: width, height: height) + } +} + +// swiftlint:disable type_body_length +@objc(CapacitorGoogleMapsPlugin) +public class CapacitorGoogleMapsPlugin: CAPPlugin, GMSMapViewDelegate { + private var maps = [String: Map]() + private var isInitialized = false + + func checkLocationPermission() -> String { + let locationState: String + + switch CLLocationManager.authorizationStatus() { + case .notDetermined: + locationState = "prompt" + case .restricted, .denied: + locationState = "denied" + case .authorizedAlways, .authorizedWhenInUse: + locationState = "granted" + @unknown default: + locationState = "prompt" + } + + return locationState + } + + @objc func create(_ call: CAPPluginCall) { + do { + if !isInitialized { + guard let apiKey = call.getString("apiKey") else { + throw GoogleMapErrors.invalidAPIKey + } + + GMSServices.provideAPIKey(apiKey) + isInitialized = true + } + + guard let id = call.getString("id") else { + throw GoogleMapErrors.invalidMapId + } + + guard let configObj = call.getObject("config") else { + throw GoogleMapErrors.invalidArguments("config object is missing") + } + + let forceCreate = call.getBool("forceCreate", false) + + let config = try GoogleMapConfig(fromJSObject: configObj) + + if self.maps[id] != nil { + if !forceCreate { + call.resolve() + return + } + + let removedMap = self.maps.removeValue(forKey: id) + removedMap?.destroy() + } + + DispatchQueue.main.sync { + let newMap = Map(id: id, config: config, delegate: self) + self.maps[id] = newMap + } + + call.resolve() + } catch { + handleError(call, error: error) + } + } + + @objc func destroy(_ call: CAPPluginCall) { + do { + guard let id = call.getString("id") else { + throw GoogleMapErrors.invalidMapId + } + + guard let removedMap = self.maps.removeValue(forKey: id) else { + throw GoogleMapErrors.mapNotFound + } + + removedMap.destroy() + call.resolve() + } catch { + handleError(call, error: error) + } + } + + @objc func addMarker(_ call: CAPPluginCall) { + do { + guard let id = call.getString("id") else { + throw GoogleMapErrors.invalidMapId + } + + guard let markerObj = call.getObject("marker") else { + throw GoogleMapErrors.invalidArguments("marker object is missing") + } + + let marker = try Marker(fromJSObject: markerObj) + + guard let map = self.maps[id] else { + throw GoogleMapErrors.mapNotFound + } + + let markerId = try map.addMarker(marker: marker) + + call.resolve(["id": String(markerId)]) + + } catch { + handleError(call, error: error) + } + } + + @objc func addMarkers(_ call: CAPPluginCall) { + do { + guard let id = call.getString("id") else { + throw GoogleMapErrors.invalidMapId + } + + guard let markerObjs = call.getArray("markers") as? [JSObject] else { + throw GoogleMapErrors.invalidArguments("markers array is missing") + } + + if markerObjs.isEmpty { + throw GoogleMapErrors.invalidArguments("markers requires at least one marker") + } + + guard let map = self.maps[id] else { + throw GoogleMapErrors.mapNotFound + } + + var markers: [Marker] = [] + + try markerObjs.forEach { marker in + let marker = try Marker(fromJSObject: marker) + markers.append(marker) + } + + let ids = try map.addMarkers(markers: markers) + + call.resolve(["ids": ids.map({ id in + return String(id) + })]) + + } catch { + handleError(call, error: error) + } + } + + @objc func removeMarkers(_ call: CAPPluginCall) { + do { + guard let id = call.getString("id") else { + throw GoogleMapErrors.invalidMapId + } + + guard let markerIdStrings = call.getArray("markerIds") as? [String] else { + throw GoogleMapErrors.invalidArguments("markerIds are invalid or missing") + } + + if markerIdStrings.isEmpty { + throw GoogleMapErrors.invalidArguments("markerIds requires at least one marker id") + } + + let ids: [Int] = try markerIdStrings.map { idString in + guard let markerId = Int(idString) else { + throw GoogleMapErrors.invalidArguments("markerIds are invalid or missing") + } + + return markerId + } + + guard let map = self.maps[id] else { + throw GoogleMapErrors.mapNotFound + } + + try map.removeMarkers(ids: ids) + + call.resolve() + } catch { + handleError(call, error: error) + } + } + + @objc func removeMarker(_ call: CAPPluginCall) { + do { + guard let id = call.getString("id") else { + throw GoogleMapErrors.invalidMapId + } + + guard let markerIdString = call.getString("markerId") else { + throw GoogleMapErrors.invalidArguments("markerId is invalid or missing") + } + + guard let markerId = Int(markerIdString) else { + throw GoogleMapErrors.invalidArguments("markerId is invalid or missing") + } + + guard let map = self.maps[id] else { + throw GoogleMapErrors.mapNotFound + } + + try map.removeMarker(id: markerId) + + call.resolve() + + } catch { + handleError(call, error: error) + } + } + + @objc func setCamera(_ call: CAPPluginCall) { + do { + guard let id = call.getString("id") else { + throw GoogleMapErrors.invalidMapId + } + + guard let map = self.maps[id] else { + throw GoogleMapErrors.mapNotFound + } + + guard let configObj = call.getObject("config") else { + throw GoogleMapErrors.invalidArguments("config object is missing") + } + + let config = try GoogleMapCameraConfig(fromJSObject: configObj) + + try map.setCamera(config: config) + + call.resolve() + } catch { + handleError(call, error: error) + } + } + + @objc func setMapType(_ call: CAPPluginCall) { + do { + guard let id = call.getString("id") else { + throw GoogleMapErrors.invalidMapId + } + + guard let map = self.maps[id] else { + throw GoogleMapErrors.mapNotFound + } + + guard let mapTypeString = call.getString("mapType") else { + throw GoogleMapErrors.invalidArguments("mapType is missing") + } + + let mapType = GMSMapViewType.fromString(mapType: mapTypeString) + + try map.setMapType(mapType: mapType) + + call.resolve() + } catch { + handleError(call, error: error) + } + } + + @objc func enableIndoorMaps(_ call: CAPPluginCall) { + do { + guard let id = call.getString("id") else { + throw GoogleMapErrors.invalidMapId + } + + guard let map = self.maps[id] else { + throw GoogleMapErrors.mapNotFound + } + + guard let enabled = call.getBool("enabled") else { + throw GoogleMapErrors.invalidArguments("enabled is missing") + } + + try map.enableIndoorMaps(enabled: enabled) + + call.resolve() + } catch { + handleError(call, error: error) + } + } + + @objc func enableTrafficLayer(_ call: CAPPluginCall) { + do { + guard let id = call.getString("id") else { + throw GoogleMapErrors.invalidMapId + } + + guard let map = self.maps[id] else { + throw GoogleMapErrors.mapNotFound + } + + guard let enabled = call.getBool("enabled") else { + throw GoogleMapErrors.invalidArguments("enabled is missing") + } + + try map.enableTrafficLayer(enabled: enabled) + + call.resolve() + } catch { + handleError(call, error: error) + } + } + + @objc func enableAccessibilityElements(_ call: CAPPluginCall) { + do { + guard let id = call.getString("id") else { + throw GoogleMapErrors.invalidMapId + } + + guard let map = self.maps[id] else { + throw GoogleMapErrors.mapNotFound + } + + guard let enabled = call.getBool("enabled") else { + throw GoogleMapErrors.invalidArguments("enabled is missing") + } + + try map.enableAccessibilityElements(enabled: enabled) + + call.resolve() + } catch { + handleError(call, error: error) + } + } + + @objc func setPadding(_ call: CAPPluginCall) { + do { + guard let id = call.getString("id") else { + throw GoogleMapErrors.invalidMapId + } + + guard let map = self.maps[id] else { + throw GoogleMapErrors.mapNotFound + } + + guard let configObj = call.getObject("padding") else { + throw GoogleMapErrors.invalidArguments("padding is missing") + } + + let padding = try GoogleMapPadding.init(fromJSObject: configObj) + + try map.setPadding(padding: padding) + + call.resolve() + } catch { + handleError(call, error: error) + } + } + + @objc func enableCurrentLocation(_ call: CAPPluginCall) { + do { + guard let id = call.getString("id") else { + throw GoogleMapErrors.invalidMapId + } + + guard let map = self.maps[id] else { + throw GoogleMapErrors.mapNotFound + } + + guard let enabled = call.getBool("enabled") else { + throw GoogleMapErrors.invalidArguments("enabled is missing") + } + + if enabled && checkLocationPermission() != "granted" { + throw GoogleMapErrors.permissionsDeniedLocation + } + + try map.enableCurrentLocation(enabled: enabled) + + call.resolve() + } catch { + handleError(call, error: error) + } + } + + @objc func enableClustering(_ call: CAPPluginCall) { + do { + guard let id = call.getString("id") else { + throw GoogleMapErrors.invalidMapId + } + + guard let map = self.maps[id] else { + throw GoogleMapErrors.mapNotFound + } + + map.enableClustering() + call.resolve() + + } catch { + handleError(call, error: error) + } + } + + @objc func disableClustering(_ call: CAPPluginCall) { + do { + guard let id = call.getString("id") else { + throw GoogleMapErrors.invalidMapId + } + + guard let map = self.maps[id] else { + throw GoogleMapErrors.mapNotFound + } + + map.disableClustering() + call.resolve() + } catch { + handleError(call, error: error) + } + } + + @objc func onScroll(_ call: CAPPluginCall) { + call.unavailable("not supported on iOS") + } + + @objc func getMapBounds(_ call: CAPPluginCall) { + do { + guard let id = call.getString("id") else { + throw GoogleMapErrors.invalidMapId + } + + guard let map = self.maps[id] else { + throw GoogleMapErrors.mapNotFound + } + + try DispatchQueue.main.sync { + guard let bounds = map.getMapLatLngBounds() else { + throw GoogleMapErrors.unhandledError("Google Map Bounds could not be found.") + } + + call.resolve( + formatMapBoundsForResponse( + bounds: bounds, + cameraPosition: map.mapViewController.GMapView.camera + ) + ) + } + } catch { + handleError(call, error: error) + } + } + + private func formatMapBoundsForResponse(bounds: GMSCoordinateBounds?, cameraPosition: GMSCameraPosition) -> PluginCallResultData { + return [ + "southwest": [ + "lat": bounds?.southWest.latitude, + "lng": bounds?.southWest.longitude + ], + "center": [ + "lat": cameraPosition.target.latitude, + "lng": cameraPosition.target.longitude + ], + "northeast": [ + "lat": bounds?.northEast.latitude, + "lng": bounds?.northEast.longitude + ] + ] + } + + private func handleError(_ call: CAPPluginCall, error: Error) { + let errObject = getErrorObject(error) + call.reject(errObject.message, "\(errObject.code)", error, [:]) + } + + private func findMapIdByMapView(_ mapView: GMSMapView) -> String { + for (mapId, map) in self.maps { + if map.mapViewController.GMapView === mapView { + return mapId + } + } + return "" + } + + // --- EVENT LISTENERS --- + + // onCameraIdle + public func mapView(_ mapView: GMSMapView, idleAt cameraPosition: GMSCameraPosition) { + let mapId = self.findMapIdByMapView(mapView) + let map = self.maps[mapId] + let bounds = map?.getMapLatLngBounds() + + let data: PluginCallResultData = [ + "mapId": mapId, + "bounds": formatMapBoundsForResponse( + bounds: bounds, + cameraPosition: cameraPosition + ), + "bearing": cameraPosition.bearing, + "latitude": cameraPosition.target.latitude, + "longitude": cameraPosition.target.longitude, + "tilt": cameraPosition.viewingAngle, + "zoom": cameraPosition.zoom + ] + + self.notifyListeners("onBoundsChanged", data: data) + self.notifyListeners("onCameraIdle", data: data) + } + + // onCameraMoveStarted + public func mapView(_ mapView: GMSMapView, willMove gesture: Bool) { + self.notifyListeners("onCameraMoveStarted", data: [ + "mapId": self.findMapIdByMapView(mapView), + "isGesture": gesture + ]) + } + + // onMapClick + public func mapView(_ mapView: GMSMapView, didTapAt coordinate: CLLocationCoordinate2D) { + self.notifyListeners("onMapClick", data: [ + "mapId": self.findMapIdByMapView(mapView), + "latitude": coordinate.latitude, + "longitude": coordinate.longitude + ]) + } + + // onClusterClick, onMarkerClick + public func mapView(_ mapView: GMSMapView, didTap marker: GMSMarker) -> Bool { + if let cluster = marker.userData as? GMUCluster { + var items: [[String: Any?]] = [] + + for item in cluster.items { + items.append([ + "markerId": item.hash.hashValue, + "latitude": item.position.latitude, + "longitude": item.position.longitude, + "title": item.title ?? "", + "snippet": item.snippet ?? "" + ]) + } + + self.notifyListeners("onClusterClick", data: [ + "mapId": self.findMapIdByMapView(mapView), + "latitude": cluster.position.latitude, + "longitude": cluster.position.longitude, + "size": cluster.count, + "items": items + ]) + } else { + self.notifyListeners("onMarkerClick", data: [ + "mapId": self.findMapIdByMapView(mapView), + "markerId": marker.hash.hashValue, + "latitude": marker.position.latitude, + "longitude": marker.position.longitude, + "title": marker.title ?? "", + "snippet": marker.snippet ?? "" + ]) + } + return false + } + + // onMarkerDragStart + public func mapView(_ mapView: GMSMapView, didBeginDragging marker: GMSMarker) { + self.notifyListeners("onMarkerDragStart", data: [ + "mapId": self.findMapIdByMapView(mapView), + "markerId": marker.hash.hashValue, + "latitude": marker.position.latitude, + "longitude": marker.position.longitude, + "title": marker.title ?? "", + "snippet": marker.snippet ?? "" + ]) + } + + // onMarkerDrag + public func mapView(_ mapView: GMSMapView, didDrag marker: GMSMarker) { + self.notifyListeners("onMarkerDrag", data: [ + "mapId": self.findMapIdByMapView(mapView), + "markerId": marker.hash.hashValue, + "latitude": marker.position.latitude, + "longitude": marker.position.longitude, + "title": marker.title ?? "", + "snippet": marker.snippet ?? "" + ]) + } + + // onMarkerDragEnd + public func mapView(_ mapView: GMSMapView, didEndDragging marker: GMSMarker) { + self.notifyListeners("onMarkerDragEnd", data: [ + "mapId": self.findMapIdByMapView(mapView), + "markerId": marker.hash.hashValue, + "latitude": marker.position.latitude, + "longitude": marker.position.longitude, + "title": marker.title ?? "", + "snippet": marker.snippet ?? "" + ]) + } + + // onClusterInfoWindowClick, onInfoWindowClick + public func mapView(_ mapView: GMSMapView, didTapInfoWindowOf marker: GMSMarker) { + if let cluster = marker.userData as? GMUCluster { + var items: [[String: Any?]] = [] + + for item in cluster.items { + items.append([ + "markerId": item.hash.hashValue, + "latitude": item.position.latitude, + "longitude": item.position.longitude, + "title": item.title ?? "", + "snippet": item.snippet ?? "" + ]) + } + + self.notifyListeners("onClusterInfoWindowClick", data: [ + "mapId": self.findMapIdByMapView(mapView), + "latitude": cluster.position.latitude, + "longitude": cluster.position.longitude, + "size": cluster.count, + "items": items + ]) + } else { + self.notifyListeners("onInfoWindowClick", data: [ + "mapId": self.findMapIdByMapView(mapView), + "markerId": marker.hash.hashValue, + "latitude": marker.position.latitude, + "longitude": marker.position.longitude, + "title": marker.title ?? "", + "snippet": marker.snippet ?? "" + ]) + } + } + + // onMyLocationButtonClick + public func didTapMyLocationButtonForMapView(for mapView: GMSMapView) -> Bool { + self.notifyListeners("onMyLocationButtonClick", data: [ + "mapId": self.findMapIdByMapView(mapView) + ]) + return false + } + + // onMyLocationClick + public func mapView(_ mapView: GMSMapView, didTapMyLocation location: CLLocationCoordinate2D) { + self.notifyListeners("onMyLocationButtonClick", data: [ + "mapId": self.findMapIdByMapView(mapView), + "latitude": location.latitude, + "longitude": location.longitude + ]) + } +} diff --git a/google-maps/ios/Plugin/GoogleMapCameraConfig.swift b/google-maps/ios/Plugin/GoogleMapCameraConfig.swift new file mode 100644 index 000000000..fd337758d --- /dev/null +++ b/google-maps/ios/Plugin/GoogleMapCameraConfig.swift @@ -0,0 +1,29 @@ +import Foundation +import Capacitor + +public struct GoogleMapCameraConfig { + let coordinate: LatLng? + let zoom: Float? + let bearing: Double? + let angle: Double? + let animate: Bool? + let animationDuration: Double? + + init(fromJSObject: JSObject) throws { + zoom = fromJSObject["zoom"] as? Float + bearing = fromJSObject["bearing"] as? Double + angle = fromJSObject["angle"] as? Double + animate = fromJSObject["animate"] as? Bool + animationDuration = fromJSObject["animationDuration"] as? Double + + if let latLngObj = fromJSObject["coordinate"] as? JSObject { + guard let lat = latLngObj["lat"] as? Double, let lng = latLngObj["lng"] as? Double else { + throw GoogleMapErrors.invalidArguments("LatLng object is missing the required 'lat' and/or 'lng' property") + } + + self.coordinate = LatLng(lat: lat, lng: lng) + } else { + self.coordinate = nil + } + } +} diff --git a/google-maps/ios/Plugin/GoogleMapConfig.swift b/google-maps/ios/Plugin/GoogleMapConfig.swift new file mode 100644 index 000000000..4905b18e3 --- /dev/null +++ b/google-maps/ios/Plugin/GoogleMapConfig.swift @@ -0,0 +1,54 @@ +import Foundation +import Capacitor + +public struct GoogleMapConfig: Codable { + let width: Double + let height: Double + let x: Double + let y: Double + let center: LatLng + let zoom: Double + let styles: String? + + init(fromJSObject: JSObject) throws { + guard let width = fromJSObject["width"] as? Double else { + throw GoogleMapErrors.invalidArguments("GoogleMapConfig object is missing the required 'width' property") + } + + guard let height = fromJSObject["height"] as? Double else { + throw GoogleMapErrors.invalidArguments("GoogleMapConfig object is missing the required 'height' property") + } + + guard let x = fromJSObject["x"] as? Double else { + throw GoogleMapErrors.invalidArguments("GoogleMapConfig object is missing the required 'x' property") + } + + guard let y = fromJSObject["y"] as? Double else { + throw GoogleMapErrors.invalidArguments("GoogleMapConfig object is missing the required 'y' property") + } + + guard let zoom = fromJSObject["zoom"] as? Double else { + throw GoogleMapErrors.invalidArguments("GoogleMapConfig object is missing the required 'zoom' property") + } + + guard let latLngObj = fromJSObject["center"] as? JSObject else { + throw GoogleMapErrors.invalidArguments("GoogleMapConfig object is missing the required 'center' property") + } + + guard let lat = latLngObj["lat"] as? Double, let lng = latLngObj["lng"] as? Double else { + throw GoogleMapErrors.invalidArguments("LatLng object is missing the required 'lat' and/or 'lng' property") + } + + self.width = round(width) + self.height = round(height) + self.x = x + self.y = y + self.zoom = zoom + self.center = LatLng(lat: lat, lng: lng) + if let stylesArray = fromJSObject["styles"] as? JSArray, let jsonData = try? JSONSerialization.data(withJSONObject: stylesArray, options: []) { + self.styles = String(data: jsonData, encoding: .utf8) + } else { + self.styles = nil + } + } +} diff --git a/google-maps/ios/Plugin/GoogleMapErrors.swift b/google-maps/ios/Plugin/GoogleMapErrors.swift new file mode 100644 index 000000000..07aa7656a --- /dev/null +++ b/google-maps/ios/Plugin/GoogleMapErrors.swift @@ -0,0 +1,47 @@ +import Foundation + +public enum GoogleMapErrors: Error { + case invalidMapId + case mapNotFound + case markerNotFound + case invalidArguments(_ description: String) + case invalidAPIKey + case permissionsDeniedLocation + case unhandledError(_ description: String) +} + +public struct GoogleMapErrorObject { + let extra: [String: Any]? + let code: Int + let message: String + init(_ code: Int, _ message: String, _ extra: [String: Any]? = nil) { + self.code = code + self.message = message + self.extra = extra + } + + var asDictionary: [String: Any] { + return ["code": code, "message": message, "extra": extra ?? []] + } +} + +public func getErrorObject(_ error: Error) -> GoogleMapErrorObject { + switch error { + case GoogleMapErrors.invalidMapId: + return GoogleMapErrorObject(1, "Missing or invalid map id.") + case GoogleMapErrors.mapNotFound: + return GoogleMapErrorObject(2, "Map not found for provided id.") + case GoogleMapErrors.markerNotFound: + return GoogleMapErrorObject(3, "Marker not found for provided id.") + case GoogleMapErrors.invalidArguments(let msg): + return GoogleMapErrorObject(4, "Invalid Arguments Provided: \(msg)") + case GoogleMapErrors.permissionsDeniedLocation: + return GoogleMapErrorObject(5, "Permissions denied for accessing device location.") + case GoogleMapErrors.invalidAPIKey: + return GoogleMapErrorObject(6, "Missing or invalid Google Maps SDK API key.") + case GoogleMapErrors.unhandledError(let msg): + return GoogleMapErrorObject(0, "Unhandled Error: \(msg)") + default: + return GoogleMapErrorObject(0, "Unhandled Error: \(error.localizedDescription)") + } +} diff --git a/google-maps/ios/Plugin/GoogleMapPadding.swift b/google-maps/ios/Plugin/GoogleMapPadding.swift new file mode 100644 index 000000000..15953566f --- /dev/null +++ b/google-maps/ios/Plugin/GoogleMapPadding.swift @@ -0,0 +1,16 @@ +import Foundation +import Capacitor + +public struct GoogleMapPadding { + let top: Float + let bottom: Float + let left: Float + let right: Float + + init(fromJSObject: JSObject) throws { + top = fromJSObject["top"] as? Float ?? 0 + bottom = fromJSObject["bottom"] as? Float ?? 0 + left = fromJSObject["left"] as? Float ?? 0 + right = fromJSObject["right"] as? Float ?? 0 + } +} diff --git a/storage/ios/Plugin/Info.plist b/google-maps/ios/Plugin/Info.plist similarity index 100% rename from storage/ios/Plugin/Info.plist rename to google-maps/ios/Plugin/Info.plist diff --git a/google-maps/ios/Plugin/Map.swift b/google-maps/ios/Plugin/Map.swift new file mode 100644 index 000000000..a967769d1 --- /dev/null +++ b/google-maps/ios/Plugin/Map.swift @@ -0,0 +1,483 @@ +import Foundation +import GoogleMaps +import Capacitor +import GoogleMapsUtils + +public struct LatLng: Codable { + let lat: Double + let lng: Double +} + +class GMViewController: UIViewController { + var mapViewBounds: [String: Double]! + var GMapView: GMSMapView! + var cameraPosition: [String: Double]! + + private var clusterManager: GMUClusterManager? + + var clusteringEnabled: Bool { + return clusterManager != nil + } + + override func viewDidLoad() { + super.viewDidLoad() + + let camera = GMSCameraPosition.camera(withLatitude: cameraPosition["latitude"] ?? 0, longitude: cameraPosition["longitude"] ?? 0, zoom: Float(cameraPosition["zoom"] ?? 12)) + let frame = CGRect(x: mapViewBounds["x"] ?? 0, y: mapViewBounds["y"] ?? 0, width: mapViewBounds["width"] ?? 0, height: mapViewBounds["height"] ?? 0) + self.GMapView = GMSMapView.map(withFrame: frame, camera: camera) + self.view = GMapView + } + + func initClusterManager() { + let iconGenerator = GMUDefaultClusterIconGenerator() + let algorithm = GMUNonHierarchicalDistanceBasedAlgorithm() + let renderer = GMUDefaultClusterRenderer(mapView: self.GMapView, clusterIconGenerator: iconGenerator) + + self.clusterManager = GMUClusterManager(map: self.GMapView, algorithm: algorithm, renderer: renderer) + } + + func destroyClusterManager() { + self.clusterManager = nil + } + + func addMarkersToCluster(markers: [GMSMarker]) { + if let clusterManager = clusterManager { + clusterManager.add(markers) + clusterManager.cluster() + } + } + + func removeMarkersFromCluster(markers: [GMSMarker]) { + if let clusterManager = clusterManager { + markers.forEach { marker in + clusterManager.remove(marker) + } + clusterManager.cluster() + } + } +} + +public class Map { + var id: String + var config: GoogleMapConfig + var mapViewController: GMViewController + var targetViewController: UIView? + var markers = [Int: GMSMarker]() + var markerIcons = [String: UIImage]() + + // swiftlint:disable weak_delegate + private var delegate: CapacitorGoogleMapsPlugin + + init(id: String, config: GoogleMapConfig, delegate: CapacitorGoogleMapsPlugin) { + self.id = id + self.config = config + self.delegate = delegate + self.mapViewController = GMViewController() + + self.render() + } + + func render() { + DispatchQueue.main.async { + self.mapViewController.mapViewBounds = [ + "width": self.config.width, + "height": self.config.height, + "x": self.config.x, + "y": self.config.y + ] + + self.mapViewController.cameraPosition = [ + "latitude": self.config.center.lat, + "longitude": self.config.center.lng, + "zoom": self.config.zoom + ] + if let bridge = self.delegate.bridge { + + for item in bridge.webView!.getAllSubViews() { + let isScrollView = item.isKind(of: NSClassFromString("WKChildScrollView")!) || item.isKind(of: NSClassFromString("WKScrollView")!) + if isScrollView { + (item as? UIScrollView)?.isScrollEnabled = true + + let isWidthEqual = round(Double(item.bounds.width)) == self.config.width + let isHeightEqual = round(Double(item.bounds.height)) == self.config.height + + if isWidthEqual && isHeightEqual && (item as? UIView)?.tag == 0 { + self.targetViewController = item + break + } + } + } + + if let target = self.targetViewController { + target.tag = 1 + target.removeAllSubview() + self.mapViewController.view.frame = target.bounds + target.addSubview(self.mapViewController.view) + self.mapViewController.GMapView.delegate = self.delegate + } + + if let styles = self.config.styles { + do { + self.mapViewController.GMapView.mapStyle = try GMSMapStyle(jsonString: styles) + } catch { + CAPLog.print("Invalid Google Maps styles") + } + } + + self.delegate.notifyListeners("onMapReady", data: [ + "mapId": self.id + ]) + } + } + } + + func updateRender(frame: CGRect, mapBounds: CGRect) { + DispatchQueue.main.async { + self.mapViewController.view.layer.mask = nil + + var updatedFrame = self.mapViewController.view.frame + updatedFrame.origin.x = mapBounds.origin.x + updatedFrame.origin.y = mapBounds.origin.y + + self.mapViewController.view.frame = updatedFrame + + var maskBounds: [CGRect] = [] + + if !frame.contains(mapBounds) { + maskBounds.append(contentsOf: self.getFrameOverflowBounds(frame: frame, mapBounds: mapBounds)) + } + + if maskBounds.count > 0 { + let maskLayer = CAShapeLayer() + let path = CGMutablePath() + + path.addRect(self.mapViewController.view.bounds) + maskBounds.forEach { b in + path.addRect(b) + } + + maskLayer.path = path + maskLayer.fillRule = .evenOdd + + self.mapViewController.view.layer.mask = maskLayer + + } + + self.mapViewController.view.layoutIfNeeded() + } + + } + + func destroy() { + DispatchQueue.main.async { + self.targetViewController?.tag = 0 + self.mapViewController.view = nil + + } + } + + func addMarker(marker: Marker) throws -> Int { + var markerHash = 0 + + DispatchQueue.main.sync { + let newMarker = self.buildMarker(marker: marker) + + if self.mapViewController.clusteringEnabled { + self.mapViewController.addMarkersToCluster(markers: [newMarker]) + } else { + newMarker.map = self.mapViewController.GMapView + } + + self.markers[newMarker.hash.hashValue] = newMarker + + markerHash = newMarker.hash.hashValue + } + + return markerHash + } + + func addMarkers(markers: [Marker]) throws -> [Int] { + var markerHashes: [Int] = [] + + DispatchQueue.main.sync { + var googleMapsMarkers: [GMSMarker] = [] + + markers.forEach { marker in + let newMarker = self.buildMarker(marker: marker) + + if self.mapViewController.clusteringEnabled { + googleMapsMarkers.append(newMarker) + } else { + newMarker.map = self.mapViewController.GMapView + } + + self.markers[newMarker.hash.hashValue] = newMarker + + markerHashes.append(newMarker.hash.hashValue) + } + + if self.mapViewController.clusteringEnabled { + self.mapViewController.addMarkersToCluster(markers: googleMapsMarkers) + } + } + + return markerHashes + } + + func enableClustering() { + if !self.mapViewController.clusteringEnabled { + DispatchQueue.main.sync { + self.mapViewController.initClusterManager() + + // add existing markers to the cluster + if !self.markers.isEmpty { + var existingMarkers: [GMSMarker] = [] + for (_, marker) in self.markers { + marker.map = nil + existingMarkers.append(marker) + } + + self.mapViewController.addMarkersToCluster(markers: existingMarkers) + } + } + } + } + + func disableClustering() { + DispatchQueue.main.sync { + self.mapViewController.destroyClusterManager() + + // add existing markers back to the map + if !self.markers.isEmpty { + for (_, marker) in self.markers { + marker.map = self.mapViewController.GMapView + } + } + } + } + + func removeMarker(id: Int) throws { + if let marker = self.markers[id] { + DispatchQueue.main.async { + if self.mapViewController.clusteringEnabled { + self.mapViewController.removeMarkersFromCluster(markers: [marker]) + } + + marker.map = nil + self.markers.removeValue(forKey: id) + + } + } else { + throw GoogleMapErrors.markerNotFound + } + } + + func setCamera(config: GoogleMapCameraConfig) throws { + let currentCamera = self.mapViewController.GMapView.camera + + let lat = config.coordinate?.lat ?? currentCamera.target.latitude + let lng = config.coordinate?.lng ?? currentCamera.target.longitude + + let zoom = config.zoom ?? currentCamera.zoom + let bearing = config.bearing ?? Double(currentCamera.bearing) + let angle = config.angle ?? currentCamera.viewingAngle + + let animate = config.animate ?? false + + DispatchQueue.main.sync { + let newCamera = GMSCameraPosition(latitude: lat, longitude: lng, zoom: zoom, bearing: bearing, viewingAngle: angle) + + if animate { + self.mapViewController.GMapView.animate(to: newCamera) + } else { + self.mapViewController.GMapView.camera = newCamera + } + } + + } + + func setMapType(mapType: GMSMapViewType) throws { + DispatchQueue.main.sync { + self.mapViewController.GMapView.mapType = mapType + } + } + + func enableIndoorMaps(enabled: Bool) throws { + DispatchQueue.main.sync { + self.mapViewController.GMapView.isIndoorEnabled = enabled + } + } + + func enableTrafficLayer(enabled: Bool) throws { + DispatchQueue.main.sync { + self.mapViewController.GMapView.isTrafficEnabled = enabled + } + } + + func enableAccessibilityElements(enabled: Bool) throws { + DispatchQueue.main.sync { + self.mapViewController.GMapView.accessibilityElementsHidden = enabled + } + } + + func enableCurrentLocation(enabled: Bool) throws { + DispatchQueue.main.sync { + self.mapViewController.GMapView.isMyLocationEnabled = enabled + } + } + + func setPadding(padding: GoogleMapPadding) throws { + DispatchQueue.main.sync { + let mapInsets = UIEdgeInsets(top: CGFloat(padding.top), left: CGFloat(padding.left), bottom: CGFloat(padding.bottom), right: CGFloat(padding.right)) + self.mapViewController.GMapView.padding = mapInsets + } + } + + func removeMarkers(ids: [Int]) throws { + DispatchQueue.main.sync { + var markers: [GMSMarker] = [] + ids.forEach { id in + if let marker = self.markers[id] { + marker.map = nil + self.markers.removeValue(forKey: id) + markers.append(marker) + } + } + + if self.mapViewController.clusteringEnabled { + self.mapViewController.removeMarkersFromCluster(markers: markers) + } + } + } + + func getMapLatLngBounds() -> GMSCoordinateBounds? { + return GMSCoordinateBounds(region: self.mapViewController.GMapView.projection.visibleRegion()) + } + + private func getFrameOverflowBounds(frame: CGRect, mapBounds: CGRect) -> [CGRect] { + var intersections: [CGRect] = [] + + // get top overflow + if mapBounds.origin.y < frame.origin.y { + let height = frame.origin.y - mapBounds.origin.y + let width = mapBounds.width + intersections.append(CGRect(x: 0, y: 0, width: width, height: height)) + } + + // get bottom overflow + if (mapBounds.origin.y + mapBounds.height) > (frame.origin.y + frame.height) { + let height = (mapBounds.origin.y + mapBounds.height) - (frame.origin.y + frame.height) + let width = mapBounds.width + intersections.append(CGRect(x: 0, y: mapBounds.height, width: width, height: height)) + } + + return intersections + } + + private func buildMarker(marker: Marker) -> GMSMarker { + let newMarker = GMSMarker() + newMarker.position = CLLocationCoordinate2D(latitude: marker.coordinate.lat, longitude: marker.coordinate.lng) + newMarker.title = marker.title + newMarker.snippet = marker.snippet + newMarker.isFlat = marker.isFlat ?? false + newMarker.opacity = marker.opacity ?? 1 + newMarker.isDraggable = marker.draggable ?? false + if let iconAnchor = marker.iconAnchor { + newMarker.groundAnchor = iconAnchor + } + + // cache and reuse marker icon uiimages + if let iconUrl = marker.iconUrl { + if let iconImage = self.markerIcons[iconUrl] { + newMarker.icon = getResizedIcon(iconImage, marker) + } else { + if iconUrl.starts(with: "https:") { + DispatchQueue.main.async { + if let url = URL(string: iconUrl), let data = try? Data(contentsOf: url), let iconImage = UIImage(data: data) { + self.markerIcons[iconUrl] = iconImage + newMarker.icon = getResizedIcon(iconImage, marker) + } + } + } else if let iconImage = UIImage(named: "public/\(iconUrl)") { + self.markerIcons[iconUrl] = iconImage + newMarker.icon = getResizedIcon(iconImage, marker) + } else { + var detailedMessage = "" + + if iconUrl.hasSuffix(".svg") { + detailedMessage = "SVG not supported." + } + + print("CapacitorGoogleMaps Warning: could not load image '\(iconUrl)'. \(detailedMessage) Using default marker icon.") + } + } + } else { + if let color = marker.color { + newMarker.icon = GMSMarker.markerImage(with: color) + } + } + + return newMarker + } +} + +private func getResizedIcon(_ iconImage: UIImage, _ marker: Marker) -> UIImage? { + if let iconSize = marker.iconSize { + return iconImage.resizeImageTo(size: iconSize) + } else { + return iconImage + } +} + +extension WKWebView { + override open func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { + var hitView = super.hitTest(point, with: event) + + if let typeClass = NSClassFromString("WKChildScrollView"), let tempHitView = hitView, tempHitView.isKind(of: typeClass) { + for item in tempHitView.subviews.reversed() { + let convertPoint = item.convert(point, from: self) + if let hitTestView = item.hitTest(convertPoint, with: event) { + hitView = hitTestView + break + } + } + } + + return hitView + } +} + +extension UIView { + private static var allSubviews: [UIView] = [] + + private func viewArray(root: UIView) -> [UIView] { + for view in root.subviews { + if view.isKind(of: UIView.self) { + UIView.allSubviews.append(view) + } + _ = viewArray(root: view) + } + return UIView.allSubviews + } + + fileprivate func getAllSubViews() -> [UIView] { + UIView.allSubviews = [] + return viewArray(root: self) + } + + fileprivate func removeAllSubview() { + subviews.forEach { + $0.removeFromSuperview() + } + } +} + +extension UIImage { + func resizeImageTo(size: CGSize) -> UIImage? { + UIGraphicsBeginImageContextWithOptions(size, false, 0.0) + self.draw(in: CGRect(origin: CGPoint.zero, size: size)) + let resizedImage = UIGraphicsGetImageFromCurrentImageContext()! + UIGraphicsEndImageContext() + return resizedImage + } +} diff --git a/google-maps/ios/Plugin/Marker.swift b/google-maps/ios/Plugin/Marker.swift new file mode 100644 index 000000000..de1df85b7 --- /dev/null +++ b/google-maps/ios/Plugin/Marker.swift @@ -0,0 +1,78 @@ +import Foundation +import Capacitor + +public struct Marker { + let coordinate: LatLng + let opacity: Float? + let title: String? + let snippet: String? + let isFlat: Bool? + let iconUrl: String? + let iconSize: CGSize? + let iconAnchor: CGPoint? + let draggable: Bool? + let color: UIColor? + + init(fromJSObject: JSObject) throws { + guard let latLngObj = fromJSObject["coordinate"] as? JSObject else { + throw GoogleMapErrors.invalidArguments("Marker object is missing the required 'coordinate' property") + } + + guard let lat = latLngObj["lat"] as? Double, let lng = latLngObj["lng"] as? Double else { + throw GoogleMapErrors.invalidArguments("LatLng object is missing the required 'lat' and/or 'lng' property") + } + + var iconSize: CGSize? + if let sizeObj = fromJSObject["iconSize"] as? JSObject { + if let width = sizeObj["width"] as? Double, let height = sizeObj["height"] as? Double { + iconSize = CGSize(width: width, height: height) + } + } + + var iconAnchor: CGPoint? + if let anchorObject = fromJSObject["iconAnchor"] as? JSObject { + if let x = anchorObject["x"] as? Double, let y = anchorObject["y"] as? Double { + if let size = iconSize { + let u = x / size.width + let v = y / size.height + + iconAnchor = CGPoint(x: u, y: v) + } + } + } + + var tintColor: UIColor? + if let rgbObject = fromJSObject["tintColor"] as? JSObject { + if let r = rgbObject["r"] as? Double, let g = rgbObject["g"] as? Double, let b = rgbObject["b"] as? Double, let a = rgbObject["a"] as? Double { + + let uiColorR = CGFloat(r / 255).clamp(min: 0, max: 255) + let uiColorG = CGFloat(g / 255).clamp(min: 0, max: 255) + let uiColorB = CGFloat(b / 255).clamp(min: 0, max: 255) + tintColor = UIColor(red: uiColorR, green: uiColorG, blue: uiColorB, alpha: CGFloat(a)) + } + } + + self.coordinate = LatLng(lat: lat, lng: lng) + self.opacity = fromJSObject["opacity"] as? Float + self.title = fromJSObject["title"] as? String + self.snippet = fromJSObject["snippet"] as? String + self.isFlat = fromJSObject["isFlat"] as? Bool + self.iconUrl = fromJSObject["iconUrl"] as? String + self.draggable = fromJSObject["draggable"] as? Bool + self.iconSize = iconSize + self.iconAnchor = iconAnchor + self.color = tintColor + } +} + +extension CGFloat { + func clamp(min: CGFloat, max: CGFloat) -> CGFloat { + if self < min { + return min + } + if self > max { + return max + } + return self + } +} diff --git a/google-maps/ios/PluginTests/CapacitorGoogleMapsTests.swift b/google-maps/ios/PluginTests/CapacitorGoogleMapsTests.swift new file mode 100644 index 000000000..c4643e5d7 --- /dev/null +++ b/google-maps/ios/PluginTests/CapacitorGoogleMapsTests.swift @@ -0,0 +1,25 @@ +import XCTest +@testable import Plugin + +class CapacitorGoogleMapsTests: XCTestCase { + override func setUp() { + super.setUp() + // Put setup code here. This method is called before the invocation of each test method in the class. + } + + override func tearDown() { + // Put teardown code here. This method is called after the invocation of each test method in the class. + super.tearDown() + } + + func testEcho() { + // This is an example of a functional test case for a plugin. + // Use XCTAssert and related functions to verify your tests produce the correct results. + + let implementation = CapacitorGoogleMaps() + let value = "Hello, World!" + let result = implementation.echo(value) + + XCTAssertEqual(value, result) + } +} diff --git a/storage/ios/PluginTests/Info.plist b/google-maps/ios/PluginTests/Info.plist similarity index 100% rename from storage/ios/PluginTests/Info.plist rename to google-maps/ios/PluginTests/Info.plist diff --git a/google-maps/ios/Podfile b/google-maps/ios/Podfile new file mode 100644 index 000000000..e42042377 --- /dev/null +++ b/google-maps/ios/Podfile @@ -0,0 +1,20 @@ +platform :ios, '13.0' + +def capacitor_pods + # Comment the next line if you're not using Swift and don't want to use dynamic frameworks + use_frameworks! + pod 'Capacitor', :path => '../node_modules/@capacitor/ios' + pod 'CapacitorCordova', :path => '../node_modules/@capacitor/ios' +end + +target 'Plugin' do + capacitor_pods + pod 'GoogleMaps' + pod 'Google-Maps-iOS-Utils' +end + +target 'PluginTests' do + capacitor_pods + pod 'GoogleMaps' + pod 'Google-Maps-iOS-Utils' +end diff --git a/google-maps/package.json b/google-maps/package.json new file mode 100644 index 000000000..94beff7cd --- /dev/null +++ b/google-maps/package.json @@ -0,0 +1,100 @@ +{ + "name": "@capacitor/google-maps", + "version": "4.3.1", + "description": "Google maps on Capacitor", + "main": "dist/plugin.cjs.js", + "module": "dist/esm/index.js", + "typings": "dist/typings/index.d.ts", + "typesVersions": { + "<4.1": { + "dist/typings/index.d.ts": [ + "dist/typings/ts_old/index.d.ts" + ] + } + }, + "unpkg": "dist/plugin.js", + "files": [ + "android/src/main/", + "android/build.gradle", + "dist/", + "ios/Plugin/", + "CapacitorGoogleMaps.podspec" + ], + "author": "Ionic ", + "license": "MIT", + "repository": { + "type": "git", + "url": "git+https://github.com/ionic-team/capacitor-plugins.git" + }, + "bugs": { + "url": "https://github.com/ionic-team/capacitor-plugins/issues" + }, + "keywords": [ + "capacitor", + "plugin", + "native" + ], + "scripts": { + "verify": "npm run verify:ios && npm run verify:android && npm run verify:web", + "verify:ios": "cd ios && pod install && xcodebuild -workspace Plugin.xcworkspace -scheme Plugin -sdk iphonesimulator && cd ..", + "verify:android": "cd android && ./gradlew clean build test && cd ..", + "verify:web": "npm run build", + "lint": "npm run eslint && npm run prettier -- --check && npm run swiftlint -- lint", + "fmt": "npm run eslint -- --fix && npm run prettier -- --write && npm run swiftlint -- --fix --format", + "eslint": "eslint . --ext ts", + "prettier": "prettier \"**/*.{css,html,ts,js,java}\"", + "swiftlint": "node-swiftlint", + "docgen": "docgen --api GoogleMapInterface --output-readme README.md --output-json dist/docs.json", + "build": "npm run clean && npm run docgen && tsc && rollup -c rollup.config.js && npm run downlevel-dts", + "clean": "rimraf ./dist", + "watch": "tsc --watch", + "prepublishOnly": "npm run build", + "publish:cocoapod": "pod trunk push ./CapacitorGoogleMaps.podspec --allow-warnings", + "downlevel-dts": "npx downlevel-dts dist/typings dist/typings/ts_old --to=3.5", + "pack-local": "npm run build && npm pack && find . -name 'capacitor-google-maps-*tgz' -exec bash -c 'mv $0 capacitor-google-maps.tgz' {} \\; ", + "unittest:ios": "xcodebuild test -project ./unit-tests/ios/GoogleMapsPlugin/GoogleMapsPlugin.xcodeproj -scheme TestApp -destination 'platform=iOS Simulator,name=iPhone 12,OS=15.2' | xcpretty && exit ${PIPESTATUS[0]}", + "unittest:android": "cd ./unit-tests/android && ./gradlew testDebugUnitTest" + }, + "devDependencies": { + "@capacitor/android": "^4.0.1", + "@capacitor/core": "^4.0.1", + "@capacitor/docgen": "0.2.0", + "@capacitor/ios": "^4.0.1", + "@ionic/eslint-config": "^0.3.0", + "@ionic/prettier-config": "^1.0.1", + "@ionic/swiftlint-config": "^1.1.2", + "@types/supercluster": "^7.1.0", + "downlevel-dts": "^0.7.0", + "eslint": "^7.11.0", + "eslint-plugin-import": "^2.25.4", + "prettier": "~2.3.0", + "prettier-plugin-java": "~1.0.2", + "rimraf": "^3.0.2", + "rollup": "^2.32.0", + "swiftlint": "^1.0.1", + "typescript": "~4.1.5" + }, + "peerDependencies": { + "@capacitor/core": "^4.0.1" + }, + "prettier": "@ionic/prettier-config", + "eslintConfig": { + "extends": "@ionic/eslint-config/recommended" + }, + "capacitor": { + "ios": { + "src": "ios" + }, + "android": { + "src": "android" + } + }, + "publishConfig": { + "access": "public" + }, + "dependencies": { + "@googlemaps/js-api-loader": "^1.13.7", + "@googlemaps/markerclusterer": "^2.0.7", + "@types/google.maps": "^3.50.5" + } +} diff --git a/google-maps/rollup.config.js b/google-maps/rollup.config.js new file mode 100644 index 000000000..07b8e87a1 --- /dev/null +++ b/google-maps/rollup.config.js @@ -0,0 +1,26 @@ +export default { + input: 'dist/esm/index.js', + output: [ + { + file: 'dist/plugin.js', + format: 'iife', + name: 'capacitorCapacitorGoogleMaps', + globals: { + '@capacitor/core': 'capacitorExports', + }, + sourcemap: true, + inlineDynamicImports: true, + }, + { + file: 'dist/plugin.cjs.js', + format: 'cjs', + sourcemap: true, + inlineDynamicImports: true, + }, + ], + external: [ + '@capacitor/core', + '@googlemaps/js-api-loader', + '@googlemaps/markerclusterer', + ], +}; diff --git a/google-maps/src/definitions.ts b/google-maps/src/definitions.ts new file mode 100644 index 000000000..7b9cdcfc6 --- /dev/null +++ b/google-maps/src/definitions.ts @@ -0,0 +1,297 @@ +/** + * An interface representing the viewports latitude and longitude bounds. + */ +export interface LatLngBounds { + southwest: LatLng; + center: LatLng; + northeast: LatLng; +} + +/** + * An interface representing a pair of latitude and longitude coordinates. + */ +export interface LatLng { + /** + * Coordinate latitude, in degrees. This value is in the range [-90, 90]. + */ + lat: number; + + /** + * Coordinate longitude, in degrees. This value is in the range [-180, 180]. + */ + lng: number; +} + +export interface Size { + width: number; + height: number; +} + +export interface Point { + x: number; + y: number; +} + +/** + * For web, all the javascript Google Maps options are available as + * GoogleMapConfig extends google.maps.MapOptions. + * For iOS and Android only the config options declared on GoogleMapConfig are available. + */ +export interface GoogleMapConfig extends google.maps.MapOptions { + /** + * Override width for native map. + */ + width?: number; + /** + * Override height for native map. + */ + height?: number; + /** + * Override absolute x coordinate position for native map. + */ + x?: number; + /** + * Override absolute y coordinate position for native map. + */ + y?: number; + /** + * Default location on the Earth towards which the camera points. + */ + center: LatLng; + /** + * Sets the zoom of the map. + */ + zoom: number; + /** + * Enables image-based lite mode on Android. + * + * @default false + */ + androidLiteMode?: boolean; + /** + * Override pixel ratio for native map. + */ + devicePixelRatio?: number; + /** + * Styles to apply to each of the default map types. Note that for + * satellite, hybrid and terrain modes, + * these styles will only apply to labels and geometry. + * + * @since 4.3.0 + */ + styles?: google.maps.MapTypeStyle[] | null; +} + +/** + * Configuration properties for a Google Map Camera + */ +export interface CameraConfig { + /** + * Location on the Earth towards which the camera points. + */ + coordinate?: LatLng; + /** + * Sets the zoom of the map. + */ + zoom?: number; + /** + * Bearing of the camera, in degrees clockwise from true north. + * + * @default 0 + */ + bearing?: number; + /** + * The angle, in degrees, of the camera from the nadir (directly facing the Earth). + * + * The only allowed values are 0 and 45. + * + * @default 0 + */ + angle?: number; + /** + * Animate the transition to the new Camera properties. + * + * @default false + */ + animate?: boolean; + + /** + * + */ + animationDuration?: number; +} + +export enum MapType { + /** + * Basic map. + */ + Normal = 'Normal', + /** + * Satellite imagery with roads and labels. + */ + Hybrid = 'Hybrid', + /** + * Satellite imagery with no labels. + */ + Satellite = 'Satellite', + /** + * Topographic data. + */ + Terrain = 'Terrain', + /** + * No base map tiles. + */ + None = 'None', +} + +/** + * Controls for setting padding on the 'visible' region of the view. + */ +export interface MapPadding { + top: number; + left: number; + right: number; + bottom: number; +} + +/** + * A marker is an icon placed at a particular point on the map's surface. + */ +export interface Marker { + /** + * Marker position + */ + coordinate: LatLng; + /** + * Sets the opacity of the marker, between 0 (completely transparent) and 1 inclusive. + * + * @default 1 + */ + opacity?: number; + /** + * Title, a short description of the overlay. + */ + title?: string; + /** + * Snippet text, shown beneath the title in the info window when selected. + */ + snippet?: string; + /** + * Controls whether this marker should be flat against the Earth's surface or a billboard facing the camera. + * + * @default false + */ + isFlat?: boolean; + /** + * Path to a marker icon to render. It can be relative to the web app public directory, + * or a https url of a remote marker icon. + * + * **SVGs are not supported on native platforms.** + * + * @usage + * ```typescript + * { + * ... + * iconUrl: 'assets/icon/pin.png', + * ... + * } + * ``` + * + * @since 4.2.0 + */ + iconUrl?: string; + /** + * Controls the scaled size of the marker image set in `iconUrl`. + * + * @since 4.2.0 + */ + iconSize?: Size; + + /** + * The position of the image within a sprite, if any. By default, the origin is located at the top left corner of the image . + * + * @since 4.2.0 + */ + iconOrigin?: Point; + + /** + * The position at which to anchor an image in correspondence to the location of the marker on the map. By default, the anchor is located along the center point of the bottom of the image. + * + * @since 4.2.0 + */ + iconAnchor?: Point; + /** + * Customizes the color of the default marker image. Each value must be between 0 and 255. + * + * Only for iOS and Android. + * + * @since 4.2.0 + */ + tintColor?: { + r: number; + g: number; + b: number; + a: number; + }; + + /** + * Controls whether this marker can be dragged interactively + * + * @default false + */ + draggable?: boolean; +} + +/** + * The callback function to be called when map events are emitted. + */ +export type MapListenerCallback = (data: T) => void; + +export interface MapReadyCallbackData { + mapId: string; +} + +export interface MarkerCallbackData { + markerId: string; + latitude: number; + longitude: number; + title: string; + snippet: string; +} + +export interface CameraIdleCallbackData { + mapId: string; + bounds: LatLngBounds; + bearing: number; + latitude: number; + longitude: number; + tilt: number; + zoom: number; +} + +export interface CameraMoveStartedCallbackData { + mapId: string; + isGesture: boolean; +} + +export interface ClusterClickCallbackData { + mapId: string; + latitude: number; + longitude: number; + size: number; + items: MarkerCallbackData[]; +} + +export interface MapClickCallbackData { + mapId: string; + latitude: number; + longitude: number; +} + +export interface MarkerClickCallbackData extends MarkerCallbackData { + mapId: string; +} + +export interface MyLocationButtonClickCallbackData { + mapId: string; +} diff --git a/google-maps/src/implementation.ts b/google-maps/src/implementation.ts new file mode 100644 index 000000000..023e3e053 --- /dev/null +++ b/google-maps/src/implementation.ts @@ -0,0 +1,147 @@ +import type { Plugin } from '@capacitor/core'; +import { registerPlugin } from '@capacitor/core'; + +import type { + CameraConfig, + GoogleMapConfig, + LatLngBounds, + MapPadding, + MapType, + Marker, +} from './definitions'; + +/** + * An interface containing the options used when creating a map. + */ +export interface CreateMapArgs { + /** + * A unique identifier for the map instance. + */ + id: string; + /** + * The Google Maps SDK API Key. + */ + apiKey: string; + /** + * The initial configuration settings for the map. + */ + config: GoogleMapConfig; + /** + * The DOM element that the Google Map View will be mounted on which determines size and positioning. + */ + element: HTMLElement; + /** + * Destroy and re-create the map instance if a map with the supplied id already exists + * @default false + */ + forceCreate?: boolean; +} + +export interface DestroyMapArgs { + id: string; +} + +export interface RemoveMarkerArgs { + id: string; + markerId: string; +} + +export interface RemoveMarkersArgs { + id: string; + markerIds: string[]; +} + +export interface AddMarkerArgs { + id: string; + marker: Marker; +} + +export interface CameraArgs { + id: string; + config: CameraConfig; +} + +export interface MapTypeArgs { + id: string; + mapType: MapType; +} + +export interface IndoorMapArgs { + id: string; + enabled: boolean; +} + +export interface TrafficLayerArgs { + id: string; + enabled: boolean; +} + +export interface AccElementsArgs { + id: string; + enabled: boolean; +} + +export interface PaddingArgs { + id: string; + padding: MapPadding; +} + +export interface CurrentLocArgs { + id: string; + enabled: boolean; +} +export interface AddMarkersArgs { + id: string; + markers: Marker[]; +} + +export interface OnScrollArgs { + id: string; + mapBounds: { + x: number; + y: number; + width: number; + height: number; + }; +} + +export interface CapacitorGoogleMapsPlugin extends Plugin { + create(options: CreateMapArgs): Promise; + addMarker(args: AddMarkerArgs): Promise<{ id: string }>; + addMarkers(args: AddMarkersArgs): Promise<{ ids: string[] }>; + removeMarker(args: RemoveMarkerArgs): Promise; + removeMarkers(args: RemoveMarkersArgs): Promise; + enableClustering(args: { id: string }): Promise; + disableClustering(args: { id: string }): Promise; + destroy(args: DestroyMapArgs): Promise; + setCamera(args: CameraArgs): Promise; + setMapType(args: MapTypeArgs): Promise; + enableIndoorMaps(args: IndoorMapArgs): Promise; + enableTrafficLayer(args: TrafficLayerArgs): Promise; + enableAccessibilityElements(args: AccElementsArgs): Promise; + enableCurrentLocation(args: CurrentLocArgs): Promise; + setPadding(args: PaddingArgs): Promise; + onScroll(args: OnScrollArgs): Promise; + dispatchMapEvent(args: { id: string; focus: boolean }): Promise; + getMapBounds(args: { id: string }): Promise; +} + +const CapacitorGoogleMaps = registerPlugin( + 'CapacitorGoogleMaps', + { + web: () => import('./web').then(m => new m.CapacitorGoogleMapsWeb()), + }, +); + +CapacitorGoogleMaps.addListener('isMapInFocus', data => { + const x = data.x; + const y = data.y; + + const elem = document.elementFromPoint(x, y) as HTMLElement | null; + const internalId = elem?.dataset?.internalId; + const mapInFocus = internalId === data.mapId; + + CapacitorGoogleMaps.dispatchMapEvent({ id: data.mapId, focus: mapInFocus }); +}); + +export { CapacitorGoogleMaps }; diff --git a/google-maps/src/index.ts b/google-maps/src/index.ts new file mode 100644 index 000000000..ecd7d30c6 --- /dev/null +++ b/google-maps/src/index.ts @@ -0,0 +1,13 @@ +/* eslint-disable @typescript-eslint/no-namespace */ +import { MapType, Marker } from './definitions'; +import { GoogleMap } from './map'; + +export { GoogleMap, MapType, Marker }; + +declare global { + export namespace JSX { + export interface IntrinsicElements { + 'capacitor-google-map': any; + } + } +} diff --git a/google-maps/src/map.ts b/google-maps/src/map.ts new file mode 100644 index 000000000..fcf9ff1f5 --- /dev/null +++ b/google-maps/src/map.ts @@ -0,0 +1,842 @@ +import { Capacitor } from '@capacitor/core'; +import type { PluginListenerHandle } from '@capacitor/core'; + +import type { + CameraConfig, + Marker, + MapPadding, + MapType, + MapListenerCallback, + MapReadyCallbackData, + CameraIdleCallbackData, + CameraMoveStartedCallbackData, + ClusterClickCallbackData, + MapClickCallbackData, + MarkerClickCallbackData, + MyLocationButtonClickCallbackData, + LatLngBounds, +} from './definitions'; +import type { CreateMapArgs } from './implementation'; +import { CapacitorGoogleMaps } from './implementation'; + +export interface GoogleMapInterface { + create( + options: CreateMapArgs, + callback?: MapListenerCallback, + ): Promise; + enableClustering(): Promise; + disableClustering(): Promise; + addMarker(marker: Marker): Promise; + addMarkers(markers: Marker[]): Promise; + removeMarker(id: string): Promise; + removeMarkers(ids: string[]): Promise; + destroy(): Promise; + setCamera(config: CameraConfig): Promise; + setMapType(mapType: MapType): Promise; + enableIndoorMaps(enabled: boolean): Promise; + enableTrafficLayer(enabled: boolean): Promise; + enableAccessibilityElements(enabled: boolean): Promise; + enableCurrentLocation(enabled: boolean): Promise; + setPadding(padding: MapPadding): Promise; + setOnBoundsChangedListener( + callback?: MapListenerCallback, + ): Promise; + setOnCameraIdleListener( + callback?: MapListenerCallback, + ): Promise; + setOnCameraMoveStartedListener( + callback?: MapListenerCallback, + ): Promise; + setOnClusterClickListener( + callback?: MapListenerCallback, + ): Promise; + setOnClusterInfoWindowClickListener( + callback?: MapListenerCallback, + ): Promise; + setOnInfoWindowClickListener( + callback?: MapListenerCallback, + ): Promise; + setOnMapClickListener( + callback?: MapListenerCallback, + ): Promise; + setOnMarkerClickListener( + callback?: MapListenerCallback, + ): Promise; + setOnMarkerDragStartListener( + callback?: MapListenerCallback, + ): Promise; + setOnMarkerDragListener( + callback?: MapListenerCallback, + ): Promise; + setOnMarkerDragEndListener( + callback?: MapListenerCallback, + ): Promise; + setOnMyLocationButtonClickListener( + callback?: MapListenerCallback, + ): Promise; + setOnMyLocationClickListener( + callback?: MapListenerCallback, + ): Promise; +} + +class MapCustomElement extends HTMLElement { + constructor() { + super(); + } + + connectedCallback() { + if (Capacitor.getPlatform() == 'ios') { + this.style.overflow = 'scroll'; + (this.style as any)['-webkit-overflow-scrolling'] = 'touch'; + + const overflowDiv = document.createElement('div'); + overflowDiv.style.height = '200%'; + + this.appendChild(overflowDiv); + } + } +} + +customElements.define('capacitor-google-map', MapCustomElement); + +export class GoogleMap { + private id: string; + private element: HTMLElement | null = null; + + private onBoundsChangedListener?: PluginListenerHandle; + private onCameraIdleListener?: PluginListenerHandle; + private onCameraMoveStartedListener?: PluginListenerHandle; + private onClusterClickListener?: PluginListenerHandle; + private onClusterInfoWindowClickListener?: PluginListenerHandle; + private onInfoWindowClickListener?: PluginListenerHandle; + private onMapClickListener?: PluginListenerHandle; + private onMarkerClickListener?: PluginListenerHandle; + private onMarkerDragStartListener?: PluginListenerHandle; + private onMarkerDragListener?: PluginListenerHandle; + private onMarkerDragEndListener?: PluginListenerHandle; + private onMyLocationButtonClickListener?: PluginListenerHandle; + private onMyLocationClickListener?: PluginListenerHandle; + + private constructor(id: string) { + this.id = id; + } + + /** + * Creates a new instance of a Google Map + * @param options + * @param callback + * @returns GoogleMap + */ + public static async create( + options: CreateMapArgs, + callback?: MapListenerCallback, + ): Promise { + const newMap = new GoogleMap(options.id); + + if (!options.element) { + throw new Error('container element is required'); + } + + if (options.config.androidLiteMode === undefined) { + options.config.androidLiteMode = false; + } + + newMap.element = options.element; + newMap.element.dataset.internalId = options.id; + + const elementBounds = await GoogleMap.getElementBounds(options.element); + options.config.width = elementBounds.width; + options.config.height = elementBounds.height; + options.config.x = elementBounds.x; + options.config.y = elementBounds.y; + options.config.devicePixelRatio = window.devicePixelRatio; + + if (Capacitor.getPlatform() == 'android') { + newMap.initScrolling(); + } + + if (Capacitor.isNativePlatform()) { + (options.element as any) = {}; + } + + await CapacitorGoogleMaps.create(options); + + if (callback) { + const onMapReadyListener = await CapacitorGoogleMaps.addListener( + 'onMapReady', + (data: MapReadyCallbackData) => { + if (data.mapId == newMap.id) { + callback(data); + onMapReadyListener.remove(); + } + }, + ); + } + + return newMap; + } + + private static async getElementBounds( + element: HTMLElement, + ): Promise { + return new Promise(resolve => { + let elementBounds = element.getBoundingClientRect(); + if (elementBounds.width == 0) { + let retries = 0; + const boundsInterval = setInterval(function () { + if (elementBounds.width == 0 && retries < 30) { + elementBounds = element.getBoundingClientRect(); + retries++; + } else { + if (retries == 30) { + console.warn('Map size could not be determined'); + } + clearInterval(boundsInterval); + resolve(elementBounds); + } + }, 100); + } else { + resolve(elementBounds); + } + }); + } + + /** + * Enable marker clustering + * + * @returns void + */ + async enableClustering(): Promise { + return CapacitorGoogleMaps.enableClustering({ + id: this.id, + }); + } + + /** + * Disable marker clustering + * + * @returns void + */ + async disableClustering(): Promise { + return CapacitorGoogleMaps.disableClustering({ + id: this.id, + }); + } + + /** + * Adds a marker to the map + * + * @param marker + * @returns created marker id + */ + async addMarker(marker: Marker): Promise { + const res = await CapacitorGoogleMaps.addMarker({ + id: this.id, + marker, + }); + + return res.id; + } + + /** + * Adds multiple markers to the map + * + * @param markers + * @returns array of created marker IDs + */ + async addMarkers(markers: Marker[]): Promise { + const res = await CapacitorGoogleMaps.addMarkers({ + id: this.id, + markers, + }); + + return res.ids; + } + + /** + * Remove marker from the map + * + * @param id id of the marker to remove from the map + * @returns + */ + async removeMarker(id: string): Promise { + return CapacitorGoogleMaps.removeMarker({ + id: this.id, + markerId: id, + }); + } + + /** + * Remove markers from the map + * + * @param ids array of ids to remove from the map + * @returns + */ + async removeMarkers(ids: string[]): Promise { + return CapacitorGoogleMaps.removeMarkers({ + id: this.id, + markerIds: ids, + }); + } + + /** + * Destroy the current instance of the map + */ + async destroy(): Promise { + if (Capacitor.getPlatform() == 'android') { + this.disableScrolling(); + } + + this.removeAllMapListeners(); + + return CapacitorGoogleMaps.destroy({ + id: this.id, + }); + } + + /** + * Update the map camera configuration + * + * @param config + * @returns + */ + async setCamera(config: CameraConfig): Promise { + return CapacitorGoogleMaps.setCamera({ + id: this.id, + config, + }); + } + + /** + * Sets the type of map tiles that should be displayed. + * + * @param mapType + * @returns + */ + async setMapType(mapType: MapType): Promise { + return CapacitorGoogleMaps.setMapType({ + id: this.id, + mapType, + }); + } + + /** + * Sets whether indoor maps are shown, where available. + * + * @param enabled + * @returns + */ + async enableIndoorMaps(enabled: boolean): Promise { + return CapacitorGoogleMaps.enableIndoorMaps({ + id: this.id, + enabled, + }); + } + + /** + * Controls whether the map is drawing traffic data, if available. + * + * @param enabled + * @returns + */ + async enableTrafficLayer(enabled: boolean): Promise { + return CapacitorGoogleMaps.enableTrafficLayer({ + id: this.id, + enabled, + }); + } + + /** + * Show accessibility elements for overlay objects, such as Marker and Polyline. + * + * Only available on iOS. + * + * @param enabled + * @returns + */ + async enableAccessibilityElements(enabled: boolean): Promise { + return CapacitorGoogleMaps.enableAccessibilityElements({ + id: this.id, + enabled, + }); + } + + /** + * Set whether the My Location dot and accuracy circle is enabled. + * + * @param enabled + * @returns + */ + async enableCurrentLocation(enabled: boolean): Promise { + return CapacitorGoogleMaps.enableCurrentLocation({ + id: this.id, + enabled, + }); + } + + /** + * Set padding on the 'visible' region of the view. + * + * @param padding + * @returns + */ + async setPadding(padding: MapPadding): Promise { + return CapacitorGoogleMaps.setPadding({ + id: this.id, + padding, + }); + } + + /** + * Get the map's current viewport latitude and longitude bounds. + * + * @returns {LatLngBounds} + */ + async getMapBounds(): Promise { + return CapacitorGoogleMaps.getMapBounds({ + id: this.id, + }); + } + + initScrolling(): void { + const ionContents = document.getElementsByTagName('ion-content'); + + // eslint-disable-next-line @typescript-eslint/prefer-for-of + for (let i = 0; i < ionContents.length; i++) { + (ionContents[i] as any).scrollEvents = true; + } + + window.addEventListener('ionScroll', this.handleScrollEvent); + window.addEventListener('scroll', this.handleScrollEvent); + window.addEventListener('resize', this.handleScrollEvent); + if (screen.orientation) { + screen.orientation.addEventListener('change', () => { + setTimeout(this.updateMapBounds, 500); + }); + } else { + window.addEventListener('orientationchange', () => { + setTimeout(this.updateMapBounds, 500); + }); + } + } + + disableScrolling(): void { + window.removeEventListener('ionScroll', this.handleScrollEvent); + window.removeEventListener('scroll', this.handleScrollEvent); + window.removeEventListener('resize', this.handleScrollEvent); + if (screen.orientation) { + screen.orientation.removeEventListener('change', () => { + setTimeout(this.updateMapBounds, 1000); + }); + } else { + window.removeEventListener('orientationchange', () => { + setTimeout(this.updateMapBounds, 1000); + }); + } + } + + handleScrollEvent = (): void => this.updateMapBounds(); + + private updateMapBounds(): void { + if (this.element) { + const mapRect = this.element.getBoundingClientRect(); + + CapacitorGoogleMaps.onScroll({ + id: this.id, + mapBounds: { + x: mapRect.x, + y: mapRect.y, + width: mapRect.width, + height: mapRect.height, + }, + }); + } + } + + /* + private findContainerElement(): HTMLElement | null { + if (!this.element) { + return null; + } + + let parentElement = this.element.parentElement; + while (parentElement !== null) { + if (window.getComputedStyle(parentElement).overflowY !== 'hidden') { + return parentElement; + } + + parentElement = parentElement.parentElement; + } + + return null; + } + */ + + /** + * Set the event listener on the map for 'onCameraIdle' events. + * + * @param callback + * @returns + */ + async setOnCameraIdleListener( + callback?: MapListenerCallback, + ): Promise { + if (this.onCameraIdleListener) { + this.onCameraIdleListener.remove(); + } + + if (callback) { + this.onCameraIdleListener = await CapacitorGoogleMaps.addListener( + 'onCameraIdle', + this.generateCallback(callback), + ); + } else { + this.onCameraIdleListener = undefined; + } + } + + /** + * Set the event listener on the map for 'onBoundsChanged' events. + * + * @param callback + * @returns + */ + async setOnBoundsChangedListener( + callback?: MapListenerCallback, + ): Promise { + if (this.onBoundsChangedListener) { + this.onBoundsChangedListener.remove(); + } + + if (callback) { + this.onBoundsChangedListener = await CapacitorGoogleMaps.addListener( + 'onBoundsChanged', + this.generateCallback(callback), + ); + } else { + this.onBoundsChangedListener = undefined; + } + } + + /** + * Set the event listener on the map for 'onCameraMoveStarted' events. + * + * @param callback + * @returns + */ + async setOnCameraMoveStartedListener( + callback?: MapListenerCallback, + ): Promise { + if (this.onCameraMoveStartedListener) { + this.onCameraMoveStartedListener.remove(); + } + + if (callback) { + this.onCameraMoveStartedListener = await CapacitorGoogleMaps.addListener( + 'onCameraMoveStarted', + this.generateCallback(callback), + ); + } else { + this.onCameraMoveStartedListener = undefined; + } + } + + /** + * Set the event listener on the map for 'onClusterClick' events. + * + * @param callback + * @returns + */ + async setOnClusterClickListener( + callback?: MapListenerCallback, + ): Promise { + if (this.onClusterClickListener) { + this.onClusterClickListener.remove(); + } + + if (callback) { + this.onClusterClickListener = await CapacitorGoogleMaps.addListener( + 'onClusterClick', + this.generateCallback(callback), + ); + } else { + this.onClusterClickListener = undefined; + } + } + + /** + * Set the event listener on the map for 'onClusterInfoWindowClick' events. + * + * @param callback + * @returns + */ + async setOnClusterInfoWindowClickListener( + callback?: MapListenerCallback, + ): Promise { + if (this.onClusterInfoWindowClickListener) { + this.onClusterInfoWindowClickListener.remove(); + } + + if (callback) { + this.onClusterInfoWindowClickListener = + await CapacitorGoogleMaps.addListener( + 'onClusterInfoWindowClick', + this.generateCallback(callback), + ); + } else { + this.onClusterInfoWindowClickListener = undefined; + } + } + + /** + * Set the event listener on the map for 'onInfoWindowClick' events. + * + * @param callback + * @returns + */ + async setOnInfoWindowClickListener( + callback?: MapListenerCallback, + ): Promise { + if (this.onInfoWindowClickListener) { + this.onInfoWindowClickListener.remove(); + } + + if (callback) { + this.onInfoWindowClickListener = await CapacitorGoogleMaps.addListener( + 'onInfoWindowClick', + this.generateCallback(callback), + ); + } else { + this.onInfoWindowClickListener = undefined; + } + } + + /** + * Set the event listener on the map for 'onMapClick' events. + * + * @param callback + * @returns + */ + async setOnMapClickListener( + callback?: MapListenerCallback, + ): Promise { + if (this.onMapClickListener) { + this.onMapClickListener.remove(); + } + + if (callback) { + this.onMapClickListener = await CapacitorGoogleMaps.addListener( + 'onMapClick', + this.generateCallback(callback), + ); + } else { + this.onMapClickListener = undefined; + } + } + + /** + * Set the event listener on the map for 'onMarkerClick' events. + * + * @param callback + * @returns + */ + async setOnMarkerClickListener( + callback?: MapListenerCallback, + ): Promise { + if (this.onMarkerClickListener) { + this.onMarkerClickListener.remove(); + } + + if (callback) { + this.onMarkerClickListener = await CapacitorGoogleMaps.addListener( + 'onMarkerClick', + this.generateCallback(callback), + ); + } else { + this.onMarkerClickListener = undefined; + } + } + + /** + * Set the event listener on the map for 'onMarkerDragStart' events. + * + * @param callback + * @returns + */ + async setOnMarkerDragStartListener( + callback?: MapListenerCallback, + ): Promise { + if (this.onMarkerDragStartListener) { + this.onMarkerDragStartListener.remove(); + } + + if (callback) { + this.onMarkerDragStartListener = await CapacitorGoogleMaps.addListener( + 'onMarkerDragStart', + this.generateCallback(callback), + ); + } else { + this.onMarkerDragStartListener = undefined; + } + } + + /** + * Set the event listener on the map for 'onMarkerDrag' events. + * + * @param callback + * @returns + */ + async setOnMarkerDragListener( + callback?: MapListenerCallback, + ): Promise { + if (this.onMarkerDragListener) { + this.onMarkerDragListener.remove(); + } + + if (callback) { + this.onMarkerDragListener = await CapacitorGoogleMaps.addListener( + 'onMarkerDrag', + this.generateCallback(callback), + ); + } else { + this.onMarkerDragListener = undefined; + } + } + + /** + * Set the event listener on the map for 'onMarkerDragEnd' events. + * + * @param callback + * @returns + */ + async setOnMarkerDragEndListener( + callback?: MapListenerCallback, + ): Promise { + if (this.onMarkerDragEndListener) { + this.onMarkerDragEndListener.remove(); + } + + if (callback) { + this.onMarkerDragEndListener = await CapacitorGoogleMaps.addListener( + 'onMarkerDragEnd', + this.generateCallback(callback), + ); + } else { + this.onMarkerDragEndListener = undefined; + } + } + + /** + * Set the event listener on the map for 'onMyLocationButtonClick' events. + * + * @param callback + * @returns + */ + async setOnMyLocationButtonClickListener( + callback?: MapListenerCallback, + ): Promise { + if (this.onMyLocationButtonClickListener) { + this.onMyLocationButtonClickListener.remove(); + } + + if (callback) { + this.onMyLocationButtonClickListener = + await CapacitorGoogleMaps.addListener( + 'onMyLocationButtonClick', + this.generateCallback(callback), + ); + } else { + this.onMyLocationButtonClickListener = undefined; + } + } + + /** + * Set the event listener on the map for 'onMyLocationClick' events. + * + * @param callback + * @returns + */ + async setOnMyLocationClickListener( + callback?: MapListenerCallback, + ): Promise { + if (this.onMyLocationClickListener) { + this.onMyLocationClickListener.remove(); + } + + if (callback) { + this.onMyLocationClickListener = await CapacitorGoogleMaps.addListener( + 'onMyLocationClick', + this.generateCallback(callback), + ); + } else { + this.onMyLocationClickListener = undefined; + } + } + + /** + * Remove all event listeners on the map. + * + * @param callback + * @returns + */ + async removeAllMapListeners(): Promise { + if (this.onBoundsChangedListener) { + this.onBoundsChangedListener.remove(); + this.onBoundsChangedListener = undefined; + } + if (this.onCameraIdleListener) { + this.onCameraIdleListener.remove(); + this.onCameraIdleListener = undefined; + } + if (this.onCameraMoveStartedListener) { + this.onCameraMoveStartedListener.remove(); + this.onCameraMoveStartedListener = undefined; + } + + if (this.onClusterClickListener) { + this.onClusterClickListener.remove(); + this.onClusterClickListener = undefined; + } + + if (this.onClusterInfoWindowClickListener) { + this.onClusterInfoWindowClickListener.remove(); + this.onClusterInfoWindowClickListener = undefined; + } + + if (this.onInfoWindowClickListener) { + this.onInfoWindowClickListener.remove(); + this.onInfoWindowClickListener = undefined; + } + + if (this.onMapClickListener) { + this.onMapClickListener.remove(); + this.onMapClickListener = undefined; + } + + if (this.onMarkerClickListener) { + this.onMarkerClickListener.remove(); + this.onMarkerClickListener = undefined; + } + + if (this.onMyLocationButtonClickListener) { + this.onMyLocationButtonClickListener.remove(); + this.onMyLocationButtonClickListener = undefined; + } + + if (this.onMyLocationClickListener) { + this.onMyLocationClickListener.remove(); + this.onMyLocationClickListener = undefined; + } + } + + private generateCallback( + callback: MapListenerCallback, + ): MapListenerCallback { + const mapId = this.id; + return (data: any) => { + if (data.mapId == mapId) { + callback(data); + } + }; + } +} diff --git a/google-maps/src/web.ts b/google-maps/src/web.ts new file mode 100644 index 000000000..7cf35caee --- /dev/null +++ b/google-maps/src/web.ts @@ -0,0 +1,432 @@ +import { WebPlugin } from '@capacitor/core'; +import type { + Cluster, + onClusterClickHandler, +} from '@googlemaps/markerclusterer'; +import { MarkerClusterer } from '@googlemaps/markerclusterer'; + +import type { LatLngBounds, Marker } from './definitions'; +import type { + AccElementsArgs, + AddMarkerArgs, + CameraArgs, + AddMarkersArgs, + CapacitorGoogleMapsPlugin, + CreateMapArgs, + CurrentLocArgs, + DestroyMapArgs, + IndoorMapArgs, + MapTypeArgs, + PaddingArgs, + RemoveMarkerArgs, + TrafficLayerArgs, + RemoveMarkersArgs, + OnScrollArgs, +} from './implementation'; + +export class CapacitorGoogleMapsWeb + extends WebPlugin + implements CapacitorGoogleMapsPlugin +{ + private gMapsRef: typeof google.maps | undefined = undefined; + private maps: { + [id: string]: { + element: HTMLElement; + map: google.maps.Map; + markers: { + [id: string]: google.maps.Marker; + }; + markerClusterer?: MarkerClusterer; + trafficLayer?: google.maps.TrafficLayer; + }; + } = {}; + private currMarkerId = 0; + + private onClusterClickHandler: onClusterClickHandler = ( + _: google.maps.MapMouseEvent, + cluster: Cluster, + map: google.maps.Map, + ): void => { + const mapId = this.getIdFromMap(map); + const items: any[] = []; + + if (cluster.markers != undefined) { + for (const marker of cluster.markers) { + const markerId = this.getIdFromMarker(mapId, marker); + + items.push({ + markerId: markerId, + latitude: marker.getPosition()?.lat(), + longitude: marker.getPosition()?.lng(), + title: marker.getTitle(), + snippet: '', + }); + } + } + + this.notifyListeners('onClusterClick', { + mapId: mapId, + latitude: cluster.position.lat(), + longitude: cluster.position.lng(), + size: cluster.count, + items: items, + }); + }; + + private getIdFromMap(map: google.maps.Map): string { + for (const id in this.maps) { + if (this.maps[id].map == map) { + return id; + } + } + + return ''; + } + + private getIdFromMarker(mapId: string, marker: google.maps.Marker): string { + for (const id in this.maps[mapId].markers) { + if (this.maps[mapId].markers[id] == marker) { + return id; + } + } + + return ''; + } + + private async importGoogleLib(apiKey: string) { + if (this.gMapsRef === undefined) { + const lib = await import('@googlemaps/js-api-loader'); + const loader = new lib.Loader({ + apiKey: apiKey ?? '', + version: 'weekly', + libraries: ['places'], + }); + const google = await loader.load(); + this.gMapsRef = google.maps; + console.log('Loaded google maps API'); + } + } + + async setCamera(_args: CameraArgs): Promise { + // Animation not supported yet... + this.maps[_args.id].map.moveCamera({ + center: _args.config.coordinate, + heading: _args.config.bearing, + tilt: _args.config.angle, + zoom: _args.config.zoom, + }); + } + + async setMapType(_args: MapTypeArgs): Promise { + this.maps[_args.id].map.setMapTypeId(_args.mapType); + } + + async enableIndoorMaps(_args: IndoorMapArgs): Promise { + throw new Error('Method not supported on web.'); + } + + async enableTrafficLayer(_args: TrafficLayerArgs): Promise { + const trafficLayer = + this.maps[_args.id].trafficLayer ?? new google.maps.TrafficLayer(); + + if (_args.enabled) { + trafficLayer.setMap(this.maps[_args.id].map); + this.maps[_args.id].trafficLayer = trafficLayer; + } else if (this.maps[_args.id].trafficLayer) { + trafficLayer.setMap(null); + this.maps[_args.id].trafficLayer = undefined; + } + } + + async enableAccessibilityElements(_args: AccElementsArgs): Promise { + throw new Error('Method not supported on web.'); + } + + dispatchMapEvent(_args: { id: string }): Promise { + throw new Error('Method not supported on web.'); + } + + async enableCurrentLocation(_args: CurrentLocArgs): Promise { + if (_args.enabled) { + if (navigator.geolocation) { + navigator.geolocation.getCurrentPosition( + (position: GeolocationPosition) => { + const pos = { + lat: position.coords.latitude, + lng: position.coords.longitude, + }; + + this.maps[_args.id].map.setCenter(pos); + + this.notifyListeners('onMyLocationButtonClick', {}); + + this.notifyListeners('onMyLocationClick', {}); + }, + () => { + throw new Error('Geolocation not supported on web browser.'); + }, + ); + } else { + throw new Error('Geolocation not supported on web browser.'); + } + } + } + async setPadding(_args: PaddingArgs): Promise { + const bounds = this.maps[_args.id].map.getBounds(); + + if (bounds !== undefined) { + this.maps[_args.id].map.fitBounds(bounds, _args.padding); + } + } + + async getMapBounds(_args: { id: string }): Promise { + const bounds = this.maps[_args.id].map.getBounds(); + + if (!bounds) { + throw new Error('Google Map Bounds could not be found.'); + } + + return { + southwest: { + lat: bounds.getSouthWest().lat(), + lng: bounds.getSouthWest().lng(), + }, + center: { + lat: bounds.getCenter().lat(), + lng: bounds.getCenter().lng(), + }, + northeast: { + lat: bounds.getNorthEast().lat(), + lng: bounds.getNorthEast().lng(), + }, + }; + } + + async addMarkers(_args: AddMarkersArgs): Promise<{ ids: string[] }> { + const markerIds: string[] = []; + const map = this.maps[_args.id]; + + for (const markerArgs of _args.markers) { + const markerOpts = this.buildMarkerOpts(markerArgs, map.map); + const marker = new google.maps.Marker(markerOpts); + + const id = '' + this.currMarkerId; + + map.markers[id] = marker; + this.setMarkerListeners(_args.id, id, marker); + + markerIds.push(id); + this.currMarkerId++; + } + + return { ids: markerIds }; + } + + async addMarker(_args: AddMarkerArgs): Promise<{ id: string }> { + const markerOpts = this.buildMarkerOpts( + _args.marker, + this.maps[_args.id].map, + ); + + const marker = new google.maps.Marker(markerOpts); + + const id = '' + this.currMarkerId; + + this.maps[_args.id].markers[id] = marker; + this.setMarkerListeners(_args.id, id, marker); + + this.currMarkerId++; + + return { id: id }; + } + + async removeMarkers(_args: RemoveMarkersArgs): Promise { + const map = this.maps[_args.id]; + + for (const id of _args.markerIds) { + map.markers[id].setMap(null); + delete map.markers[id]; + } + } + + async removeMarker(_args: RemoveMarkerArgs): Promise { + this.maps[_args.id].markers[_args.markerId].setMap(null); + delete this.maps[_args.id].markers[_args.markerId]; + } + + async enableClustering(_args: { id: string }): Promise { + const markers: google.maps.Marker[] = []; + + for (const id in this.maps[_args.id].markers) { + markers.push(this.maps[_args.id].markers[id]); + } + + this.maps[_args.id].markerClusterer = new MarkerClusterer({ + map: this.maps[_args.id].map, + markers: markers, + onClusterClick: this.onClusterClickHandler, + }); + } + + async disableClustering(_args: { id: string }): Promise { + this.maps[_args.id].markerClusterer?.setMap(null); + this.maps[_args.id].markerClusterer = undefined; + } + + async onScroll(_args: OnScrollArgs): Promise { + throw new Error('Method not supported on web.'); + } + + async create(_args: CreateMapArgs): Promise { + console.log(`Create map: ${_args.id}`); + await this.importGoogleLib(_args.apiKey); + this.maps[_args.id] = { + map: new window.google.maps.Map(_args.element, { ..._args.config }), + element: _args.element, + markers: {}, + }; + this.setMapListeners(_args.id); + } + + async destroy(_args: DestroyMapArgs): Promise { + console.log(`Destroy map: ${_args.id}`); + const mapItem = this.maps[_args.id]; + mapItem.element.innerHTML = ''; + mapItem.map.unbindAll(); + delete this.maps[_args.id]; + } + + async setMarkerListeners( + mapId: string, + markerId: string, + marker: google.maps.Marker, + ): Promise { + marker.addListener('click', () => { + this.notifyListeners('onMarkerClick', { + mapId: mapId, + markerId: markerId, + latitude: marker.getPosition()?.lat(), + longitude: marker.getPosition()?.lng(), + title: marker.getTitle(), + snippet: '', + }); + }); + + marker.addListener('dragstart', () => { + this.notifyListeners('onMarkerDragStart', { + mapId: mapId, + markerId: markerId, + latitude: marker.getPosition()?.lat(), + longitude: marker.getPosition()?.lng(), + title: marker.getTitle(), + snippet: '', + }); + }); + + marker.addListener('drag', () => { + this.notifyListeners('onMarkerDrag', { + mapId: mapId, + markerId: markerId, + latitude: marker.getPosition()?.lat(), + longitude: marker.getPosition()?.lng(), + title: marker.getTitle(), + snippet: '', + }); + }); + + marker.addListener('dragend', () => { + this.notifyListeners('onMarkerDragEnd', { + mapId: mapId, + markerId: markerId, + latitude: marker.getPosition()?.lat(), + longitude: marker.getPosition()?.lng(), + title: marker.getTitle(), + snippet: '', + }); + }); + } + + async setMapListeners(mapId: string): Promise { + const map = this.maps[mapId].map; + + map.addListener('idle', async () => { + const bounds = await this.getMapBounds({ id: mapId }); + this.notifyListeners('onCameraIdle', { + mapId: mapId, + bearing: map.getHeading(), + bounds: bounds, + latitude: map.getCenter()?.lat(), + longitude: map.getCenter()?.lng(), + tilt: map.getTilt(), + zoom: map.getZoom(), + }); + }); + + map.addListener('center_changed', () => { + this.notifyListeners('onCameraMoveStarted', { + mapId: mapId, + isGesture: true, + }); + }); + + map.addListener('bounds_changed', async () => { + const bounds = await this.getMapBounds({ id: mapId }); + this.notifyListeners('onBoundsChanged', { + mapId: mapId, + bearing: map.getHeading(), + bounds: bounds, + latitude: map.getCenter()?.lat(), + longitude: map.getCenter()?.lng(), + tilt: map.getTilt(), + zoom: map.getZoom(), + }); + }); + + map.addListener( + 'click', + (e: google.maps.MapMouseEvent | google.maps.IconMouseEvent) => { + this.notifyListeners('onMapClick', { + mapId: mapId, + latitude: e.latLng?.lat(), + longitude: e.latLng?.lng(), + }); + }, + ); + + this.notifyListeners('onMapReady', { + mapId: mapId, + }); + } + + private buildMarkerOpts( + marker: Marker, + map: google.maps.Map, + ): google.maps.MarkerOptions { + let iconImage: google.maps.Icon | undefined = undefined; + if (marker.iconUrl) { + iconImage = { + url: marker.iconUrl, + scaledSize: marker.iconSize + ? new google.maps.Size(marker.iconSize.width, marker.iconSize.height) + : null, + anchor: marker.iconAnchor + ? new google.maps.Point(marker.iconAnchor.x, marker.iconAnchor.y) + : new google.maps.Point(0, 0), + origin: marker.iconOrigin + ? new google.maps.Point(marker.iconOrigin.x, marker.iconOrigin.y) + : new google.maps.Point(0, 0), + }; + } + + const opts: google.maps.MarkerOptions = { + position: marker.coordinate, + map: map, + opacity: marker.opacity, + title: marker.title, + icon: iconImage, + draggable: marker.draggable, + }; + + return opts; + } +} diff --git a/google-maps/swiftlint.config.js b/google-maps/swiftlint.config.js new file mode 100644 index 000000000..829e91209 --- /dev/null +++ b/google-maps/swiftlint.config.js @@ -0,0 +1,9 @@ +/* eslint-disable no-undef */ +module.exports = { + ...require('@ionic/swiftlint-config'), + // eslint-disable-next-line no-template-curly-in-string + included: ['${PWD}/ios/Plugin'], + identifier_name: { + min_length: 1, + }, +}; diff --git a/google-maps/tsconfig.json b/google-maps/tsconfig.json new file mode 100644 index 000000000..b2cbfd6c3 --- /dev/null +++ b/google-maps/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "allowUnreachableCode": false, + "declaration": true, + "declarationDir": "dist/typings", + "esModuleInterop": true, + "inlineSources": true, + "lib": ["dom", "es2017"], + "module": "esnext", + "moduleResolution": "node", + "noFallthroughCasesInSwitch": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "outDir": "dist/esm", + "pretty": true, + "sourceMap": true, + "strict": true, + "target": "es2017" + }, + "files": ["src/index.ts"] +} diff --git a/google-maps/unit-tests/android/.gitignore b/google-maps/unit-tests/android/.gitignore new file mode 100644 index 000000000..aa724b770 --- /dev/null +++ b/google-maps/unit-tests/android/.gitignore @@ -0,0 +1,15 @@ +*.iml +.gradle +/local.properties +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +.DS_Store +/build +/captures +.externalNativeBuild +.cxx +local.properties diff --git a/google-maps/unit-tests/android/app/build.gradle b/google-maps/unit-tests/android/app/build.gradle new file mode 100644 index 000000000..551211168 --- /dev/null +++ b/google-maps/unit-tests/android/app/build.gradle @@ -0,0 +1,58 @@ +plugins { + id 'com.android.application' + id 'kotlin-android' +} + +android { + compileSdkVersion 31 + buildToolsVersion "30.0.3" + + defaultConfig { + applicationId "io.ionic.googlemapstest" + minSdkVersion 22 + targetSdkVersion 31 + versionCode 1 + versionName "1.0" + + testInstrumentationRunner "androidx.test.ext.junit.runners.AndroidJUnit4" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + kotlinOptions { + jvmTarget = '1.8' + } + sourceSets { + main.java.srcDirs += '../../../android' + } + testOptions { + unitTests { + includeAndroidResources = true + } + unitTests.all { + testLogging { + events "passed", "skipped", "failed", "standardOut", "standardError" + outputs.upToDateWhen {false} + showStandardStreams = false + } + } + } +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib:${kotlin_version}" + implementation 'androidx.core:core-ktx:1.7.0' + implementation 'androidx.appcompat:appcompat:1.4.0' + implementation 'com.google.android.material:material:1.4.0' + implementation 'junit:junit:4.13.2' + testImplementation 'org.robolectric:robolectric:4.7.1' + implementation project(':capacitor-android') +} \ No newline at end of file diff --git a/google-maps/unit-tests/android/app/proguard-rules.pro b/google-maps/unit-tests/android/app/proguard-rules.pro new file mode 100644 index 000000000..481bb4348 --- /dev/null +++ b/google-maps/unit-tests/android/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/google-maps/unit-tests/android/app/src/main/AndroidManifest.xml b/google-maps/unit-tests/android/app/src/main/AndroidManifest.xml new file mode 100644 index 000000000..b8e985a0a --- /dev/null +++ b/google-maps/unit-tests/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,15 @@ + + + + + + + + \ No newline at end of file diff --git a/google-maps/unit-tests/android/app/src/main/java/io/ionic/googlemapstest/MainActivity.kt b/google-maps/unit-tests/android/app/src/main/java/io/ionic/googlemapstest/MainActivity.kt new file mode 100644 index 000000000..c01c3d7d1 --- /dev/null +++ b/google-maps/unit-tests/android/app/src/main/java/io/ionic/googlemapstest/MainActivity.kt @@ -0,0 +1,6 @@ +package io.ionic.googlemapstest + +import androidx.appcompat.app.AppCompatActivity + +class MainActivity : AppCompatActivity() { +} \ No newline at end of file diff --git a/google-maps/unit-tests/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/google-maps/unit-tests/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 000000000..2b068d114 --- /dev/null +++ b/google-maps/unit-tests/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/google-maps/unit-tests/android/app/src/main/res/drawable/ic_launcher_background.xml b/google-maps/unit-tests/android/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 000000000..07d5da9cb --- /dev/null +++ b/google-maps/unit-tests/android/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/google-maps/unit-tests/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/google-maps/unit-tests/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 000000000..eca70cfe5 --- /dev/null +++ b/google-maps/unit-tests/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/google-maps/unit-tests/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/google-maps/unit-tests/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 000000000..eca70cfe5 --- /dev/null +++ b/google-maps/unit-tests/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/google-maps/unit-tests/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/google-maps/unit-tests/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 000000000..a571e6009 Binary files /dev/null and b/google-maps/unit-tests/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/google-maps/unit-tests/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/google-maps/unit-tests/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png new file mode 100644 index 000000000..61da551c5 Binary files /dev/null and b/google-maps/unit-tests/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ diff --git a/google-maps/unit-tests/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/google-maps/unit-tests/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 000000000..c41dd2853 Binary files /dev/null and b/google-maps/unit-tests/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/google-maps/unit-tests/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/google-maps/unit-tests/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png new file mode 100644 index 000000000..db5080a75 Binary files /dev/null and b/google-maps/unit-tests/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ diff --git a/google-maps/unit-tests/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/google-maps/unit-tests/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 000000000..6dba46dab Binary files /dev/null and b/google-maps/unit-tests/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/google-maps/unit-tests/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/google-maps/unit-tests/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 000000000..da31a871c Binary files /dev/null and b/google-maps/unit-tests/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ diff --git a/google-maps/unit-tests/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/google-maps/unit-tests/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 000000000..15ac68172 Binary files /dev/null and b/google-maps/unit-tests/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/google-maps/unit-tests/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/google-maps/unit-tests/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 000000000..b216f2d31 Binary files /dev/null and b/google-maps/unit-tests/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/google-maps/unit-tests/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/google-maps/unit-tests/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 000000000..f25a41974 Binary files /dev/null and b/google-maps/unit-tests/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/google-maps/unit-tests/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/google-maps/unit-tests/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 000000000..e96783ccc Binary files /dev/null and b/google-maps/unit-tests/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ diff --git a/google-maps/unit-tests/android/app/src/main/res/values-night/themes.xml b/google-maps/unit-tests/android/app/src/main/res/values-night/themes.xml new file mode 100644 index 000000000..edf82468d --- /dev/null +++ b/google-maps/unit-tests/android/app/src/main/res/values-night/themes.xml @@ -0,0 +1,16 @@ + + + + \ No newline at end of file diff --git a/google-maps/unit-tests/android/app/src/main/res/values/colors.xml b/google-maps/unit-tests/android/app/src/main/res/values/colors.xml new file mode 100644 index 000000000..f8c6127d3 --- /dev/null +++ b/google-maps/unit-tests/android/app/src/main/res/values/colors.xml @@ -0,0 +1,10 @@ + + + #FFBB86FC + #FF6200EE + #FF3700B3 + #FF03DAC5 + #FF018786 + #FF000000 + #FFFFFFFF + \ No newline at end of file diff --git a/google-maps/unit-tests/android/app/src/main/res/values/strings.xml b/google-maps/unit-tests/android/app/src/main/res/values/strings.xml new file mode 100644 index 000000000..0a680a455 --- /dev/null +++ b/google-maps/unit-tests/android/app/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + Google Maps Test + \ No newline at end of file diff --git a/google-maps/unit-tests/android/app/src/main/res/values/themes.xml b/google-maps/unit-tests/android/app/src/main/res/values/themes.xml new file mode 100644 index 000000000..9e61c2624 --- /dev/null +++ b/google-maps/unit-tests/android/app/src/main/res/values/themes.xml @@ -0,0 +1,16 @@ + + + + \ No newline at end of file diff --git a/google-maps/unit-tests/android/app/src/test/java/io/ionic/googlemapstest/GoogleMapsUnitTests.kt b/google-maps/unit-tests/android/app/src/test/java/io/ionic/googlemapstest/GoogleMapsUnitTests.kt new file mode 100644 index 000000000..1eee5112d --- /dev/null +++ b/google-maps/unit-tests/android/app/src/test/java/io/ionic/googlemapstest/GoogleMapsUnitTests.kt @@ -0,0 +1,18 @@ +package io.ionic.googlemapstest + +import com.capacitorjs.plugins.googlemaps.CapacitorGoogleMaps +import org.junit.Assert.assertEquals +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner + +@RunWith(RobolectricTestRunner::class) +class GoogleMapsUnitTests { + @Test + fun exampleTest() { + val plugin = CapacitorGoogleMaps() + + val valueOf = plugin.echo("Hello world!") + assertEquals("Hello world!", valueOf) + } +} \ No newline at end of file diff --git a/google-maps/unit-tests/android/build.gradle b/google-maps/unit-tests/android/build.gradle new file mode 100644 index 000000000..15609a9fe --- /dev/null +++ b/google-maps/unit-tests/android/build.gradle @@ -0,0 +1,25 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. +buildscript { + ext.kotlin_version = '1.6.0' + repositories { + google() + mavenCentral() + } + dependencies { + classpath "com.android.tools.build:gradle:4.2.2" + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +allprojects { + repositories { + google() + mavenCentral() + } +} + +task clean(type: Delete) { + delete rootProject.buildDir +} \ No newline at end of file diff --git a/google-maps/unit-tests/android/gradle.properties b/google-maps/unit-tests/android/gradle.properties new file mode 100644 index 000000000..252175276 --- /dev/null +++ b/google-maps/unit-tests/android/gradle.properties @@ -0,0 +1,19 @@ +# Project-wide Gradle settings. +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true +# AndroidX package structure to make it clearer which packages are bundled with the +# Android operating system, and which are packaged with your app"s APK +# https://developer.android.com/topic/libraries/support-library/androidx-rn +android.useAndroidX=true +# Kotlin code style for this project: "official" or "obsolete": +kotlin.code.style=official \ No newline at end of file diff --git a/google-maps/unit-tests/android/gradle/wrapper/gradle-wrapper.jar b/google-maps/unit-tests/android/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 000000000..f6b961fd5 Binary files /dev/null and b/google-maps/unit-tests/android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/google-maps/unit-tests/android/gradle/wrapper/gradle-wrapper.properties b/google-maps/unit-tests/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..734c61290 --- /dev/null +++ b/google-maps/unit-tests/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Nov 19 08:06:49 PST 2021 +distributionBase=GRADLE_USER_HOME +distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip +distributionPath=wrapper/dists +zipStorePath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME diff --git a/storage/android/gradlew b/google-maps/unit-tests/android/gradlew similarity index 75% rename from storage/android/gradlew rename to google-maps/unit-tests/android/gradlew index 4f906e0c8..cccdd3d51 100755 --- a/storage/android/gradlew +++ b/google-maps/unit-tests/android/gradlew @@ -1,21 +1,5 @@ #!/usr/bin/env sh -# -# Copyright 2015 the original author or authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - ############################################################################## ## ## Gradle start up script for UN*X @@ -44,7 +28,7 @@ APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' +DEFAULT_JVM_OPTS="" # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" @@ -82,7 +66,6 @@ esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then @@ -126,11 +109,10 @@ if $darwin; then GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" fi -# For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - JAVACMD=`cygpath --unix "$JAVACMD"` # We build the pattern for arguments to be converted via cygpath @@ -156,19 +138,19 @@ if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then else eval `echo args$i`="\"$arg\"" fi - i=`expr $i + 1` + i=$((i+1)) done case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; esac fi @@ -177,9 +159,14 @@ save () { for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done echo " " } -APP_ARGS=`save "$@"` +APP_ARGS=$(save "$@") # Collect all arguments for the java command, following the shell quoting and substitution rules eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + exec "$JAVACMD" "$@" diff --git a/google-maps/unit-tests/android/gradlew.bat b/google-maps/unit-tests/android/gradlew.bat new file mode 100644 index 000000000..e95643d6a --- /dev/null +++ b/google-maps/unit-tests/android/gradlew.bat @@ -0,0 +1,84 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/google-maps/unit-tests/android/settings.gradle b/google-maps/unit-tests/android/settings.gradle new file mode 100644 index 000000000..07da0dbf5 --- /dev/null +++ b/google-maps/unit-tests/android/settings.gradle @@ -0,0 +1,4 @@ +rootProject.name = "Google Maps Test" +include ':app' +include ':capacitor-android' +project(':capacitor-android').projectDir = new File('../../node_modules/@capacitor/android/capacitor') diff --git a/google-maps/unit-tests/ios/GoogleMapsPlugin/GoogleMapsPlugin.xcodeproj/project.pbxproj b/google-maps/unit-tests/ios/GoogleMapsPlugin/GoogleMapsPlugin.xcodeproj/project.pbxproj new file mode 100644 index 000000000..96482c9e0 --- /dev/null +++ b/google-maps/unit-tests/ios/GoogleMapsPlugin/GoogleMapsPlugin.xcodeproj/project.pbxproj @@ -0,0 +1,637 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 55; + objects = { + +/* Begin PBXBuildFile section */ + 022B20922746AD38000F2A2C /* GoogleMapsPlugin.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 022B20892746AD37000F2A2C /* GoogleMapsPlugin.framework */; }; + 022B20972746AD38000F2A2C /* GoogleMapsPluginTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 022B20962746AD38000F2A2C /* GoogleMapsPluginTests.swift */; }; + 022B20B02746ADD7000F2A2C /* CapacitorGoogleMaps.swift in Sources */ = {isa = PBXBuildFile; fileRef = 022B20A62746ADD7000F2A2C /* CapacitorGoogleMaps.swift */; }; + 022B20BC2746B791000F2A2C /* TestAppApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 022B20BB2746B791000F2A2C /* TestAppApp.swift */; }; + 022B20BE2746B791000F2A2C /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 022B20BD2746B791000F2A2C /* ContentView.swift */; }; + 022B20C02746B793000F2A2C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 022B20BF2746B793000F2A2C /* Assets.xcassets */; }; + 022B20C32746B793000F2A2C /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 022B20C22746B793000F2A2C /* Preview Assets.xcassets */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 022B20932746AD38000F2A2C /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 022B20802746AD37000F2A2C /* Project object */; + proxyType = 1; + remoteGlobalIDString = 022B20882746AD37000F2A2C; + remoteInfo = IdentityVaultNative; + }; + 022B20C82746B7FA000F2A2C /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 022B20802746AD37000F2A2C /* Project object */; + proxyType = 1; + remoteGlobalIDString = 022B20B82746B791000F2A2C; + remoteInfo = TestApp; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 022B20892746AD37000F2A2C /* GoogleMapsPlugin.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = GoogleMapsPlugin.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 022B20912746AD38000F2A2C /* GoogleMapsPluginTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = GoogleMapsPluginTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 022B20962746AD38000F2A2C /* GoogleMapsPluginTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GoogleMapsPluginTests.swift; sourceTree = ""; }; + 022B20A62746ADD7000F2A2C /* CapacitorGoogleMaps.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CapacitorGoogleMaps.swift; sourceTree = ""; }; + 022B20B92746B791000F2A2C /* TestApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TestApp.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 022B20BB2746B791000F2A2C /* TestAppApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestAppApp.swift; sourceTree = ""; }; + 022B20BD2746B791000F2A2C /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; + 022B20BF2746B793000F2A2C /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 022B20C22746B793000F2A2C /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; + 022B20C72746B7B1000F2A2C /* TestApp.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = TestApp.entitlements; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 022B20862746AD37000F2A2C /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 022B208E2746AD38000F2A2C /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 022B20922746AD38000F2A2C /* GoogleMapsPlugin.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 022B20B62746B791000F2A2C /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 022B207F2746AD37000F2A2C = { + isa = PBXGroup; + children = ( + 022B208B2746AD37000F2A2C /* GoogleMapsPlugin */, + 022B20952746AD38000F2A2C /* GoogleMapsPluginTests */, + 022B20BA2746B791000F2A2C /* TestApp */, + 022B208A2746AD37000F2A2C /* Products */, + ); + sourceTree = ""; + }; + 022B208A2746AD37000F2A2C /* Products */ = { + isa = PBXGroup; + children = ( + 022B20892746AD37000F2A2C /* GoogleMapsPlugin.framework */, + 022B20912746AD38000F2A2C /* GoogleMapsPluginTests.xctest */, + 022B20B92746B791000F2A2C /* TestApp.app */, + ); + name = Products; + sourceTree = ""; + }; + 022B208B2746AD37000F2A2C /* GoogleMapsPlugin */ = { + isa = PBXGroup; + children = ( + 022B20A62746ADD7000F2A2C /* CapacitorGoogleMaps.swift */, + ); + name = GoogleMapsPlugin; + path = ../../../ios/Plugin; + sourceTree = ""; + }; + 022B20952746AD38000F2A2C /* GoogleMapsPluginTests */ = { + isa = PBXGroup; + children = ( + 022B20962746AD38000F2A2C /* GoogleMapsPluginTests.swift */, + ); + path = GoogleMapsPluginTests; + sourceTree = ""; + }; + 022B20BA2746B791000F2A2C /* TestApp */ = { + isa = PBXGroup; + children = ( + 022B20C72746B7B1000F2A2C /* TestApp.entitlements */, + 022B20BB2746B791000F2A2C /* TestAppApp.swift */, + 022B20BD2746B791000F2A2C /* ContentView.swift */, + 022B20BF2746B793000F2A2C /* Assets.xcassets */, + 022B20C12746B793000F2A2C /* Preview Content */, + ); + path = TestApp; + sourceTree = ""; + }; + 022B20C12746B793000F2A2C /* Preview Content */ = { + isa = PBXGroup; + children = ( + 022B20C22746B793000F2A2C /* Preview Assets.xcassets */, + ); + path = "Preview Content"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 022B20842746AD37000F2A2C /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 022B20882746AD37000F2A2C /* GoogleMapsPlugin */ = { + isa = PBXNativeTarget; + buildConfigurationList = 022B209B2746AD38000F2A2C /* Build configuration list for PBXNativeTarget "GoogleMapsPlugin" */; + buildPhases = ( + 022B20842746AD37000F2A2C /* Headers */, + 022B20852746AD37000F2A2C /* Sources */, + 022B20862746AD37000F2A2C /* Frameworks */, + 022B20872746AD37000F2A2C /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = GoogleMapsPlugin; + productName = IdentityVaultNative; + productReference = 022B20892746AD37000F2A2C /* GoogleMapsPlugin.framework */; + productType = "com.apple.product-type.framework"; + }; + 022B20902746AD38000F2A2C /* GoogleMapsPluginTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 022B209E2746AD38000F2A2C /* Build configuration list for PBXNativeTarget "GoogleMapsPluginTests" */; + buildPhases = ( + 022B208D2746AD38000F2A2C /* Sources */, + 022B208E2746AD38000F2A2C /* Frameworks */, + 022B208F2746AD38000F2A2C /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 022B20942746AD38000F2A2C /* PBXTargetDependency */, + 022B20C92746B7FA000F2A2C /* PBXTargetDependency */, + ); + name = GoogleMapsPluginTests; + productName = IdentityVaultNativeTests; + productReference = 022B20912746AD38000F2A2C /* GoogleMapsPluginTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 022B20B82746B791000F2A2C /* TestApp */ = { + isa = PBXNativeTarget; + buildConfigurationList = 022B20C42746B793000F2A2C /* Build configuration list for PBXNativeTarget "TestApp" */; + buildPhases = ( + 022B20B52746B791000F2A2C /* Sources */, + 022B20B62746B791000F2A2C /* Frameworks */, + 022B20B72746B791000F2A2C /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = TestApp; + productName = TestApp; + productReference = 022B20B92746B791000F2A2C /* TestApp.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 022B20802746AD37000F2A2C /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = 1; + LastSwiftUpdateCheck = 1310; + LastUpgradeCheck = 1310; + TargetAttributes = { + 022B20882746AD37000F2A2C = { + CreatedOnToolsVersion = 13.1; + LastSwiftMigration = 1310; + }; + 022B20902746AD38000F2A2C = { + CreatedOnToolsVersion = 13.1; + TestTargetID = 022B20B82746B791000F2A2C; + }; + 022B20B82746B791000F2A2C = { + CreatedOnToolsVersion = 13.1; + }; + }; + }; + buildConfigurationList = 022B20832746AD37000F2A2C /* Build configuration list for PBXProject "GoogleMapsPlugin" */; + compatibilityVersion = "Xcode 13.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 022B207F2746AD37000F2A2C; + productRefGroup = 022B208A2746AD37000F2A2C /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 022B20882746AD37000F2A2C /* GoogleMapsPlugin */, + 022B20902746AD38000F2A2C /* GoogleMapsPluginTests */, + 022B20B82746B791000F2A2C /* TestApp */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 022B20872746AD37000F2A2C /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 022B208F2746AD38000F2A2C /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 022B20B72746B791000F2A2C /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 022B20C32746B793000F2A2C /* Preview Assets.xcassets in Resources */, + 022B20C02746B793000F2A2C /* Assets.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 022B20852746AD37000F2A2C /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 022B20B02746ADD7000F2A2C /* CapacitorGoogleMaps.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 022B208D2746AD38000F2A2C /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 022B20972746AD38000F2A2C /* GoogleMapsPluginTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 022B20B52746B791000F2A2C /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 022B20BE2746B791000F2A2C /* ContentView.swift in Sources */, + 022B20BC2746B791000F2A2C /* TestAppApp.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 022B20942746AD38000F2A2C /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 022B20882746AD37000F2A2C /* GoogleMapsPlugin */; + targetProxy = 022B20932746AD38000F2A2C /* PBXContainerItemProxy */; + }; + 022B20C92746B7FA000F2A2C /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 022B20B82746B791000F2A2C /* TestApp */; + targetProxy = 022B20C82746B7FA000F2A2C /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 022B20992746AD38000F2A2C /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 022B209A2746AD38000F2A2C /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 022B209C2746AD38000F2A2C /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = ""; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = io.ionic.GoogleMapsPlugin; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 022B209D2746AD38000F2A2C /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = ""; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = io.ionic.GoogleMapsPlugin; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; + 022B209F2746AD38000F2A2C /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = io.ionic.IdentityVaultNativeTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/TestApp.app/TestApp"; + }; + name = Debug; + }; + 022B20A02746AD38000F2A2C /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = io.ionic.IdentityVaultNativeTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/TestApp.app/TestApp"; + }; + name = Release; + }; + 022B20C52746B793000F2A2C /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_ENTITLEMENTS = TestApp/TestApp.entitlements; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_ASSET_PATHS = "\"TestApp/Preview Content\""; + ENABLE_PREVIEWS = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchScreen_Generation = YES; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = io.ionic.TestApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 022B20C62746B793000F2A2C /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_ENTITLEMENTS = TestApp/TestApp.entitlements; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_ASSET_PATHS = "\"TestApp/Preview Content\""; + ENABLE_PREVIEWS = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchScreen_Generation = YES; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = io.ionic.TestApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 022B20832746AD37000F2A2C /* Build configuration list for PBXProject "GoogleMapsPlugin" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 022B20992746AD38000F2A2C /* Debug */, + 022B209A2746AD38000F2A2C /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 022B209B2746AD38000F2A2C /* Build configuration list for PBXNativeTarget "GoogleMapsPlugin" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 022B209C2746AD38000F2A2C /* Debug */, + 022B209D2746AD38000F2A2C /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 022B209E2746AD38000F2A2C /* Build configuration list for PBXNativeTarget "GoogleMapsPluginTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 022B209F2746AD38000F2A2C /* Debug */, + 022B20A02746AD38000F2A2C /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 022B20C42746B793000F2A2C /* Build configuration list for PBXNativeTarget "TestApp" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 022B20C52746B793000F2A2C /* Debug */, + 022B20C62746B793000F2A2C /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 022B20802746AD37000F2A2C /* Project object */; +} diff --git a/google-maps/unit-tests/ios/GoogleMapsPlugin/GoogleMapsPlugin.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/google-maps/unit-tests/ios/GoogleMapsPlugin/GoogleMapsPlugin.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..989f75d9c --- /dev/null +++ b/google-maps/unit-tests/ios/GoogleMapsPlugin/GoogleMapsPlugin.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/google-maps/unit-tests/ios/GoogleMapsPlugin/GoogleMapsPlugin.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/google-maps/unit-tests/ios/GoogleMapsPlugin/GoogleMapsPlugin.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/google-maps/unit-tests/ios/GoogleMapsPlugin/GoogleMapsPlugin.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/google-maps/unit-tests/ios/GoogleMapsPlugin/GoogleMapsPluginTests/GoogleMapsPluginTests.swift b/google-maps/unit-tests/ios/GoogleMapsPlugin/GoogleMapsPluginTests/GoogleMapsPluginTests.swift new file mode 100644 index 000000000..034c8d71d --- /dev/null +++ b/google-maps/unit-tests/ios/GoogleMapsPlugin/GoogleMapsPluginTests/GoogleMapsPluginTests.swift @@ -0,0 +1,36 @@ +import XCTest +@testable import GoogleMapsPlugin + +class GoogleMapsPluginTests: XCTestCase { + var plugin: CapacitorGoogleMaps? + + override func setUpWithError() throws { + self.plugin = CapacitorGoogleMaps() + // Put setup code here. This method is called before the invocation of each test method in the class. + } + + override func tearDownWithError() throws { + // Put teardown code here. This method is called after the invocation of each test method in the class. + } + + func exampleTest() throws { + do { + if let plugin = self.plugin { + let value = try plugin.echo("Hello world!") + + XCTAssertEqual("Hello world!", value) + } + } catch { + print("Example Test Error \(error)") + XCTFail() + } + } + + func testPerformanceExample() throws { + // This is an example of a performance test case. + self.measure { + // Put the code you want to measure the time of here. + } + } + +} diff --git a/google-maps/unit-tests/ios/GoogleMapsPlugin/TestApp/Assets.xcassets/AccentColor.colorset/Contents.json b/google-maps/unit-tests/ios/GoogleMapsPlugin/TestApp/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 000000000..eb8789700 --- /dev/null +++ b/google-maps/unit-tests/ios/GoogleMapsPlugin/TestApp/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/google-maps/unit-tests/ios/GoogleMapsPlugin/TestApp/Assets.xcassets/AppIcon.appiconset/Contents.json b/google-maps/unit-tests/ios/GoogleMapsPlugin/TestApp/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 000000000..9221b9bb1 --- /dev/null +++ b/google-maps/unit-tests/ios/GoogleMapsPlugin/TestApp/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,98 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "20x20" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "20x20" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "40x40" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "40x40" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "60x60" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "60x60" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "20x20" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "20x20" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "29x29" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "29x29" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "40x40" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "40x40" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "76x76" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "76x76" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "83.5x83.5" + }, + { + "idiom" : "ios-marketing", + "scale" : "1x", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/google-maps/unit-tests/ios/GoogleMapsPlugin/TestApp/Assets.xcassets/Contents.json b/google-maps/unit-tests/ios/GoogleMapsPlugin/TestApp/Assets.xcassets/Contents.json new file mode 100644 index 000000000..73c00596a --- /dev/null +++ b/google-maps/unit-tests/ios/GoogleMapsPlugin/TestApp/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/google-maps/unit-tests/ios/GoogleMapsPlugin/TestApp/ContentView.swift b/google-maps/unit-tests/ios/GoogleMapsPlugin/TestApp/ContentView.swift new file mode 100644 index 000000000..6b8aa078f --- /dev/null +++ b/google-maps/unit-tests/ios/GoogleMapsPlugin/TestApp/ContentView.swift @@ -0,0 +1,21 @@ +// +// ContentView.swift +// TestApp +// +// Created by Joseph Pender on 11/18/21. +// + +import SwiftUI + +struct ContentView: View { + var body: some View { + Text("Hello, world!") + .padding() + } +} + +struct ContentView_Previews: PreviewProvider { + static var previews: some View { + ContentView() + } +} diff --git a/google-maps/unit-tests/ios/GoogleMapsPlugin/TestApp/Preview Content/Preview Assets.xcassets/Contents.json b/google-maps/unit-tests/ios/GoogleMapsPlugin/TestApp/Preview Content/Preview Assets.xcassets/Contents.json new file mode 100644 index 000000000..73c00596a --- /dev/null +++ b/google-maps/unit-tests/ios/GoogleMapsPlugin/TestApp/Preview Content/Preview Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/google-maps/unit-tests/ios/GoogleMapsPlugin/TestApp/TestApp.entitlements b/google-maps/unit-tests/ios/GoogleMapsPlugin/TestApp/TestApp.entitlements new file mode 100644 index 000000000..1c22eb380 --- /dev/null +++ b/google-maps/unit-tests/ios/GoogleMapsPlugin/TestApp/TestApp.entitlements @@ -0,0 +1,10 @@ + + + + + keychain-access-groups + + $(AppIdentifierPrefix)io.ionic.TestApp + + + diff --git a/google-maps/unit-tests/ios/GoogleMapsPlugin/TestApp/TestAppApp.swift b/google-maps/unit-tests/ios/GoogleMapsPlugin/TestApp/TestAppApp.swift new file mode 100644 index 000000000..ecd3f3b8d --- /dev/null +++ b/google-maps/unit-tests/ios/GoogleMapsPlugin/TestApp/TestAppApp.swift @@ -0,0 +1,17 @@ +// +// TestAppApp.swift +// TestApp +// +// Created by Joseph Pender on 11/18/21. +// + +import SwiftUI + +@main +struct TestAppApp: App { + var body: some Scene { + WindowGroup { + ContentView() + } + } +} diff --git a/haptics/CHANGELOG.md b/haptics/CHANGELOG.md index b4f7cd0ad..486e32d83 100644 --- a/haptics/CHANGELOG.md +++ b/haptics/CHANGELOG.md @@ -3,6 +3,88 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.1.0](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/haptics@1.1.4...@capacitor/haptics@4.1.0) (2022-11-16) + + + +## 4.0.1 (2022-07-28) + + + +# 4.0.0 (2022-07-27) + + + +# 4.0.0-beta.2 (2022-07-08) + + + +# 4.0.0-beta.0 (2022-06-27) + + +### Features + +* set targetSDK default value to 31 ([#824](https://github.com/ionic-team/capacitor-plugins/issues/824)) ([3ee10de](https://github.com/ionic-team/capacitor-plugins/commit/3ee10de98067984c1a4e75295d001c5a895c47f4)) +* set targetSDK default value to 32 ([#970](https://github.com/ionic-team/capacitor-plugins/issues/970)) ([fa70d96](https://github.com/ionic-team/capacitor-plugins/commit/fa70d96f141af751aae53ceb5642c46b204f5958)) +* Upgrade gradle to 7.4 ([#826](https://github.com/ionic-team/capacitor-plugins/issues/826)) ([5db0906](https://github.com/ionic-team/capacitor-plugins/commit/5db0906f6264287c4f8e69dbaecf19d4d387824b)) +* Use java 11 ([#910](https://github.com/ionic-team/capacitor-plugins/issues/910)) ([5acb2a2](https://github.com/ionic-team/capacitor-plugins/commit/5acb2a288a413492b163e4e97da46a085d9e4be0)) + + + + + +## [4.0.1](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0...4.0.1) (2022-07-28) + +**Note:** Version bump only for package @capacitor/haptics + + + + + +# [4.0.0](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0-beta.2...4.0.0) (2022-07-27) + +**Note:** Version bump only for package @capacitor/haptics + + + + + +# [4.0.0-beta.2](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0-beta.0...4.0.0-beta.2) (2022-07-08) + +**Note:** Version bump only for package @capacitor/haptics + + + + + +# 4.0.0-beta.0 (2022-06-27) + + +### Bug Fixes + +* add es2017 lib to tsconfig ([#180](https://github.com/ionic-team/capacitor-plugins/issues/180)) ([2c3776c](https://github.com/ionic-team/capacitor-plugins/commit/2c3776c38ca025c5ee965dec10ccf1cdb6c02e2f)) +* better ignore rules for npm distribution ([#32](https://github.com/ionic-team/capacitor-plugins/issues/32)) ([b8d55b9](https://github.com/ionic-team/capacitor-plugins/commit/b8d55b9233e4ad7b8a1cd41110b4e580fc2a059f)) +* correct addListeners links ([#655](https://github.com/ionic-team/capacitor-plugins/issues/655)) ([f9871e7](https://github.com/ionic-team/capacitor-plugins/commit/f9871e7bd53478addb21155e148829f550c0e457)) +* inline source code in esm map files ([#760](https://github.com/ionic-team/capacitor-plugins/issues/760)) ([a960489](https://github.com/ionic-team/capacitor-plugins/commit/a960489a19db0182b90d187a50deff9dfbe51038)) +* remove postpublish scripts ([#656](https://github.com/ionic-team/capacitor-plugins/issues/656)) ([ed6ac49](https://github.com/ionic-team/capacitor-plugins/commit/ed6ac499ebf4a47525071ccbfc36c27503e11f60)) +* support deprecated types from Capacitor 2 ([#139](https://github.com/ionic-team/capacitor-plugins/issues/139)) ([2d7127a](https://github.com/ionic-team/capacitor-plugins/commit/2d7127a488e26f0287951921a6db47c49d817336)) +* use correct package in manifest files ([#22](https://github.com/ionic-team/capacitor-plugins/issues/22)) ([ab62987](https://github.com/ionic-team/capacitor-plugins/commit/ab629877e1951f944594f1b23e1bffefcbc783dd)) + + +### Features + +* add commonjs output format ([#179](https://github.com/ionic-team/capacitor-plugins/issues/179)) ([8e9e098](https://github.com/ionic-team/capacitor-plugins/commit/8e9e09862064b3f6771d7facbc4008e995d9b463)) +* Haptics plugin ([#5](https://github.com/ionic-team/capacitor-plugins/issues/5)) ([95322d3](https://github.com/ionic-team/capacitor-plugins/commit/95322d385c855cff50582a7d3daff83fe4fe9e90)) +* set targetSDK default value to 31 ([#824](https://github.com/ionic-team/capacitor-plugins/issues/824)) ([3ee10de](https://github.com/ionic-team/capacitor-plugins/commit/3ee10de98067984c1a4e75295d001c5a895c47f4)) +* set targetSDK default value to 32 ([#970](https://github.com/ionic-team/capacitor-plugins/issues/970)) ([fa70d96](https://github.com/ionic-team/capacitor-plugins/commit/fa70d96f141af751aae53ceb5642c46b204f5958)) +* Upgrade gradle to 7.4 ([#826](https://github.com/ionic-team/capacitor-plugins/issues/826)) ([5db0906](https://github.com/ionic-team/capacitor-plugins/commit/5db0906f6264287c4f8e69dbaecf19d4d387824b)) +* Use java 11 ([#910](https://github.com/ionic-team/capacitor-plugins/issues/910)) ([5acb2a2](https://github.com/ionic-team/capacitor-plugins/commit/5acb2a288a413492b163e4e97da46a085d9e4be0)) +* **haptics:** Implement duration for vibration ([#618](https://github.com/ionic-team/capacitor-plugins/issues/618)) ([78e6b68](https://github.com/ionic-team/capacitor-plugins/commit/78e6b6886fa50318b1bfbe229e7318e521e3c245)) + + + + + ## [1.1.4](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/haptics@1.1.3...@capacitor/haptics@1.1.4) (2022-01-19) diff --git a/haptics/CapacitorHaptics.podspec b/haptics/CapacitorHaptics.podspec index e653ec4d1..4b5032055 100644 --- a/haptics/CapacitorHaptics.podspec +++ b/haptics/CapacitorHaptics.podspec @@ -11,7 +11,7 @@ Pod::Spec.new do |s| s.author = package['author'] s.source = { :git => 'https://github.com/ionic-team/capacitor-plugins.git', :tag => package['name'] + '@' + package['version'] } s.source_files = 'ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}', 'haptics/ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}' - s.ios.deployment_target = '12.0' + s.ios.deployment_target = '13.0' s.dependency 'Capacitor' s.swift_version = '5.1' end diff --git a/haptics/README.md b/haptics/README.md index f9aea21ab..fa9ffb729 100644 --- a/haptics/README.md +++ b/haptics/README.md @@ -171,9 +171,9 @@ For example, call this when a user has lifted their finger from a control #### VibrateOptions -| Prop | Type | Description | Default | Since | -| -------------- | ------------------- | ----------------------------------------------------------------------------- | ---------------- | ----- | -| **`duration`** | number | Duration of the vibration in milliseconds. Not supported in iOS 12 and older. | 300 | 1.0.0 | +| Prop | Type | Description | Default | Since | +| -------------- | ------------------- | ------------------------------------------ | ---------------- | ----- | +| **`duration`** | number | Duration of the vibration in milliseconds. | 300 | 1.0.0 | ### Enums diff --git a/haptics/android/build.gradle b/haptics/android/build.gradle index 56ee0b28b..43252f49c 100644 --- a/haptics/android/build.gradle +++ b/haptics/android/build.gradle @@ -1,27 +1,39 @@ ext { - junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.1' - androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.2.0' - androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.1.2' - androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.3.0' + capacitorVersion = System.getenv('CAPACITOR_VERSION') + junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.2' + androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.4.2' + androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.1.3' + androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.4.0' } buildscript { repositories { google() mavenCentral() + maven { + url "https://plugins.gradle.org/m2/" + } } dependencies { - classpath 'com.android.tools.build:gradle:4.2.1' + classpath 'com.android.tools.build:gradle:7.2.1' + if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + classpath 'io.github.gradle-nexus:publish-plugin:1.1.0' + } } } apply plugin: 'com.android.library' +if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + apply plugin: 'io.github.gradle-nexus.publish-plugin' + apply from: file('../../scripts/android/publish-root.gradle') + apply from: file('../../scripts/android/publish-module.gradle') +} android { - compileSdkVersion project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 30 + compileSdkVersion project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 32 defaultConfig { - minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 21 - targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 30 + minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 22 + targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 32 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" @@ -36,21 +48,26 @@ android { abortOnError false } compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility JavaVersion.VERSION_11 + targetCompatibility JavaVersion.VERSION_11 } } repositories { google() mavenCentral() - jcenter() } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation project(':capacitor-android') + + if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + implementation "com.capacitorjs:core:$capacitorVersion" + } else { + implementation project(':capacitor-android') + } + implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion" testImplementation "junit:junit:$junitVersion" androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion" diff --git a/haptics/android/gradle/wrapper/gradle-wrapper.jar b/haptics/android/gradle/wrapper/gradle-wrapper.jar index e708b1c02..41d9927a4 100644 Binary files a/haptics/android/gradle/wrapper/gradle-wrapper.jar and b/haptics/android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/haptics/android/gradle/wrapper/gradle-wrapper.properties b/haptics/android/gradle/wrapper/gradle-wrapper.properties index 3c4101c3e..92f06b50f 100644 --- a/haptics/android/gradle/wrapper/gradle-wrapper.properties +++ b/haptics/android/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/haptics/android/gradlew b/haptics/android/gradlew index 4f906e0c8..1b6c78733 100755 --- a/haptics/android/gradlew +++ b/haptics/android/gradlew @@ -1,7 +1,7 @@ -#!/usr/bin/env sh +#!/bin/sh # -# Copyright 2015 the original author or authors. +# Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,67 +17,101 @@ # ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` +APP_BASE_NAME=${0##*/} # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar @@ -87,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -98,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" + JAVACMD=java which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the @@ -106,80 +140,95 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=`expr $i + 1` + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" diff --git a/haptics/android/src/main/java/com/capacitorjs/plugins/haptics/Haptics.java b/haptics/android/src/main/java/com/capacitorjs/plugins/haptics/Haptics.java index d5f3373ef..e9f182e68 100644 --- a/haptics/android/src/main/java/com/capacitorjs/plugins/haptics/Haptics.java +++ b/haptics/android/src/main/java/com/capacitorjs/plugins/haptics/Haptics.java @@ -4,6 +4,7 @@ import android.os.Build; import android.os.VibrationEffect; import android.os.Vibrator; +import android.os.VibratorManager; import com.capacitorjs.plugins.haptics.arguments.HapticsSelectionType; import com.capacitorjs.plugins.haptics.arguments.HapticsVibrationType; @@ -15,11 +16,21 @@ public class Haptics { Haptics(Context context) { this.context = context; - this.vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + VibratorManager vibratorManager = (VibratorManager) context.getSystemService(Context.VIBRATOR_MANAGER_SERVICE); + this.vibrator = vibratorManager.getDefaultVibrator(); + } else { + this.vibrator = getDeprecatedVibrator(context); + } + } + + @SuppressWarnings("deprecation") + private Vibrator getDeprecatedVibrator(Context context) { + return (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE); } public void vibrate(int duration) { - if (Build.VERSION.SDK_INT >= 26) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { vibrator.vibrate(VibrationEffect.createOneShot(duration, VibrationEffect.DEFAULT_AMPLITUDE)); } else { vibratePre26(duration); @@ -51,7 +62,7 @@ public void selectionEnd() { } public void performHaptics(HapticsVibrationType type) { - if (Build.VERSION.SDK_INT >= 26) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { vibrator.vibrate(VibrationEffect.createWaveform(type.getTimings(), type.getAmplitudes(), -1)); } else { vibratePre26(type.getOldSDKPattern(), -1); diff --git a/haptics/ios/Plugin.xcodeproj/project.pbxproj b/haptics/ios/Plugin.xcodeproj/project.pbxproj index da5f21387..96d1a22da 100644 --- a/haptics/ios/Plugin.xcodeproj/project.pbxproj +++ b/haptics/ios/Plugin.xcodeproj/project.pbxproj @@ -386,7 +386,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -446,7 +446,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; @@ -469,12 +469,13 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Plugin/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks $(FRAMEWORK_SEARCH_PATHS)\n$(FRAMEWORK_SEARCH_PATHS)\n$(FRAMEWORK_SEARCH_PATHS)"; ONLY_ACTIVE_ARCH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.getcapacitor.Plugin; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; + SUPPORTS_MACCATALYST = NO; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -494,12 +495,13 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Plugin/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks $(FRAMEWORK_SEARCH_PATHS)"; ONLY_ACTIVE_ARCH = NO; PRODUCT_BUNDLE_IDENTIFIER = com.getcapacitor.Plugin; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; + SUPPORTS_MACCATALYST = NO; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; diff --git a/haptics/ios/Plugin/Haptics.swift b/haptics/ios/Plugin/Haptics.swift index 55496563a..97ad97d8a 100644 --- a/haptics/ios/Plugin/Haptics.swift +++ b/haptics/ios/Plugin/Haptics.swift @@ -37,33 +37,29 @@ import CoreHaptics } @objc public func vibrate(_ duration: Double) { - if #available(iOS 13, *) { - if CHHapticEngine.capabilitiesForHardware().supportsHaptics { - do { - let engine = try CHHapticEngine() - try engine.start() - engine.resetHandler = { [] in - do { - try engine.start() - } catch { - self.vibrate() - } + if CHHapticEngine.capabilitiesForHardware().supportsHaptics { + do { + let engine = try CHHapticEngine() + try engine.start() + engine.resetHandler = { [] in + do { + try engine.start() + } catch { + self.vibrate() } - let intensity = CHHapticEventParameter(parameterID: .hapticIntensity, value: 1.0) - let sharpness = CHHapticEventParameter(parameterID: .hapticSharpness, value: 1.0) + } + let intensity = CHHapticEventParameter(parameterID: .hapticIntensity, value: 1.0) + let sharpness = CHHapticEventParameter(parameterID: .hapticSharpness, value: 1.0) - let continuousEvent = CHHapticEvent(eventType: .hapticContinuous, - parameters: [intensity, sharpness], - relativeTime: 0.0, - duration: duration) - let pattern = try CHHapticPattern(events: [continuousEvent], parameters: []) - let player = try engine.makePlayer(with: pattern) + let continuousEvent = CHHapticEvent(eventType: .hapticContinuous, + parameters: [intensity, sharpness], + relativeTime: 0.0, + duration: duration) + let pattern = try CHHapticPattern(events: [continuousEvent], parameters: []) + let player = try engine.makePlayer(with: pattern) - try player.start(atTime: 0) - } catch { - vibrate() - } - } else { + try player.start(atTime: 0) + } catch { vibrate() } } else { diff --git a/haptics/ios/Podfile b/haptics/ios/Podfile index 54a00c161..dee40960f 100644 --- a/haptics/ios/Podfile +++ b/haptics/ios/Podfile @@ -1,4 +1,4 @@ -platform :ios, '12.0' +platform :ios, '13.0' def capacitor_pods # Comment the next line if you're not using Swift and don't want to use dynamic frameworks diff --git a/haptics/package.json b/haptics/package.json index f005c32eb..b626ecc13 100644 --- a/haptics/package.json +++ b/haptics/package.json @@ -1,6 +1,6 @@ { "name": "@capacitor/haptics", - "version": "1.1.4", + "version": "4.1.0", "description": "The Haptics API provides physical feedback to the user through touch or vibration.", "main": "dist/plugin.cjs.js", "module": "dist/esm/index.js", @@ -29,7 +29,7 @@ ], "scripts": { "verify": "npm run verify:ios && npm run verify:android && npm run verify:web", - "verify:ios": "cd ios && pod install && xcodebuild -workspace Plugin.xcworkspace -scheme Plugin && cd ..", + "verify:ios": "cd ios && pod install && xcodebuild -workspace Plugin.xcworkspace -scheme Plugin -destination generic/platform=iOS && cd ..", "verify:android": "cd android && ./gradlew clean build test && cd ..", "verify:web": "npm run build", "lint": "npm run eslint && npm run prettier -- --check && npm run swiftlint -- lint", @@ -45,10 +45,10 @@ "publish:cocoapod": "pod trunk push ./CapacitorHaptics.podspec --allow-warnings" }, "devDependencies": { - "@capacitor/android": "^3.0.0", - "@capacitor/core": "^3.0.0", - "@capacitor/docgen": "0.0.18", - "@capacitor/ios": "^3.0.0", + "@capacitor/android": "^4.0.0", + "@capacitor/core": "^4.0.0", + "@capacitor/docgen": "0.2.0", + "@capacitor/ios": "^4.0.0", "@ionic/eslint-config": "^0.3.0", "@ionic/prettier-config": "~1.0.1", "@ionic/swiftlint-config": "^1.1.2", @@ -61,7 +61,7 @@ "typescript": "~4.1.5" }, "peerDependencies": { - "@capacitor/core": "^3.0.0" + "@capacitor/core": "^4.0.0" }, "prettier": "@ionic/prettier-config", "swiftlint": "@ionic/swiftlint-config", diff --git a/haptics/src/definitions.ts b/haptics/src/definitions.ts index f361012ae..01389a6d6 100644 --- a/haptics/src/definitions.ts +++ b/haptics/src/definitions.ts @@ -119,8 +119,6 @@ export interface VibrateOptions { /** * Duration of the vibration in milliseconds. * - * Not supported in iOS 12 and older. - * * @default 300 * @since 1.0.0 */ diff --git a/keyboard/CHANGELOG.md b/keyboard/CHANGELOG.md index 85392209d..31d05ba3d 100644 --- a/keyboard/CHANGELOG.md +++ b/keyboard/CHANGELOG.md @@ -3,6 +3,131 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.1.0](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/keyboard@1.2.3...@capacitor/keyboard@4.1.0) (2022-11-16) + + + +## 4.0.1 (2022-07-28) + + + +# 4.0.0 (2022-07-27) + + +### Features + +* **keyboard:** add getResizeMode function ([#1082](https://github.com/ionic-team/capacitor-plugins/issues/1082)) ([594d854](https://github.com/ionic-team/capacitor-plugins/commit/594d8545fa1560c2d518d0eff30e2702f1b90a45)) + + + +# 4.0.0-beta.2 (2022-07-08) + + + +# 4.0.0-beta.0 (2022-06-27) + + +### Bug Fixes + +* Make removeAllListeners return a promise ([#895](https://github.com/ionic-team/capacitor-plugins/issues/895)) ([e5c49d6](https://github.com/ionic-team/capacitor-plugins/commit/e5c49d64445dca70286334e6a0441d8021197b13)) + + +### Features + +* set targetSDK default value to 32 ([#970](https://github.com/ionic-team/capacitor-plugins/issues/970)) ([fa70d96](https://github.com/ionic-team/capacitor-plugins/commit/fa70d96f141af751aae53ceb5642c46b204f5958)) +* **keyboard:** Use KeyboardStyle for style config option ([#969](https://github.com/ionic-team/capacitor-plugins/issues/969)) ([42a01b4](https://github.com/ionic-team/capacitor-plugins/commit/42a01b46d5a9e39bfb3ac05d5595aecaeb790557)) +* set targetSDK default value to 31 ([#824](https://github.com/ionic-team/capacitor-plugins/issues/824)) ([3ee10de](https://github.com/ionic-team/capacitor-plugins/commit/3ee10de98067984c1a4e75295d001c5a895c47f4)) +* Upgrade gradle to 7.4 ([#826](https://github.com/ionic-team/capacitor-plugins/issues/826)) ([5db0906](https://github.com/ionic-team/capacitor-plugins/commit/5db0906f6264287c4f8e69dbaecf19d4d387824b)) +* Use java 11 ([#910](https://github.com/ionic-team/capacitor-plugins/issues/910)) ([5acb2a2](https://github.com/ionic-team/capacitor-plugins/commit/5acb2a288a413492b163e4e97da46a085d9e4be0)) + + + + + +## [4.0.1](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0...4.0.1) (2022-07-28) + +**Note:** Version bump only for package @capacitor/keyboard + + + + + +# [4.0.0](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0-beta.2...4.0.0) (2022-07-27) + + +### Features + +* **keyboard:** add getResizeMode function ([#1082](https://github.com/ionic-team/capacitor-plugins/issues/1082)) ([594d854](https://github.com/ionic-team/capacitor-plugins/commit/594d8545fa1560c2d518d0eff30e2702f1b90a45)) + + + + + +# [4.0.0-beta.2](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0-beta.0...4.0.0-beta.2) (2022-07-08) + +**Note:** Version bump only for package @capacitor/keyboard + + + + + +# 4.0.0-beta.0 (2022-06-27) + + +### Bug Fixes + +* **ios:** Check if UIApplicationDelegate responds to window selector ([#1032](https://github.com/ionic-team/capacitor-plugins/issues/1032)) ([5be1466](https://github.com/ionic-team/capacitor-plugins/commit/5be14662181305e48bc097ade6504c579880bda8)) +* add es2017 lib to tsconfig ([#180](https://github.com/ionic-team/capacitor-plugins/issues/180)) ([2c3776c](https://github.com/ionic-team/capacitor-plugins/commit/2c3776c38ca025c5ee965dec10ccf1cdb6c02e2f)) +* Make removeAllListeners return a promise ([#895](https://github.com/ionic-team/capacitor-plugins/issues/895)) ([e5c49d6](https://github.com/ionic-team/capacitor-plugins/commit/e5c49d64445dca70286334e6a0441d8021197b13)) +* **keyboard:** Prevent null pointer if native listener not set ([#789](https://github.com/ionic-team/capacitor-plugins/issues/789)) ([8b6f119](https://github.com/ionic-team/capacitor-plugins/commit/8b6f119ad5143d380aa9ebd7c73b701ad5a1f10a)) +* correct addListeners links ([#655](https://github.com/ionic-team/capacitor-plugins/issues/655)) ([f9871e7](https://github.com/ionic-team/capacitor-plugins/commit/f9871e7bd53478addb21155e148829f550c0e457)) +* inline source code in esm map files ([#760](https://github.com/ionic-team/capacitor-plugins/issues/760)) ([a960489](https://github.com/ionic-team/capacitor-plugins/commit/a960489a19db0182b90d187a50deff9dfbe51038)) +* remove postpublish scripts ([#656](https://github.com/ionic-team/capacitor-plugins/issues/656)) ([ed6ac49](https://github.com/ionic-team/capacitor-plugins/commit/ed6ac499ebf4a47525071ccbfc36c27503e11f60)) +* **keyboard:** remove deprecated warnings ([#122](https://github.com/ionic-team/capacitor-plugins/issues/122)) ([a6e207c](https://github.com/ionic-team/capacitor-plugins/commit/a6e207c47dfac14d6cbcaa2a942b7b04cae3dae8)) +* **keyboard:** Use new Config name for scroll ([#335](https://github.com/ionic-team/capacitor-plugins/issues/335)) ([bec3d22](https://github.com/ionic-team/capacitor-plugins/commit/bec3d22e67dfb22db5b5bb774f53fb01a34f116f)) +* support deprecated types from Capacitor 2 ([#139](https://github.com/ionic-team/capacitor-plugins/issues/139)) ([2d7127a](https://github.com/ionic-team/capacitor-plugins/commit/2d7127a488e26f0287951921a6db47c49d817336)) + + +### Features + +* set targetSDK default value to 32 ([#970](https://github.com/ionic-team/capacitor-plugins/issues/970)) ([fa70d96](https://github.com/ionic-team/capacitor-plugins/commit/fa70d96f141af751aae53ceb5642c46b204f5958)) +* **keyboard:** Use KeyboardStyle for style config option ([#969](https://github.com/ionic-team/capacitor-plugins/issues/969)) ([42a01b4](https://github.com/ionic-team/capacitor-plugins/commit/42a01b46d5a9e39bfb3ac05d5595aecaeb790557)) +* add commonjs output format ([#179](https://github.com/ionic-team/capacitor-plugins/issues/179)) ([8e9e098](https://github.com/ionic-team/capacitor-plugins/commit/8e9e09862064b3f6771d7facbc4008e995d9b463)) +* Keyboard plugin ([#59](https://github.com/ionic-team/capacitor-plugins/issues/59)) ([3a65a9a](https://github.com/ionic-team/capacitor-plugins/commit/3a65a9a9757a34c3cd803da7479b9403d8689511)) +* set targetSDK default value to 31 ([#824](https://github.com/ionic-team/capacitor-plugins/issues/824)) ([3ee10de](https://github.com/ionic-team/capacitor-plugins/commit/3ee10de98067984c1a4e75295d001c5a895c47f4)) +* Upgrade gradle to 7.4 ([#826](https://github.com/ionic-team/capacitor-plugins/issues/826)) ([5db0906](https://github.com/ionic-team/capacitor-plugins/commit/5db0906f6264287c4f8e69dbaecf19d4d387824b)) +* Use java 11 ([#910](https://github.com/ionic-team/capacitor-plugins/issues/910)) ([5acb2a2](https://github.com/ionic-team/capacitor-plugins/commit/5acb2a288a413492b163e4e97da46a085d9e4be0)) +* **keyboard:** Add default style option for setStyle ([#334](https://github.com/ionic-team/capacitor-plugins/issues/334)) ([9dbb809](https://github.com/ionic-team/capacitor-plugins/commit/9dbb809ce3219d517e62b235406d2b798c95425c)) +* **keyboard:** add types for config files ([#115](https://github.com/ionic-team/capacitor-plugins/issues/115)) ([09bba16](https://github.com/ionic-team/capacitor-plugins/commit/09bba168242c26b3816ab5ff5b15f22531935fec)) +* **keyboard:** Make resize work in apps that use scenes ([#729](https://github.com/ionic-team/capacitor-plugins/issues/729)) ([6dde082](https://github.com/ionic-team/capacitor-plugins/commit/6dde082d1683daa923e6f42678785bc679f63b02)) +* **Keyboard:** Add resizeOnFullScreen plugin configuration ([#627](https://github.com/ionic-team/capacitor-plugins/issues/627)) ([8e87836](https://github.com/ionic-team/capacitor-plugins/commit/8e8783622d6e77c38c4aa741a622455302f30486)) + + + + + +## [1.2.3](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/keyboard@1.2.2...@capacitor/keyboard@1.2.3) (2022-06-17) + + +### Bug Fixes + +* **ios:** Check if UIApplicationDelegate responds to window selector ([#1032](https://github.com/ionic-team/capacitor-plugins/issues/1032)) ([5be1466](https://github.com/ionic-team/capacitor-plugins/commit/5be14662181305e48bc097ade6504c579880bda8)) + + + + + +## [1.2.2](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/keyboard@1.2.1...@capacitor/keyboard@1.2.2) (2022-02-10) + + +### Bug Fixes + +* **keyboard:** Prevent null pointer if native listener not set ([#789](https://github.com/ionic-team/capacitor-plugins/issues/789)) ([8b6f119](https://github.com/ionic-team/capacitor-plugins/commit/8b6f119ad5143d380aa9ebd7c73b701ad5a1f10a)) + + + + + ## [1.2.1](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/keyboard@1.2.0...@capacitor/keyboard@1.2.1) (2022-01-19) diff --git a/keyboard/CapacitorKeyboard.podspec b/keyboard/CapacitorKeyboard.podspec index 14c1e4d97..ef62c3c90 100644 --- a/keyboard/CapacitorKeyboard.podspec +++ b/keyboard/CapacitorKeyboard.podspec @@ -11,7 +11,7 @@ Pod::Spec.new do |s| s.author = package['author'] s.source = { :git => 'https://github.com/ionic-team/capacitor-plugins.git', :tag => package['name'] + '@' + package['version'] } s.source_files = 'ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}', 'keyboard/ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}' - s.ios.deployment_target = '12.0' + s.ios.deployment_target = '13.0' s.dependency 'Capacitor' s.swift_version = '5.1' end diff --git a/keyboard/README.md b/keyboard/README.md index f74134521..b02d6a446 100644 --- a/keyboard/README.md +++ b/keyboard/README.md @@ -33,15 +33,12 @@ Keyboard.addListener('keyboardDidHide', () => { ## Configuration - - - On iOS, the keyboard can be configured with the following options: | Prop | Type | Description | Default | Since | | ------------------------ | --------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------- | ----- | | **`resize`** | KeyboardResize | Configure the way the app is resized when the Keyboard appears. Only available on iOS. | native | 1.0.0 | -| **`style`** | 'dark' \| 'light' | Override the keyboard style if your app doesn't support dark/light theme changes. If not set, the keyboard style will depend on the device appearance. Only available on iOS. | | 1.0.0 | +| **`style`** | KeyboardStyle | Override the keyboard style if your app doesn't support dark/light theme changes. If not set, the keyboard style will depend on the device appearance. Only available on iOS. | | 1.0.0 | | **`resizeOnFullScreen`** | boolean | There is an Android bug that prevents the keyboard from resizing the WebView when the app is in full screen (i.e. if StatusBar plugin is used to overlay the status bar). This setting, if set to true, add a workaround that resizes the WebView even when the app is in full screen. Only available for Android | | 1.1.0 | ### Examples @@ -53,7 +50,7 @@ In `capacitor.config.json`: "plugins": { "Keyboard": { "resize": "body", - "style": "dark", + "style": "DARK", "resizeOnFullScreen": true } } @@ -66,12 +63,13 @@ In `capacitor.config.ts`: /// import { CapacitorConfig } from '@capacitor/cli'; +import { KeyboardResize, KeyboardStyle } from '@capacitor/keyboard'; const config: CapacitorConfig = { plugins: { Keyboard: { - resize: "body", - style: "dark", + resize: KeyboardResize.Body, + style: KeyboardStyle.Dark, resizeOnFullScreen: true, }, }, @@ -80,8 +78,6 @@ const config: CapacitorConfig = { export default config; ``` - - ## Compatibility with `cordova-plugin-ionic-keyboard` To maintain compatibility with @@ -103,6 +99,7 @@ the following events also work with `window.addEventListener`: * [`setScroll(...)`](#setscroll) * [`setStyle(...)`](#setstyle) * [`setResizeMode(...)`](#setresizemode) +* [`getResizeMode()`](#getresizemode) * [`addListener('keyboardWillShow', ...)`](#addlistenerkeyboardwillshow) * [`addListener('keyboardDidShow', ...)`](#addlistenerkeyboarddidshow) * [`addListener('keyboardWillHide', ...)`](#addlistenerkeyboardwillhide) @@ -221,6 +218,23 @@ This method is only supported on iOS. -------------------- +### getResizeMode() + +```typescript +getResizeMode() => Promise +``` + +Get the currently set resize mode. + +This method is only supported on iOS. + +**Returns:** Promise<KeyboardResizeOptions> + +**Since:** 4.0.0 + +-------------------- + + ### addListener('keyboardWillShow', ...) ```typescript diff --git a/keyboard/android/build.gradle b/keyboard/android/build.gradle index 56ee0b28b..43252f49c 100644 --- a/keyboard/android/build.gradle +++ b/keyboard/android/build.gradle @@ -1,27 +1,39 @@ ext { - junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.1' - androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.2.0' - androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.1.2' - androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.3.0' + capacitorVersion = System.getenv('CAPACITOR_VERSION') + junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.2' + androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.4.2' + androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.1.3' + androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.4.0' } buildscript { repositories { google() mavenCentral() + maven { + url "https://plugins.gradle.org/m2/" + } } dependencies { - classpath 'com.android.tools.build:gradle:4.2.1' + classpath 'com.android.tools.build:gradle:7.2.1' + if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + classpath 'io.github.gradle-nexus:publish-plugin:1.1.0' + } } } apply plugin: 'com.android.library' +if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + apply plugin: 'io.github.gradle-nexus.publish-plugin' + apply from: file('../../scripts/android/publish-root.gradle') + apply from: file('../../scripts/android/publish-module.gradle') +} android { - compileSdkVersion project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 30 + compileSdkVersion project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 32 defaultConfig { - minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 21 - targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 30 + minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 22 + targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 32 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" @@ -36,21 +48,26 @@ android { abortOnError false } compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility JavaVersion.VERSION_11 + targetCompatibility JavaVersion.VERSION_11 } } repositories { google() mavenCentral() - jcenter() } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation project(':capacitor-android') + + if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + implementation "com.capacitorjs:core:$capacitorVersion" + } else { + implementation project(':capacitor-android') + } + implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion" testImplementation "junit:junit:$junitVersion" androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion" diff --git a/keyboard/android/gradle/wrapper/gradle-wrapper.jar b/keyboard/android/gradle/wrapper/gradle-wrapper.jar index e708b1c02..41d9927a4 100644 Binary files a/keyboard/android/gradle/wrapper/gradle-wrapper.jar and b/keyboard/android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/keyboard/android/gradle/wrapper/gradle-wrapper.properties b/keyboard/android/gradle/wrapper/gradle-wrapper.properties index 3c4101c3e..92f06b50f 100644 --- a/keyboard/android/gradle/wrapper/gradle-wrapper.properties +++ b/keyboard/android/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/keyboard/android/gradlew b/keyboard/android/gradlew index 4f906e0c8..1b6c78733 100755 --- a/keyboard/android/gradlew +++ b/keyboard/android/gradlew @@ -1,7 +1,7 @@ -#!/usr/bin/env sh +#!/bin/sh # -# Copyright 2015 the original author or authors. +# Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,67 +17,101 @@ # ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` +APP_BASE_NAME=${0##*/} # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar @@ -87,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -98,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" + JAVACMD=java which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the @@ -106,80 +140,95 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=`expr $i + 1` + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" diff --git a/keyboard/android/src/main/java/com/capacitorjs/plugins/keyboard/Keyboard.java b/keyboard/android/src/main/java/com/capacitorjs/plugins/keyboard/Keyboard.java index 9394e19b5..983fdb95a 100644 --- a/keyboard/android/src/main/java/com/capacitorjs/plugins/keyboard/Keyboard.java +++ b/keyboard/android/src/main/java/com/capacitorjs/plugins/keyboard/Keyboard.java @@ -1,6 +1,7 @@ package com.capacitorjs.plugins.keyboard; import android.content.Context; +import android.graphics.Insets; import android.graphics.Point; import android.graphics.Rect; import android.os.Build; @@ -14,6 +15,7 @@ import android.widget.FrameLayout; import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; +import com.getcapacitor.Logger; public class Keyboard { @@ -45,21 +47,11 @@ public void setKeyboardEventListener(@Nullable KeyboardEventListener keyboardEve static final String EVENT_KB_WILL_HIDE = "keyboardWillHide"; static final String EVENT_KB_DID_HIDE = "keyboardDidHide"; - /** - * @deprecated - * Use {@link #Keyboard(AppCompatActivity activity, boolean resizeFullScreen)} - * @param activity - */ - public Keyboard(AppCompatActivity activity) { - this(activity, false); - } - public Keyboard(AppCompatActivity activity, boolean resizeOnFullScreen) { this.activity = activity; //calculate density-independent pixels (dp) //http://developer.android.com/guide/practices/screens_support.html - DisplayMetrics dm = new DisplayMetrics(); - activity.getWindowManager().getDefaultDisplay().getMetrics(dm); + DisplayMetrics dm = activity.getResources().getDisplayMetrics(); final float density = dm.density; //http://stackoverflow.com/a/4737265/1091751 detect if keyboard is showing @@ -83,29 +75,33 @@ public void onGlobalLayout() { int resultBottom = r.bottom; int screenHeight; - if (Build.VERSION.SDK_INT >= 23) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + Insets windowInsets = rootView.getRootWindowInsets().getInsetsIgnoringVisibility(WindowInsets.Type.systemBars()); + screenHeight = rootViewHeight; + resultBottom = resultBottom + windowInsets.bottom; + } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { WindowInsets windowInsets = rootView.getRootWindowInsets(); - int stableInsetBottom = windowInsets.getStableInsetBottom(); + int stableInsetBottom = getLegacyStableInsetBottom(windowInsets); screenHeight = rootViewHeight; resultBottom = resultBottom + stableInsetBottom; } else { - // calculate screen height differently for android versions <23: Lollipop 5.x, Marshmallow 6.x - //http://stackoverflow.com/a/29257533/3642890 beware of nexus 5 - Display display = activity.getWindowManager().getDefaultDisplay(); - Point size = new Point(); - display.getSize(size); + Point size = getLegacySizePoint(); screenHeight = size.y; } int heightDiff = screenHeight - resultBottom; int pixelHeightDiff = (int) (heightDiff / density); - if (pixelHeightDiff > 100 && pixelHeightDiff != previousHeightDiff) { // if more than 100 pixels, its probably a keyboard... - keyboardEventListener.onKeyboardEvent(EVENT_KB_WILL_SHOW, pixelHeightDiff); - keyboardEventListener.onKeyboardEvent(EVENT_KB_DID_SHOW, pixelHeightDiff); - } else if (pixelHeightDiff != previousHeightDiff && (previousHeightDiff - pixelHeightDiff) > 100) { - keyboardEventListener.onKeyboardEvent(EVENT_KB_WILL_HIDE, 0); - keyboardEventListener.onKeyboardEvent(EVENT_KB_DID_HIDE, 0); + if (keyboardEventListener != null) { + if (pixelHeightDiff > 100 && pixelHeightDiff != previousHeightDiff) { // if more than 100 pixels, its probably a keyboard... + keyboardEventListener.onKeyboardEvent(EVENT_KB_WILL_SHOW, pixelHeightDiff); + keyboardEventListener.onKeyboardEvent(EVENT_KB_DID_SHOW, pixelHeightDiff); + } else if (pixelHeightDiff != previousHeightDiff && (previousHeightDiff - pixelHeightDiff) > 100) { + keyboardEventListener.onKeyboardEvent(EVENT_KB_WILL_HIDE, 0); + keyboardEventListener.onKeyboardEvent(EVENT_KB_DID_HIDE, 0); + } + } else { + Logger.warn("Native Keyboard Event Listener not found"); } previousHeightDiff = pixelHeightDiff; } @@ -125,6 +121,7 @@ private int computeUsableHeight() { return isOverlays() ? r.bottom : r.height(); } + @SuppressWarnings("deprecation") private boolean isOverlays() { final Window window = activity.getWindow(); return ( @@ -138,11 +135,23 @@ private boolean isOverlays() { frameLayoutParams = (FrameLayout.LayoutParams) mChildOfContent.getLayoutParams(); } + @SuppressWarnings("deprecation") + private int getLegacyStableInsetBottom(WindowInsets windowInsets) { + return windowInsets.getStableInsetBottom(); + } + + @SuppressWarnings("deprecation") + private Point getLegacySizePoint() { + // calculate screen height differently for android versions <23: Lollipop 5.x, Marshmallow 6.x + //http://stackoverflow.com/a/29257533/3642890 beware of nexus 5 + Display display = activity.getWindowManager().getDefaultDisplay(); + Point size = new Point(); + display.getSize(size); + return size; + } + public void show() { - ((InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE)).toggleSoftInput( - 0, - InputMethodManager.HIDE_IMPLICIT_ONLY - ); + ((InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE)).showSoftInput(activity.getCurrentFocus(), 0); } public boolean hide() { diff --git a/keyboard/android/src/main/java/com/capacitorjs/plugins/keyboard/KeyboardPlugin.java b/keyboard/android/src/main/java/com/capacitorjs/plugins/keyboard/KeyboardPlugin.java index b73a20b24..35c1690c7 100644 --- a/keyboard/android/src/main/java/com/capacitorjs/plugins/keyboard/KeyboardPlugin.java +++ b/keyboard/android/src/main/java/com/capacitorjs/plugins/keyboard/KeyboardPlugin.java @@ -1,6 +1,7 @@ package com.capacitorjs.plugins.keyboard; import android.os.Handler; +import android.os.Looper; import com.getcapacitor.JSObject; import com.getcapacitor.Plugin; import com.getcapacitor.PluginCall; @@ -27,7 +28,7 @@ public void load() { public void show(final PluginCall call) { execute( () -> - new Handler() + new Handler(Looper.getMainLooper()) .postDelayed( () -> { implementation.show(); @@ -66,6 +67,11 @@ public void setResizeMode(PluginCall call) { call.unimplemented(); } + @PluginMethod + public void getResizeMode(PluginCall call) { + call.unimplemented(); + } + @PluginMethod public void setScroll(PluginCall call) { call.unimplemented(); diff --git a/keyboard/ios/Plugin.xcodeproj/project.pbxproj b/keyboard/ios/Plugin.xcodeproj/project.pbxproj index 5ca6de138..3bd18e004 100644 --- a/keyboard/ios/Plugin.xcodeproj/project.pbxproj +++ b/keyboard/ios/Plugin.xcodeproj/project.pbxproj @@ -386,7 +386,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -446,7 +446,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; @@ -469,12 +469,13 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Plugin/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks $(FRAMEWORK_SEARCH_PATHS)\n$(FRAMEWORK_SEARCH_PATHS)\n$(FRAMEWORK_SEARCH_PATHS)"; ONLY_ACTIVE_ARCH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.getcapacitor.Plugin; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; + SUPPORTS_MACCATALYST = NO; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -494,12 +495,13 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Plugin/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks $(FRAMEWORK_SEARCH_PATHS)"; ONLY_ACTIVE_ARCH = NO; PRODUCT_BUNDLE_IDENTIFIER = com.getcapacitor.Plugin; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; + SUPPORTS_MACCATALYST = NO; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; diff --git a/keyboard/ios/Plugin/Keyboard.m b/keyboard/ios/Plugin/Keyboard.m index b7cd86c8a..8cb00bce1 100644 --- a/keyboard/ios/Plugin/Keyboard.m +++ b/keyboard/ios/Plugin/Keyboard.m @@ -60,13 +60,13 @@ - (void)load UIClassString = [@[@"UI", @"Web", @"Browser", @"View"] componentsJoinedByString:@""]; WKClassString = [@[@"WK", @"Content", @"View"] componentsJoinedByString:@""]; UITraitsClassString = [@[@"UI", @"Text", @"Input", @"Traits"] componentsJoinedByString:@""]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(statusBarDidChangeFrame:) name:UIApplicationDidChangeStatusBarFrameNotification object: nil]; - - NSString * style = [self getConfigValue:@"style"]; + + PluginConfig * config = [self getConfig]; + NSString * style = [config getString:@"style": nil]; [self changeKeyboardStyle:style.uppercaseString]; self.keyboardResizes = ResizeNative; - NSString * resizeMode = [self getConfigValue:@"resize"]; + NSString * resizeMode = [config getString:@"resize": nil]; if ([resizeMode isEqualToString:@"none"]) { self.keyboardResizes = ResizeNone; @@ -101,10 +101,6 @@ - (void)load #pragma mark Keyboard events --(void)statusBarDidChangeFrame:(NSNotification *)notification { - [self _updateFrame]; -} - - (void)resetScrollView { UIScrollView *scrollView = [self.webView scrollView]; @@ -191,16 +187,13 @@ - (void)resizeElement:(NSString *)element withPaddingBottom:(int)paddingBottom w - (void)_updateFrame { - CGSize statusBarSize = [[UIApplication sharedApplication] statusBarFrame].size; - int statusBarHeight = MIN(statusBarSize.width, statusBarSize.height); - - int _paddingBottom = (int)self.paddingBottom; - - if (statusBarHeight == 40) { - _paddingBottom = _paddingBottom + 20; - } CGRect f, wf = CGRectZero; - UIWindow * window = [[[UIApplication sharedApplication] delegate] window]; + UIWindow * window = nil; + + if ([[[UIApplication sharedApplication] delegate] respondsToSelector:@selector(window)]) { + window = [[[UIApplication sharedApplication] delegate] window]; + } + if (!window) { if (@available(iOS 13.0, *)) { UIScene *scene = [UIApplication sharedApplication].connectedScenes.allObjects.firstObject; @@ -331,6 +324,24 @@ - (void)setResizeMode:(CAPPluginCall *)call [call resolve]; } +- (void)getResizeMode:(CAPPluginCall *)call +{ + NSString *mode; + + if (self.keyboardResizes == ResizeIonic) { + mode = @"ionic"; + } else if(self.keyboardResizes == ResizeBody) { + mode = @"body"; + } else if (self.keyboardResizes == ResizeNative) { + mode = @"native"; + } else { + mode = @"none"; + } + + NSDictionary *response = [NSDictionary dictionaryWithObject:mode forKey:@"mode"]; + [call resolve: response]; +} + - (void)setScroll:(CAPPluginCall *)call { self.disableScroll = [call getBool:@"isDisabled" defaultValue:FALSE]; [call resolve]; diff --git a/keyboard/ios/Plugin/KeyboardPlugin.m b/keyboard/ios/Plugin/KeyboardPlugin.m index 22d7a2edf..455f67ca5 100644 --- a/keyboard/ios/Plugin/KeyboardPlugin.m +++ b/keyboard/ios/Plugin/KeyboardPlugin.m @@ -9,6 +9,7 @@ CAP_PLUGIN_METHOD(setAccessoryBarVisible, CAPPluginReturnPromise); CAP_PLUGIN_METHOD(setStyle, CAPPluginReturnPromise); CAP_PLUGIN_METHOD(setResizeMode, CAPPluginReturnPromise); + CAP_PLUGIN_METHOD(getResizeMode, CAPPluginReturnPromise); CAP_PLUGIN_METHOD(setScroll, CAPPluginReturnPromise); - CAP_PLUGIN_METHOD(removeAllListeners, CAPPluginReturnNone); + CAP_PLUGIN_METHOD(removeAllListeners, CAPPluginReturnPromise); ) diff --git a/keyboard/ios/Podfile b/keyboard/ios/Podfile index 54a00c161..dee40960f 100644 --- a/keyboard/ios/Podfile +++ b/keyboard/ios/Podfile @@ -1,4 +1,4 @@ -platform :ios, '12.0' +platform :ios, '13.0' def capacitor_pods # Comment the next line if you're not using Swift and don't want to use dynamic frameworks diff --git a/keyboard/package.json b/keyboard/package.json index 9b15986b2..c1ce902d4 100644 --- a/keyboard/package.json +++ b/keyboard/package.json @@ -1,6 +1,6 @@ { "name": "@capacitor/keyboard", - "version": "1.2.1", + "version": "4.1.0", "description": "The Keyboard API provides keyboard display and visibility control, along with event tracking when the keyboard shows and hides.", "main": "dist/plugin.cjs.js", "module": "dist/esm/index.js", @@ -29,7 +29,7 @@ ], "scripts": { "verify": "npm run verify:ios && npm run verify:android && npm run verify:web", - "verify:ios": "cd ios && pod install && xcodebuild -workspace Plugin.xcworkspace -scheme Plugin && cd ..", + "verify:ios": "cd ios && pod install && xcodebuild -workspace Plugin.xcworkspace -scheme Plugin -destination generic/platform=iOS && cd ..", "verify:android": "cd android && ./gradlew clean build test && cd ..", "verify:web": "npm run build", "lint": "npm run eslint && npm run prettier -- --check && npm run swiftlint -- lint", @@ -45,11 +45,11 @@ "publish:cocoapod": "pod trunk push ./CapacitorKeyboard.podspec --allow-warnings" }, "devDependencies": { - "@capacitor/android": "^3.0.0", - "@capacitor/cli": "^3.0.0", - "@capacitor/core": "^3.0.0", - "@capacitor/docgen": "0.0.18", - "@capacitor/ios": "^3.0.0", + "@capacitor/android": "^4.0.0", + "@capacitor/cli": "^4.0.0", + "@capacitor/core": "^4.0.0", + "@capacitor/docgen": "0.2.0", + "@capacitor/ios": "^4.0.0", "@ionic/eslint-config": "^0.3.0", "@ionic/prettier-config": "~1.0.1", "@ionic/swiftlint-config": "^1.1.2", @@ -62,7 +62,7 @@ "typescript": "~4.1.5" }, "peerDependencies": { - "@capacitor/core": "^3.0.0" + "@capacitor/core": "^4.0.0" }, "prettier": "@ionic/prettier-config", "swiftlint": "@ionic/swiftlint-config", diff --git a/keyboard/src/definitions.ts b/keyboard/src/definitions.ts index 89a7ab516..87ee01bdf 100644 --- a/keyboard/src/definitions.ts +++ b/keyboard/src/definitions.ts @@ -26,9 +26,9 @@ declare module '@capacitor/cli' { * Only available on iOS. * * @since 1.0.0 - * @example "dark" + * @example "DARK" */ - style?: 'dark' | 'light'; + style?: KeyboardStyle; /** * There is an Android bug that prevents the keyboard from resizing the WebView @@ -186,6 +186,15 @@ export interface KeyboardPlugin { */ setResizeMode(options: KeyboardResizeOptions): Promise; + /** + * Get the currently set resize mode. + * + * This method is only supported on iOS. + * + * @since 4.0.0 + */ + getResizeMode(): Promise; + /** * Listen for when the keyboard is about to be shown. * diff --git a/lerna.json b/lerna.json index 82213c082..46dac7ecc 100644 --- a/lerna.json +++ b/lerna.json @@ -10,24 +10,27 @@ "dialog", "filesystem", "geolocation", + "google-maps", "haptics", "keyboard", "local-notifications", "motion", "network", + "preferences", "push-notifications", "screen-reader", "share", "splash-screen", "status-bar", - "storage", "text-zoom", "toast" ], "command": { "bootstrap": { "ci": false, - "npmClientArgs": ["--no-package-lock"] + "npmClientArgs": [ + "--no-package-lock" + ] }, "version": { "allowBranch": "main", diff --git a/local-notifications/CHANGELOG.md b/local-notifications/CHANGELOG.md index 7b36a97e1..1d2723ab1 100644 --- a/local-notifications/CHANGELOG.md +++ b/local-notifications/CHANGELOG.md @@ -3,6 +3,122 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [4.1.3](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/local-notifications@4.1.2...@capacitor/local-notifications@4.1.3) (2022-11-16) + +**Note:** Version bump only for package @capacitor/local-notifications + + + + + +## [4.1.2](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/local-notifications@4.1.1...@capacitor/local-notifications@4.1.2) (2022-10-21) + +**Note:** Version bump only for package @capacitor/local-notifications + + + + + +## [4.1.1](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/local-notifications@4.1.0...@capacitor/local-notifications@4.1.1) (2022-09-29) + + +### Bug Fixes + +* **local-notifications:** Add FLAG_MUTABLE to schedule on notifications ([#1173](https://github.com/ionic-team/capacitor-plugins/issues/1173)) ([98a5cb1](https://github.com/ionic-team/capacitor-plugins/commit/98a5cb1c60598bd3932a47dceb1f8918241ce8cb)) +* **local-notifications:** Showing correct scheduled notification time ([#1198](https://github.com/ionic-team/capacitor-plugins/issues/1198)) ([96c5430](https://github.com/ionic-team/capacitor-plugins/commit/96c5430f9bae13b54f3897dd1bffad030bfe3a3b)) + + + + + +# [4.1.0](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/local-notifications@1.1.0...@capacitor/local-notifications@4.1.0) (2022-09-12) + + +### Bug Fixes + +* **local-notifications:** prevent crash on restoring old notifications ([#1156](https://github.com/ionic-team/capacitor-plugins/issues/1156)) ([8c65584](https://github.com/ionic-team/capacitor-plugins/commit/8c655843ebbee5ab02503d7a10dd8296aa56ab04)) + + + + + +## [4.0.1](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0...4.0.1) (2022-07-28) + +**Note:** Version bump only for package @capacitor/local-notifications + + + + + +# [4.0.0](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0-beta.2...4.0.0) (2022-07-27) + +**Note:** Version bump only for package @capacitor/local-notifications + + + + + +# [4.0.0-beta.2](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0-beta.0...4.0.0-beta.2) (2022-07-08) + + +### Features + +* **local-notifications:** Add delivered notification handling ([#1060](https://github.com/ionic-team/capacitor-plugins/issues/1060)) ([0a89dc9](https://github.com/ionic-team/capacitor-plugins/commit/0a89dc97407685a7f1ec97532af304115fea7a0f)) + + + + + +# 4.0.0-beta.0 (2022-06-27) + + +### Bug Fixes + +* **local-notifications:** Add FLAG_MUTABLE to pending intents for SDK 31 support ([#914](https://github.com/ionic-team/capacitor-plugins/issues/914)) ([9ad0ce6](https://github.com/ionic-team/capacitor-plugins/commit/9ad0ce6f1497f425db907908be1b125e6ed83dbc)) +* **local-notifications:** Handle case of not allowed exact notifications ([#954](https://github.com/ionic-team/capacitor-plugins/issues/954)) ([5016996](https://github.com/ionic-team/capacitor-plugins/commit/5016996b3a4e9824d8dd2bc4c71892fc5dbc7365)) +* correct addListeners links ([#655](https://github.com/ionic-team/capacitor-plugins/issues/655)) ([f9871e7](https://github.com/ionic-team/capacitor-plugins/commit/f9871e7bd53478addb21155e148829f550c0e457)) +* inline source code in esm map files ([#760](https://github.com/ionic-team/capacitor-plugins/issues/760)) ([a960489](https://github.com/ionic-team/capacitor-plugins/commit/a960489a19db0182b90d187a50deff9dfbe51038)) +* Make removeAllListeners return a promise ([#895](https://github.com/ionic-team/capacitor-plugins/issues/895)) ([e5c49d6](https://github.com/ionic-team/capacitor-plugins/commit/e5c49d64445dca70286334e6a0441d8021197b13)) +* remove postpublish scripts ([#656](https://github.com/ionic-team/capacitor-plugins/issues/656)) ([ed6ac49](https://github.com/ionic-team/capacitor-plugins/commit/ed6ac499ebf4a47525071ccbfc36c27503e11f60)) +* **android:** fire localNotificationReceived event on Android ([#217](https://github.com/ionic-team/capacitor-plugins/issues/217)) ([d97682d](https://github.com/ionic-team/capacitor-plugins/commit/d97682d9f3d6f612993716c3bc35d3015c4e0c07)) +* **local-notification:** Throw unavailable if Notification API not supported ([#285](https://github.com/ionic-team/capacitor-plugins/issues/285)) ([a90a88b](https://github.com/ionic-team/capacitor-plugins/commit/a90a88b217f5fa2a257416050afb476dd84d8051)) +* **local-notifications:** Adding check for `new Notification` support ([#295](https://github.com/ionic-team/capacitor-plugins/issues/295)) ([a806f22](https://github.com/ionic-team/capacitor-plugins/commit/a806f22577209322bdc93ef7fe5490d3b0b6e42f)) +* **local-notifications:** Checking for null schedule in notification JSObject ([#258](https://github.com/ionic-team/capacitor-plugins/issues/258)) ([73cb416](https://github.com/ionic-team/capacitor-plugins/commit/73cb4168329622bb5a6625c900090a01fc5eca99)) +* **local-notifications:** don't store notifications if not scheduled ([#310](https://github.com/ionic-team/capacitor-plugins/issues/310)) ([c1445fd](https://github.com/ionic-team/capacitor-plugins/commit/c1445fddc69db27506f83b3ea56d8e90d4384346)) +* **local-notifications:** extra not being returned on notification events ([#340](https://github.com/ionic-team/capacitor-plugins/issues/340)) ([5b03a7f](https://github.com/ionic-team/capacitor-plugins/commit/5b03a7fdbfd2e8293a9fc3726185b516d7efa9a9)) +* **local-notifications:** Make getPending not return already fired notifications ([#256](https://github.com/ionic-team/capacitor-plugins/issues/256)) ([fb96f8a](https://github.com/ionic-team/capacitor-plugins/commit/fb96f8ab8c4776528e5825be6c2e19567462eef8)) +* **local-notifications:** Opt out of Capacitor date serialization ([#264](https://github.com/ionic-team/capacitor-plugins/issues/264)) ([6e447d5](https://github.com/ionic-team/capacitor-plugins/commit/6e447d54aff3cac47df540addf2a0bf05238c158)) +* **local-notifications:** requestPermissions and checkPermissions return if enabled ([#494](https://github.com/ionic-team/capacitor-plugins/issues/494)) ([555bb1f](https://github.com/ionic-team/capacitor-plugins/commit/555bb1f9bd02ccd999891a316e7ee0f8c1844e92)) +* **local-notifications:** return schedule on as object ([#603](https://github.com/ionic-team/capacitor-plugins/issues/603)) ([ca34b01](https://github.com/ionic-team/capacitor-plugins/commit/ca34b01c73f14bb0ad14e8a501210e42a0e65b04)) +* **local-notifications:** Throw errors if missing mandatory channel fields ([#577](https://github.com/ionic-team/capacitor-plugins/issues/577)) ([6bf3a4f](https://github.com/ionic-team/capacitor-plugins/commit/6bf3a4f0de8880588200ae60e73427fa6959ea20)) +* **local-notifications:** use proper rollup config ([#528](https://github.com/ionic-team/capacitor-plugins/issues/528)) ([cd17daa](https://github.com/ionic-team/capacitor-plugins/commit/cd17daa02241f50299232212ad72722d8a35ee16)) +* normalize use of integers for notification IDs ([#195](https://github.com/ionic-team/capacitor-plugins/issues/195)) ([b56e111](https://github.com/ionic-team/capacitor-plugins/commit/b56e1118227ee58d1872dbb32a18b8484290d3c7)) +* **web:** fix scheduled notifications not being sent ([#220](https://github.com/ionic-team/capacitor-plugins/issues/220)) ([c8e92d6](https://github.com/ionic-team/capacitor-plugins/commit/c8e92d6a178f8b3278b1d3a9c364eb8120d28848)) +* add es2017 lib to tsconfig ([#180](https://github.com/ionic-team/capacitor-plugins/issues/180)) ([2c3776c](https://github.com/ionic-team/capacitor-plugins/commit/2c3776c38ca025c5ee965dec10ccf1cdb6c02e2f)) +* Use the event names from Capacitor 2 ([#215](https://github.com/ionic-team/capacitor-plugins/issues/215)) ([008fe9e](https://github.com/ionic-team/capacitor-plugins/commit/008fe9e9bf6a960b0ab7b6fc4d5014f10ba13df8)) + + +### Features + +* set targetSDK default value to 31 ([#824](https://github.com/ionic-team/capacitor-plugins/issues/824)) ([3ee10de](https://github.com/ionic-team/capacitor-plugins/commit/3ee10de98067984c1a4e75295d001c5a895c47f4)) +* set targetSDK default value to 32 ([#970](https://github.com/ionic-team/capacitor-plugins/issues/970)) ([fa70d96](https://github.com/ionic-team/capacitor-plugins/commit/fa70d96f141af751aae53ceb5642c46b204f5958)) +* Upgrade gradle to 7.4 ([#826](https://github.com/ionic-team/capacitor-plugins/issues/826)) ([5db0906](https://github.com/ionic-team/capacitor-plugins/commit/5db0906f6264287c4f8e69dbaecf19d4d387824b)) +* Use java 11 ([#910](https://github.com/ionic-team/capacitor-plugins/issues/910)) ([5acb2a2](https://github.com/ionic-team/capacitor-plugins/commit/5acb2a288a413492b163e4e97da46a085d9e4be0)) +* **android:** implements Activity Result API changes for permissions and activity results ([#222](https://github.com/ionic-team/capacitor-plugins/issues/222)) ([f671b9f](https://github.com/ionic-team/capacitor-plugins/commit/f671b9f4b472806ef43db6dcf302d4503cf1828c)) +* **local-notifications:** add more info to pending notifications ([#211](https://github.com/ionic-team/capacitor-plugins/issues/211)) ([7c50487](https://github.com/ionic-team/capacitor-plugins/commit/7c50487d40836380a27bd4c8d3655d83e0c3a720)) +* **local-notifications:** Add weekday scheduling support for Android and iOS ([#756](https://github.com/ionic-team/capacitor-plugins/issues/756)) ([430b485](https://github.com/ionic-team/capacitor-plugins/commit/430b48592ce59ccc967dd9a081873d7dc3937e93)) +* **local-notifications:** Adding summary text to grouped notifications ([#296](https://github.com/ionic-team/capacitor-plugins/issues/296)) ([f625bd2](https://github.com/ionic-team/capacitor-plugins/commit/f625bd28bc00dbd0b51d7bdecf5e6f3077dcc7a9)) +* **local-notifications:** Fire local notifications while app is idle ([#237](https://github.com/ionic-team/capacitor-plugins/issues/237)) ([43380ef](https://github.com/ionic-team/capacitor-plugins/commit/43380efa8901adf9d669d0c1ef20038a2fd7df8e)) +* **local-notifications:** Support for Big Text and Inbox Notification Style ([#280](https://github.com/ionic-team/capacitor-plugins/issues/280)) ([dc96ef9](https://github.com/ionic-team/capacitor-plugins/commit/dc96ef923725f5b53346431d35f82d5ff13f4e17)) +* **local-notifications:** Support setting seconds in Schedule "on" ([#253](https://github.com/ionic-team/capacitor-plugins/issues/253)) ([4ec8d06](https://github.com/ionic-team/capacitor-plugins/commit/4ec8d06e0cb52403e541a05e5c3518d4c5ea754e)) +* **web:** implement ActionPerformed and Received events ([#219](https://github.com/ionic-team/capacitor-plugins/issues/219)) ([e062901](https://github.com/ionic-team/capacitor-plugins/commit/e062901fc2e55cf6b6dc1ab20258d80a0be8b2d9)) +* add commonjs output format ([#179](https://github.com/ionic-team/capacitor-plugins/issues/179)) ([8e9e098](https://github.com/ionic-team/capacitor-plugins/commit/8e9e09862064b3f6771d7facbc4008e995d9b463)) +* Local Notifications plugin ([#94](https://github.com/ionic-team/capacitor-plugins/issues/94)) ([e59ba9c](https://github.com/ionic-team/capacitor-plugins/commit/e59ba9ceea78a26ec60e521825f228baa9d74577)) + + + + + # [1.1.0](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/local-notifications@1.0.10...@capacitor/local-notifications@1.1.0) (2022-01-19) diff --git a/local-notifications/CapacitorLocalNotifications.podspec b/local-notifications/CapacitorLocalNotifications.podspec index 4e69271f9..76b3c0662 100644 --- a/local-notifications/CapacitorLocalNotifications.podspec +++ b/local-notifications/CapacitorLocalNotifications.podspec @@ -11,7 +11,7 @@ Pod::Spec.new do |s| s.author = package['author'] s.source = { :git => 'https://github.com/ionic-team/capacitor-plugins.git', :tag => package['name'] + '@' + package['version'] } s.source_files = 'ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}', 'local-notifications/ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}' - s.ios.deployment_target = '12.0' + s.ios.deployment_target = '13.0' s.dependency 'Capacitor' s.swift_version = '5.1' end diff --git a/local-notifications/README.md b/local-notifications/README.md index d8ed94f98..9553c319c 100644 --- a/local-notifications/README.md +++ b/local-notifications/README.md @@ -9,6 +9,16 @@ npm install @capacitor/local-notifications npx cap sync ``` +## Android + +Starting on Android 12, scheduled notifications won't be exact unless this permission is added to your `AndroidManifest.xml`: + +```xml + +``` + +Note that even if the permission is present, users can still disable exact notifications from the app settings. + ## Configuration @@ -73,6 +83,9 @@ If the device has entered [Doze](https://developer.android.com/training/monitori * [`registerActionTypes(...)`](#registeractiontypes) * [`cancel(...)`](#cancel) * [`areEnabled()`](#areenabled) +* [`getDeliveredNotifications()`](#getdeliverednotifications) +* [`removeDeliveredNotifications(...)`](#removedeliverednotifications) +* [`removeAllDeliveredNotifications()`](#removealldeliverednotifications) * [`createChannel(...)`](#createchannel) * [`deleteChannel(...)`](#deletechannel) * [`listChannels()`](#listchannels) @@ -175,10 +188,55 @@ Check if notifications are enabled or not. -------------------- +### getDeliveredNotifications() + +```typescript +getDeliveredNotifications() => Promise +``` + +Get a list of notifications that are visible on the notifications screen. + +**Returns:** Promise<DeliveredNotifications> + +**Since:** 4.0.0 + +-------------------- + + +### removeDeliveredNotifications(...) + +```typescript +removeDeliveredNotifications(delivered: DeliveredNotifications) => Promise +``` + +Remove the specified notifications from the notifications screen. + +| Param | Type | +| --------------- | ------------------------------------------------------------------------- | +| **`delivered`** | DeliveredNotifications | + +**Since:** 4.0.0 + +-------------------- + + +### removeAllDeliveredNotifications() + +```typescript +removeAllDeliveredNotifications() => Promise +``` + +Remove all the notifications from the notifications screen. + +**Since:** 4.0.0 + +-------------------- + + ### createChannel(...) ```typescript -createChannel(channel: NotificationChannel) => Promise +createChannel(channel: Channel) => Promise ``` Create a notification channel. @@ -197,16 +255,16 @@ Only available for Android. ### deleteChannel(...) ```typescript -deleteChannel(channel: NotificationChannel) => Promise +deleteChannel(args: { id: string; }) => Promise ``` Delete a notification channel. Only available for Android. -| Param | Type | -| ------------- | ------------------------------------------- | -| **`channel`** | Channel | +| Param | Type | +| ---------- | ---------------------------- | +| **`args`** | { id: string; } | **Since:** 1.0.0 @@ -357,7 +415,7 @@ The object that describes a local notification. | **`actionTypeId`** | string | Associate an action type with this notification. | 1.0.0 | | **`extra`** | any | Set extra data to store within this notification. | 1.0.0 | | **`threadIdentifier`** | string | Used to group multiple notifications. Sets `threadIdentifier` on the [`UNMutableNotificationContent`](https://developer.apple.com/documentation/usernotifications/unmutablenotificationcontent). Only available for iOS. | 1.0.0 | -| **`summaryArgument`** | string | The string this notification adds to the category's summary format string. Sets `summaryArgument` on the [`UNMutableNotificationContent`](https://developer.apple.com/documentation/usernotifications/unmutablenotificationcontent). Only available for iOS 12+. | 1.0.0 | +| **`summaryArgument`** | string | The string this notification adds to the category's summary format string. Sets `summaryArgument` on the [`UNMutableNotificationContent`](https://developer.apple.com/documentation/usernotifications/unmutablenotificationcontent). Only available for iOS. | 1.0.0 | | **`group`** | string | Used to group multiple notifications. Calls `setGroup()` on [`NotificationCompat.Builder`](https://developer.android.com/reference/androidx/core/app/NotificationCompat.Builder) with the provided value. Only available for Android. | 1.0.0 | | **`groupSummary`** | boolean | If true, this notification becomes the summary for a group of notifications. Calls `setGroupSummary()` on [`NotificationCompat.Builder`](https://developer.android.com/reference/androidx/core/app/NotificationCompat.Builder) with the provided value. Only available for Android when using `group`. | 1.0.0 | | **`channelId`** | string | Specifies the channel the notification should be delivered on. If channel with the given name does not exist then the notification will not fire. If not provided, it will use the default channel. Calls `setChannelId()` on [`NotificationCompat.Builder`](https://developer.android.com/reference/androidx/core/app/NotificationCompat.Builder) with the provided value. Only available for Android 26+. | 1.0.0 | @@ -537,19 +595,44 @@ An action that can be taken when a notification is displayed. | **`value`** | boolean | Whether or not the device has local notifications enabled. | 1.0.0 | +#### DeliveredNotifications + +| Prop | Type | Description | Since | +| ------------------- | ------------------------------------------ | ------------------------------------------------------------------- | ----- | +| **`notifications`** | DeliveredNotificationSchema[] | List of notifications that are visible on the notifications screen. | 1.0.0 | + + +#### DeliveredNotificationSchema + +| Prop | Type | Description | Since | +| ------------------ | --------------------------------------------- | ---------------------------------------------------------------------------------------------- | ----- | +| **`id`** | number | The notification identifier. | 4.0.0 | +| **`tag`** | string | The notification tag. Only available on Android. | 4.0.0 | +| **`title`** | string | The title of the notification. | 4.0.0 | +| **`body`** | string | The body of the notification, shown below the title. | 4.0.0 | +| **`group`** | string | The configured group of the notification. Only available for Android. | 4.0.0 | +| **`groupSummary`** | boolean | If this notification is the summary for a group of notifications. Only available for Android. | 4.0.0 | +| **`data`** | any | Any additional data that was included in the notification payload. Only available for Android. | 4.0.0 | +| **`extra`** | any | Extra data to store within this notification. Only available for iOS. | 4.0.0 | +| **`attachments`** | Attachment[] | The attachments for this notification. Only available for iOS. | 1.0.0 | +| **`actionTypeId`** | string | Action type ssociated with this notification. Only available for iOS. | 4.0.0 | +| **`schedule`** | Schedule | Schedule used to fire this notification. Only available for iOS. | 4.0.0 | +| **`sound`** | string | Sound that was used when the notification was displayed. Only available for iOS. | 4.0.0 | + + #### Channel -| Prop | Type | Description | Since | -| ----------------- | ------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----- | -| **`id`** | string | The channel identifier. | 1.0.0 | -| **`name`** | string | The human-friendly name of this channel (presented to the user). | 1.0.0 | -| **`description`** | string | The description of this channel (presented to the user). | 1.0.0 | -| **`sound`** | string | The sound that should be played for notifications posted to this channel. Notification channels with an importance of at least `3` should have a sound. The file name of a sound file should be specified relative to the android app `res/raw` directory. If the sound is not provided, or the sound file is not found no sound will be used. | 1.0.0 | -| **`importance`** | Importance | The level of interruption for notifications posted to this channel. | 1.0.0 | -| **`visibility`** | Visibility | The visibility of notifications posted to this channel. This setting is for whether notifications posted to this channel appear on the lockscreen or not, and if so, whether they appear in a redacted form. | 1.0.0 | -| **`lights`** | boolean | Whether notifications posted to this channel should display notification lights, on devices that support it. | 1.0.0 | -| **`lightColor`** | string | The light color for notifications posted to this channel. Only supported if lights are enabled on this channel and the device supports it. Supported color formats are `#RRGGBB` and `#RRGGBBAA`. | 1.0.0 | -| **`vibration`** | boolean | Whether notifications posted to this channel should vibrate. | 1.0.0 | +| Prop | Type | Description | Default | Since | +| ----------------- | ------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------- | ----- | +| **`id`** | string | The channel identifier. | | 1.0.0 | +| **`name`** | string | The human-friendly name of this channel (presented to the user). | | 1.0.0 | +| **`description`** | string | The description of this channel (presented to the user). | | 1.0.0 | +| **`sound`** | string | The sound that should be played for notifications posted to this channel. Notification channels with an importance of at least `3` should have a sound. The file name of a sound file should be specified relative to the android app `res/raw` directory. If the sound is not provided, or the sound file is not found no sound will be used. | | 1.0.0 | +| **`importance`** | Importance | The level of interruption for notifications posted to this channel. | `3` | 1.0.0 | +| **`visibility`** | Visibility | The visibility of notifications posted to this channel. This setting is for whether notifications posted to this channel appear on the lockscreen or not, and if so, whether they appear in a redacted form. | | 1.0.0 | +| **`lights`** | boolean | Whether notifications posted to this channel should display notification lights, on devices that support it. | | 1.0.0 | +| **`lightColor`** | string | The light color for notifications posted to this channel. Only supported if lights are enabled on this channel and the device supports it. Supported color formats are `#RRGGBB` and `#RRGGBBAA`. | | 1.0.0 | +| **`vibration`** | boolean | Whether notifications posted to this channel should vibrate. | | 1.0.0 | #### ListChannelsResult @@ -590,11 +673,6 @@ An action that can be taken when a notification is displayed. 'year' | 'month' | 'two-weeks' | 'week' | 'day' | 'hour' | 'minute' | 'second' -#### NotificationChannel - -Channel - - #### Importance The importance level. For more details, see the [Android Developer Docs](https://developer.android.com/reference/android/app/NotificationManager#IMPORTANCE_DEFAULT) diff --git a/local-notifications/android/build.gradle b/local-notifications/android/build.gradle index e80d6b95c..43252f49c 100644 --- a/local-notifications/android/build.gradle +++ b/local-notifications/android/build.gradle @@ -1,27 +1,39 @@ ext { - junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.1' - androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.2.0' - androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.1.2' - androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.3.0' + capacitorVersion = System.getenv('CAPACITOR_VERSION') + junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.2' + androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.4.2' + androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.1.3' + androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.4.0' } buildscript { repositories { google() mavenCentral() + maven { + url "https://plugins.gradle.org/m2/" + } } dependencies { - classpath 'com.android.tools.build:gradle:4.2.1' + classpath 'com.android.tools.build:gradle:7.2.1' + if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + classpath 'io.github.gradle-nexus:publish-plugin:1.1.0' + } } } apply plugin: 'com.android.library' +if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + apply plugin: 'io.github.gradle-nexus.publish-plugin' + apply from: file('../../scripts/android/publish-root.gradle') + apply from: file('../../scripts/android/publish-module.gradle') +} android { - compileSdkVersion project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 29 + compileSdkVersion project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 32 defaultConfig { - minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 21 - targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 29 + minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 22 + targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 32 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" @@ -36,21 +48,26 @@ android { abortOnError false } compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility JavaVersion.VERSION_11 + targetCompatibility JavaVersion.VERSION_11 } } repositories { google() mavenCentral() - jcenter() } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation project(':capacitor-android') + + if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + implementation "com.capacitorjs:core:$capacitorVersion" + } else { + implementation project(':capacitor-android') + } + implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion" testImplementation "junit:junit:$junitVersion" androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion" diff --git a/local-notifications/android/gradle/wrapper/gradle-wrapper.jar b/local-notifications/android/gradle/wrapper/gradle-wrapper.jar index e708b1c02..41d9927a4 100644 Binary files a/local-notifications/android/gradle/wrapper/gradle-wrapper.jar and b/local-notifications/android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/local-notifications/android/gradle/wrapper/gradle-wrapper.properties b/local-notifications/android/gradle/wrapper/gradle-wrapper.properties index 3c4101c3e..92f06b50f 100644 --- a/local-notifications/android/gradle/wrapper/gradle-wrapper.properties +++ b/local-notifications/android/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/local-notifications/android/gradlew b/local-notifications/android/gradlew index 4f906e0c8..1b6c78733 100755 --- a/local-notifications/android/gradlew +++ b/local-notifications/android/gradlew @@ -1,7 +1,7 @@ -#!/usr/bin/env sh +#!/bin/sh # -# Copyright 2015 the original author or authors. +# Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,67 +17,101 @@ # ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` +APP_BASE_NAME=${0##*/} # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar @@ -87,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -98,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" + JAVACMD=java which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the @@ -106,80 +140,95 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=`expr $i + 1` + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" diff --git a/local-notifications/android/src/main/java/com/capacitorjs/plugins/localnotifications/LocalNotificationManager.java b/local-notifications/android/src/main/java/com/capacitorjs/plugins/localnotifications/LocalNotificationManager.java index 0dc5ca4b5..9f4323e80 100644 --- a/local-notifications/android/src/main/java/com/capacitorjs/plugins/localnotifications/LocalNotificationManager.java +++ b/local-notifications/android/src/main/java/com/capacitorjs/plugins/localnotifications/LocalNotificationManager.java @@ -22,7 +22,7 @@ import com.getcapacitor.JSObject; import com.getcapacitor.Logger; import com.getcapacitor.PluginCall; -import com.getcapacitor.android.R; +import com.getcapacitor.PluginConfig; import com.getcapacitor.plugin.util.AssetUtil; import java.text.SimpleDateFormat; import java.util.Date; @@ -36,7 +36,6 @@ */ public class LocalNotificationManager { - private static final String CONFIG_KEY_PREFIX = "plugins.LocalNotifications."; private static int defaultSoundID = AssetUtil.RESOURCE_ID_ZERO_VALUE; private static int defaultSmallIconID = AssetUtil.RESOURCE_ID_ZERO_VALUE; // Action constants @@ -52,13 +51,13 @@ public class LocalNotificationManager { private Context context; private Activity activity; private NotificationStorage storage; - private CapConfig config; + private PluginConfig config; public LocalNotificationManager(NotificationStorage notificationStorage, Activity activity, Context context, CapConfig config) { storage = notificationStorage; this.activity = activity; this.context = context; - this.config = config; + this.config = config.getPluginConfiguration("LocalNotifications"); } /** @@ -212,18 +211,13 @@ private void buildNotification(NotificationManagerCompat notificationManager, Lo } } - // make sure scheduled time is shown instead of display time - if (localNotification.isScheduled() && localNotification.getSchedule().getAt() != null) { - mBuilder.setWhen(localNotification.getSchedule().getAt().getTime()).setShowWhen(true); - } - mBuilder.setVisibility(NotificationCompat.VISIBILITY_PRIVATE); mBuilder.setOnlyAlertOnce(true); mBuilder.setSmallIcon(localNotification.getSmallIcon(context, getDefaultSmallIcon(context))); mBuilder.setLargeIcon(localNotification.getLargeIcon(context)); - String iconColor = localNotification.getIconColor(config.getString(CONFIG_KEY_PREFIX + "iconColor")); + String iconColor = localNotification.getIconColor(config.getString("iconColor")); if (iconColor != null) { try { mBuilder.setColor(Color.parseColor(iconColor)); @@ -253,13 +247,11 @@ private void buildNotification(NotificationManagerCompat notificationManager, Lo private void createActionIntents(LocalNotification localNotification, NotificationCompat.Builder mBuilder) { // Open intent Intent intent = buildIntent(localNotification, DEFAULT_PRESS_ACTION); - - PendingIntent pendingIntent = PendingIntent.getActivity( - context, - localNotification.getId(), - intent, - PendingIntent.FLAG_CANCEL_CURRENT - ); + int flags = PendingIntent.FLAG_CANCEL_CURRENT; + if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + flags = flags | PendingIntent.FLAG_MUTABLE; + } + PendingIntent pendingIntent = PendingIntent.getActivity(context, localNotification.getId(), intent, flags); mBuilder.setContentIntent(pendingIntent); // Build action types @@ -273,7 +265,7 @@ private void createActionIntents(LocalNotification localNotification, Notificati context, localNotification.getId() + notificationAction.getId().hashCode(), actionIntent, - PendingIntent.FLAG_CANCEL_CURRENT + flags ); NotificationCompat.Action.Builder actionBuilder = new NotificationCompat.Action.Builder( R.drawable.ic_transparent, @@ -295,7 +287,11 @@ private void createActionIntents(LocalNotification localNotification, Notificati dissmissIntent.putExtra(ACTION_INTENT_KEY, "dismiss"); LocalNotificationSchedule schedule = localNotification.getSchedule(); dissmissIntent.putExtra(NOTIFICATION_IS_REMOVABLE_KEY, schedule == null || schedule.isRemovable()); - PendingIntent deleteIntent = PendingIntent.getBroadcast(context, localNotification.getId(), dissmissIntent, 0); + flags = 0; + if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + flags = PendingIntent.FLAG_MUTABLE; + } + PendingIntent deleteIntent = PendingIntent.getBroadcast(context, localNotification.getId(), dissmissIntent, flags); mBuilder.setDeleteIntent(deleteIntent); } @@ -330,12 +326,11 @@ private void triggerScheduledNotification(Notification notification, LocalNotifi Intent notificationIntent = new Intent(context, TimedNotificationPublisher.class); notificationIntent.putExtra(NOTIFICATION_INTENT_KEY, request.getId()); notificationIntent.putExtra(TimedNotificationPublisher.NOTIFICATION_KEY, notification); - PendingIntent pendingIntent = PendingIntent.getBroadcast( - context, - request.getId(), - notificationIntent, - PendingIntent.FLAG_CANCEL_CURRENT - ); + int flags = PendingIntent.FLAG_CANCEL_CURRENT; + if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + flags = flags | PendingIntent.FLAG_MUTABLE; + } + PendingIntent pendingIntent = PendingIntent.getBroadcast(context, request.getId(), notificationIntent, flags); // Schedule at specific time (with repeating support) Date at = schedule.getAt(); @@ -348,11 +343,7 @@ private void triggerScheduledNotification(Notification notification, LocalNotifi long interval = at.getTime() - new Date().getTime(); alarmManager.setRepeating(AlarmManager.RTC, at.getTime(), interval, pendingIntent); } else { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && schedule.allowWhileIdle()) { - alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC, at.getTime(), pendingIntent); - } else { - alarmManager.setExact(AlarmManager.RTC, at.getTime(), pendingIntent); - } + setExactIfPossible(alarmManager, schedule, at.getTime(), pendingIntent); } return; } @@ -373,15 +364,31 @@ private void triggerScheduledNotification(Notification notification, LocalNotifi if (on != null) { long trigger = on.nextTrigger(new Date()); notificationIntent.putExtra(TimedNotificationPublisher.CRON_KEY, on.toMatchString()); - pendingIntent = PendingIntent.getBroadcast(context, request.getId(), notificationIntent, PendingIntent.FLAG_CANCEL_CURRENT); + pendingIntent = PendingIntent.getBroadcast(context, request.getId(), notificationIntent, flags); + setExactIfPossible(alarmManager, schedule, trigger, pendingIntent); + SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); + Logger.debug(Logger.tags("LN"), "notification " + request.getId() + " will next fire at " + sdf.format(new Date(trigger))); + } + } + + private void setExactIfPossible( + AlarmManager alarmManager, + LocalNotificationSchedule schedule, + long trigger, + PendingIntent pendingIntent + ) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && !alarmManager.canScheduleExactAlarms()) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && schedule.allowWhileIdle()) { + alarmManager.setAndAllowWhileIdle(AlarmManager.RTC, trigger, pendingIntent); + } else { + alarmManager.set(AlarmManager.RTC, trigger, pendingIntent); + } + } else { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && schedule.allowWhileIdle()) { alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC, trigger, pendingIntent); } else { alarmManager.setExact(AlarmManager.RTC, trigger, pendingIntent); } - - SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); - Logger.debug(Logger.tags("LN"), "notification " + request.getId() + " will next fire at " + sdf.format(new Date(trigger))); } } @@ -399,7 +406,11 @@ public void cancel(PluginCall call) { private void cancelTimerForNotification(Integer notificationId) { Intent intent = new Intent(context, TimedNotificationPublisher.class); - PendingIntent pi = PendingIntent.getBroadcast(context, notificationId, intent, 0); + int flags = 0; + if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + flags = PendingIntent.FLAG_MUTABLE; + } + PendingIntent pi = PendingIntent.getBroadcast(context, notificationId, intent, flags); if (pi != null) { AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); alarmManager.cancel(pi); @@ -428,7 +439,7 @@ private int getDefaultSound(Context context) { if (defaultSoundID != AssetUtil.RESOURCE_ID_ZERO_VALUE) return defaultSoundID; int resId = AssetUtil.RESOURCE_ID_ZERO_VALUE; - String soundConfigResourceName = config.getString(CONFIG_KEY_PREFIX + "sound"); + String soundConfigResourceName = config.getString("sound"); soundConfigResourceName = AssetUtil.getResourceBaseName(soundConfigResourceName); if (soundConfigResourceName != null) { @@ -443,7 +454,7 @@ private int getDefaultSmallIcon(Context context) { if (defaultSmallIconID != AssetUtil.RESOURCE_ID_ZERO_VALUE) return defaultSmallIconID; int resId = AssetUtil.RESOURCE_ID_ZERO_VALUE; - String smallIconConfigResourceName = config.getString(CONFIG_KEY_PREFIX + "smallIcon"); + String smallIconConfigResourceName = config.getString("smallIcon"); smallIconConfigResourceName = AssetUtil.getResourceBaseName(smallIconConfigResourceName); if (smallIconConfigResourceName != null) { diff --git a/local-notifications/android/src/main/java/com/capacitorjs/plugins/localnotifications/LocalNotificationRestoreReceiver.java b/local-notifications/android/src/main/java/com/capacitorjs/plugins/localnotifications/LocalNotificationRestoreReceiver.java index e365942bc..134fd0657 100644 --- a/local-notifications/android/src/main/java/com/capacitorjs/plugins/localnotifications/LocalNotificationRestoreReceiver.java +++ b/local-notifications/android/src/main/java/com/capacitorjs/plugins/localnotifications/LocalNotificationRestoreReceiver.java @@ -5,6 +5,7 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; +import android.os.Build; import android.os.UserManager; import com.getcapacitor.CapConfig; import java.util.ArrayList; @@ -15,7 +16,7 @@ public class LocalNotificationRestoreReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { - if (SDK_INT >= 24) { + if (SDK_INT >= Build.VERSION_CODES.N) { UserManager um = context.getSystemService(UserManager.class); if (um == null || !um.isUserUnlocked()) return; } diff --git a/local-notifications/android/src/main/java/com/capacitorjs/plugins/localnotifications/LocalNotificationSchedule.java b/local-notifications/android/src/main/java/com/capacitorjs/plugins/localnotifications/LocalNotificationSchedule.java index 82cb3e7bd..185ee54c7 100644 --- a/local-notifications/android/src/main/java/com/capacitorjs/plugins/localnotifications/LocalNotificationSchedule.java +++ b/local-notifications/android/src/main/java/com/capacitorjs/plugins/localnotifications/LocalNotificationSchedule.java @@ -141,7 +141,8 @@ public boolean isRemovable() { public Long getEveryInterval() { switch (every) { case "year": - return count * DateUtils.YEAR_IN_MILLIS; + // This case is just approximation as not all years have the same number of days + return count * DateUtils.WEEK_IN_MILLIS * 52; case "month": // This case is just approximation as months have different number of days return count * 30 * DateUtils.DAY_IN_MILLIS; diff --git a/local-notifications/android/src/main/java/com/capacitorjs/plugins/localnotifications/LocalNotificationsPlugin.java b/local-notifications/android/src/main/java/com/capacitorjs/plugins/localnotifications/LocalNotificationsPlugin.java index d77a65595..f329fc9a1 100644 --- a/local-notifications/android/src/main/java/com/capacitorjs/plugins/localnotifications/LocalNotificationsPlugin.java +++ b/local-notifications/android/src/main/java/com/capacitorjs/plugins/localnotifications/LocalNotificationsPlugin.java @@ -1,6 +1,11 @@ package com.capacitorjs.plugins.localnotifications; +import android.app.Notification; +import android.app.NotificationManager; +import android.content.Context; import android.content.Intent; +import android.os.Build; +import android.service.notification.StatusBarNotification; import com.getcapacitor.Bridge; import com.getcapacitor.JSArray; import com.getcapacitor.JSObject; @@ -13,12 +18,15 @@ import java.util.List; import java.util.Map; import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; @CapacitorPlugin(name = "LocalNotifications", permissions = @Permission(strings = {}, alias = "display")) public class LocalNotificationsPlugin extends Plugin { private static Bridge staticBridge = null; private LocalNotificationManager manager; + public NotificationManager notificationManager; private NotificationStorage notificationStorage; private NotificationChannelManager notificationChannelManager; @@ -29,6 +37,7 @@ public void load() { manager = new LocalNotificationManager(notificationStorage, getActivity(), getContext(), this.bridge.getConfig()); manager.createNotificationChannel(); notificationChannelManager = new NotificationChannelManager(getActivity()); + notificationManager = (NotificationManager) getActivity().getSystemService(Context.NOTIFICATION_SERVICE); staticBridge = this.bridge; } @@ -97,6 +106,76 @@ public void areEnabled(PluginCall call) { call.resolve(data); } + @PluginMethod + public void getDeliveredNotifications(PluginCall call) { + JSArray notifications = new JSArray(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + StatusBarNotification[] activeNotifications = notificationManager.getActiveNotifications(); + + for (StatusBarNotification notif : activeNotifications) { + JSObject jsNotif = new JSObject(); + + jsNotif.put("id", notif.getId()); + jsNotif.put("tag", notif.getTag()); + + Notification notification = notif.getNotification(); + if (notification != null) { + jsNotif.put("title", notification.extras.getCharSequence(Notification.EXTRA_TITLE)); + jsNotif.put("body", notification.extras.getCharSequence(Notification.EXTRA_TEXT)); + jsNotif.put("group", notification.getGroup()); + jsNotif.put("groupSummary", 0 != (notification.flags & Notification.FLAG_GROUP_SUMMARY)); + + JSObject extras = new JSObject(); + + for (String key : notification.extras.keySet()) { + extras.put(key, notification.extras.get(key)); + } + + jsNotif.put("data", extras); + } + + notifications.put(jsNotif); + } + } + + JSObject result = new JSObject(); + result.put("notifications", notifications); + call.resolve(result); + } + + @PluginMethod + public void removeDeliveredNotifications(PluginCall call) { + JSArray notifications = call.getArray("notifications"); + + try { + for (Object o : notifications.toList()) { + if (o instanceof JSONObject) { + JSObject notif = JSObject.fromJSONObject((JSONObject) o); + String tag = notif.getString("tag"); + Integer id = notif.getInteger("id"); + + if (tag == null) { + notificationManager.cancel(id); + } else { + notificationManager.cancel(tag, id); + } + } else { + call.reject("Expected notifications to be a list of notification objects"); + } + } + } catch (JSONException e) { + call.reject(e.getMessage()); + } + + call.resolve(); + } + + @PluginMethod + public void removeAllDeliveredNotifications(PluginCall call) { + notificationManager.cancelAll(); + call.resolve(); + } + @PluginMethod public void createChannel(PluginCall call) { notificationChannelManager.createChannel(call); diff --git a/local-notifications/android/src/main/java/com/capacitorjs/plugins/localnotifications/NotificationChannelManager.java b/local-notifications/android/src/main/java/com/capacitorjs/plugins/localnotifications/NotificationChannelManager.java index 7ff89cf45..b2ea880f8 100644 --- a/local-notifications/android/src/main/java/com/capacitorjs/plugins/localnotifications/NotificationChannelManager.java +++ b/local-notifications/android/src/main/java/com/capacitorjs/plugins/localnotifications/NotificationChannelManager.java @@ -54,12 +54,8 @@ public void createChannel(PluginCall call) { call.reject("Channel missing name"); return; } - if (call.getInt(CHANNEL_IMPORTANCE) != null) { - channel.put(CHANNEL_IMPORTANCE, call.getInt(CHANNEL_IMPORTANCE)); - } else { - call.reject("Channel missing importance"); - return; - } + + channel.put(CHANNEL_IMPORTANCE, call.getInt(CHANNEL_IMPORTANCE, NotificationManager.IMPORTANCE_DEFAULT)); channel.put(CHANNEL_DESCRIPTION, call.getString(CHANNEL_DESCRIPTION, "")); channel.put(CHANNEL_VISIBILITY, call.getInt(CHANNEL_VISIBILITY, NotificationCompat.VISIBILITY_PUBLIC)); channel.put(CHANNEL_SOUND, call.getString(CHANNEL_SOUND, null)); diff --git a/local-notifications/android/src/main/java/com/capacitorjs/plugins/localnotifications/NotificationStorage.java b/local-notifications/android/src/main/java/com/capacitorjs/plugins/localnotifications/NotificationStorage.java index 550ef006b..74ab38faf 100644 --- a/local-notifications/android/src/main/java/com/capacitorjs/plugins/localnotifications/NotificationStorage.java +++ b/local-notifications/android/src/main/java/com/capacitorjs/plugins/localnotifications/NotificationStorage.java @@ -92,7 +92,12 @@ public JSObject getNotificationFromJSONString(String notificationString) { public JSObject getSavedNotificationAsJSObject(String key) { SharedPreferences storage = getStorage(NOTIFICATION_STORE_ID); - String notificationString = storage.getString(key, null); + String notificationString; + try { + notificationString = storage.getString(key, null); + } catch (ClassCastException ex) { + return null; + } if (notificationString == null) { return null; diff --git a/local-notifications/android/src/main/java/com/capacitorjs/plugins/localnotifications/TimedNotificationPublisher.java b/local-notifications/android/src/main/java/com/capacitorjs/plugins/localnotifications/TimedNotificationPublisher.java index 7c68e2c52..8ab082449 100644 --- a/local-notifications/android/src/main/java/com/capacitorjs/plugins/localnotifications/TimedNotificationPublisher.java +++ b/local-notifications/android/src/main/java/com/capacitorjs/plugins/localnotifications/TimedNotificationPublisher.java @@ -7,6 +7,7 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; +import android.os.Build; import com.getcapacitor.JSObject; import com.getcapacitor.Logger; import java.text.SimpleDateFormat; @@ -28,6 +29,8 @@ public class TimedNotificationPublisher extends BroadcastReceiver { public void onReceive(Context context, Intent intent) { NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); Notification notification = intent.getParcelableExtra(NOTIFICATION_KEY); + notification.when = System.currentTimeMillis(); + int id = intent.getIntExtra(LocalNotificationManager.NOTIFICATION_INTENT_KEY, Integer.MIN_VALUE); if (id == Integer.MIN_VALUE) { Logger.error(Logger.tags("LN"), "No valid id supplied", null); @@ -48,8 +51,16 @@ private boolean rescheduleNotificationIfNeeded(Context context, Intent intent, i AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); long trigger = date.nextTrigger(new Date()); Intent clone = (Intent) intent.clone(); - PendingIntent pendingIntent = PendingIntent.getBroadcast(context, id, clone, PendingIntent.FLAG_CANCEL_CURRENT); - alarmManager.setExact(AlarmManager.RTC, trigger, pendingIntent); + int flags = PendingIntent.FLAG_CANCEL_CURRENT; + if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + flags = flags | PendingIntent.FLAG_MUTABLE; + } + PendingIntent pendingIntent = PendingIntent.getBroadcast(context, id, clone, flags); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && !alarmManager.canScheduleExactAlarms()) { + alarmManager.set(AlarmManager.RTC, trigger, pendingIntent); + } else { + alarmManager.setExact(AlarmManager.RTC, trigger, pendingIntent); + } SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); Logger.debug(Logger.tags("LN"), "notification " + id + " will next fire at " + sdf.format(new Date(trigger))); return true; diff --git a/local-notifications/android/src/main/res/drawable/ic_transparent.xml b/local-notifications/android/src/main/res/drawable/ic_transparent.xml new file mode 100644 index 000000000..fc1779e2b --- /dev/null +++ b/local-notifications/android/src/main/res/drawable/ic_transparent.xml @@ -0,0 +1,12 @@ + + + + + + diff --git a/local-notifications/ios/Plugin.xcodeproj/project.pbxproj b/local-notifications/ios/Plugin.xcodeproj/project.pbxproj index 027ff9b47..42802111d 100644 --- a/local-notifications/ios/Plugin.xcodeproj/project.pbxproj +++ b/local-notifications/ios/Plugin.xcodeproj/project.pbxproj @@ -387,7 +387,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -448,7 +448,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; @@ -471,12 +471,13 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Plugin/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks $(FRAMEWORK_SEARCH_PATHS)\n$(FRAMEWORK_SEARCH_PATHS)\n$(FRAMEWORK_SEARCH_PATHS)"; ONLY_ACTIVE_ARCH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.getcapacitor.Plugin; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; + SUPPORTS_MACCATALYST = NO; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -496,12 +497,13 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Plugin/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks $(FRAMEWORK_SEARCH_PATHS)"; ONLY_ACTIVE_ARCH = NO; PRODUCT_BUNDLE_IDENTIFIER = com.getcapacitor.Plugin; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; + SUPPORTS_MACCATALYST = NO; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; diff --git a/local-notifications/ios/Plugin/LocalNotificationsPlugin.m b/local-notifications/ios/Plugin/LocalNotificationsPlugin.m index 21150d9b6..957b430eb 100644 --- a/local-notifications/ios/Plugin/LocalNotificationsPlugin.m +++ b/local-notifications/ios/Plugin/LocalNotificationsPlugin.m @@ -9,8 +9,11 @@ CAP_PLUGIN_METHOD(getPending, CAPPluginReturnPromise); CAP_PLUGIN_METHOD(registerActionTypes, CAPPluginReturnPromise); CAP_PLUGIN_METHOD(areEnabled, CAPPluginReturnPromise); + CAP_PLUGIN_METHOD(getDeliveredNotifications, CAPPluginReturnPromise); + CAP_PLUGIN_METHOD(removeAllDeliveredNotifications, CAPPluginReturnPromise); + CAP_PLUGIN_METHOD(removeDeliveredNotifications, CAPPluginReturnPromise); CAP_PLUGIN_METHOD(createChannel, CAPPluginReturnPromise); CAP_PLUGIN_METHOD(deleteChannel, CAPPluginReturnPromise); CAP_PLUGIN_METHOD(listChannels, CAPPluginReturnPromise); - CAP_PLUGIN_METHOD(removeAllListeners, CAPPluginReturnNone); + CAP_PLUGIN_METHOD(removeAllListeners, CAPPluginReturnPromise); ) diff --git a/local-notifications/ios/Plugin/LocalNotificationsPlugin.swift b/local-notifications/ios/Plugin/LocalNotificationsPlugin.swift index d1ecfe125..1c255ecf9 100644 --- a/local-notifications/ios/Plugin/LocalNotificationsPlugin.swift +++ b/local-notifications/ios/Plugin/LocalNotificationsPlugin.swift @@ -227,7 +227,7 @@ public class LocalNotificationsPlugin: CAPPlugin { content.threadIdentifier = threadIdentifier } - if #available(iOS 12, *), let summaryArgument = notification["summaryArgument"] as? String { + if let summaryArgument = notification["summaryArgument"] as? String { content.summaryArgument = summaryArgument } @@ -549,6 +549,45 @@ public class LocalNotificationsPlugin: CAPPlugin { return opts } + /** + * Get notifications in Notification Center + */ + @objc func getDeliveredNotifications(_ call: CAPPluginCall) { + UNUserNotificationCenter.current().getDeliveredNotifications(completionHandler: { (notifications) in + let ret = notifications.map({ (notification) -> [String: Any] in + return self.notificationDelegationHandler.makeNotificationRequestJSObject(notification.request) + }) + call.resolve([ + "notifications": ret + ]) + }) + } + + /** + * Remove specified notifications from Notification Center + */ + @objc func removeDeliveredNotifications(_ call: CAPPluginCall) { + guard let notifications = call.getArray("notifications", JSObject.self) else { + call.reject("Must supply notifications to remove") + return + } + + let ids = notifications.map { "\($0["id"] ?? "")" } + UNUserNotificationCenter.current().removeDeliveredNotifications(withIdentifiers: ids) + call.resolve() + } + + /** + * Remove all notifications from Notification Center + */ + @objc func removeAllDeliveredNotifications(_ call: CAPPluginCall) { + UNUserNotificationCenter.current().removeAllDeliveredNotifications() + DispatchQueue.main.async(execute: { + UIApplication.shared.applicationIconBadgeNumber = 0 + }) + call.resolve() + } + @objc func createChannel(_ call: CAPPluginCall) { call.unimplemented() } diff --git a/local-notifications/ios/Podfile b/local-notifications/ios/Podfile index 54a00c161..dee40960f 100644 --- a/local-notifications/ios/Podfile +++ b/local-notifications/ios/Podfile @@ -1,4 +1,4 @@ -platform :ios, '12.0' +platform :ios, '13.0' def capacitor_pods # Comment the next line if you're not using Swift and don't want to use dynamic frameworks diff --git a/local-notifications/package.json b/local-notifications/package.json index f1ed62e27..3e4e2a852 100644 --- a/local-notifications/package.json +++ b/local-notifications/package.json @@ -1,6 +1,6 @@ { "name": "@capacitor/local-notifications", - "version": "1.1.0", + "version": "4.1.3", "description": "The Local Notifications API provides a way to schedule device notifications locally (i.e. without a server sending push notifications).", "main": "dist/plugin.cjs.js", "module": "dist/esm/index.js", @@ -29,7 +29,7 @@ ], "scripts": { "verify": "npm run verify:ios && npm run verify:android && npm run verify:web", - "verify:ios": "cd ios && pod install && xcodebuild -workspace Plugin.xcworkspace -scheme Plugin && cd ..", + "verify:ios": "cd ios && pod install && xcodebuild -workspace Plugin.xcworkspace -scheme Plugin -destination generic/platform=iOS && cd ..", "verify:android": "cd android && ./gradlew clean build test && cd ..", "verify:web": "npm run build", "lint": "npm run eslint && npm run prettier -- --check && npm run swiftlint -- lint", @@ -45,11 +45,11 @@ "publish:cocoapod": "pod trunk push ./CapacitorLocalNotifications.podspec --allow-warnings" }, "devDependencies": { - "@capacitor/android": "^3.0.0", - "@capacitor/cli": "^3.0.0", - "@capacitor/core": "^3.0.0", - "@capacitor/docgen": "0.0.18", - "@capacitor/ios": "^3.0.0", + "@capacitor/android": "^4.0.0", + "@capacitor/cli": "^4.0.0", + "@capacitor/core": "^4.0.0", + "@capacitor/docgen": "0.2.0", + "@capacitor/ios": "^4.0.0", "@ionic/eslint-config": "^0.3.0", "@ionic/prettier-config": "~1.0.1", "@ionic/swiftlint-config": "^1.1.2", @@ -62,7 +62,7 @@ "typescript": "~4.1.5" }, "peerDependencies": { - "@capacitor/core": "^3.0.0" + "@capacitor/core": "^4.0.0" }, "prettier": "@ionic/prettier-config", "swiftlint": "@ionic/swiftlint-config", diff --git a/local-notifications/src/definitions.ts b/local-notifications/src/definitions.ts index ccc17ff9c..6f4cd472e 100644 --- a/local-notifications/src/definitions.ts +++ b/local-notifications/src/definitions.ts @@ -91,6 +91,29 @@ export interface LocalNotificationsPlugin { */ areEnabled(): Promise; + /** + * Get a list of notifications that are visible on the notifications screen. + * + * @since 4.0.0 + */ + getDeliveredNotifications(): Promise; + + /** + * Remove the specified notifications from the notifications screen. + * + * @since 4.0.0 + */ + removeDeliveredNotifications( + delivered: DeliveredNotifications, + ): Promise; + + /** + * Remove all the notifications from the notifications screen. + * + * @since 4.0.0 + */ + removeAllDeliveredNotifications(): Promise; + /** * Create a notification channel. * @@ -98,7 +121,7 @@ export interface LocalNotificationsPlugin { * * @since 1.0.0 */ - createChannel(channel: NotificationChannel): Promise; + createChannel(channel: Channel): Promise; /** * Delete a notification channel. @@ -107,7 +130,7 @@ export interface LocalNotificationsPlugin { * * @since 1.0.0 */ - deleteChannel(channel: NotificationChannel): Promise; + deleteChannel(args: { id: string }): Promise; /** * Get a list of notification channels. @@ -630,7 +653,7 @@ export interface LocalNotificationSchema { * Sets `summaryArgument` on the * [`UNMutableNotificationContent`](https://developer.apple.com/documentation/usernotifications/unmutablenotificationcontent). * - * Only available for iOS 12+. + * Only available for iOS. * * @since 1.0.0 */ @@ -856,6 +879,121 @@ export interface EnabledResult { value: boolean; } +export interface DeliveredNotificationSchema { + /** + * The notification identifier. + * + * @since 4.0.0 + */ + id: number; + + /** + * The notification tag. + * + * Only available on Android. + * + * @since 4.0.0 + */ + tag?: string; + /** + * The title of the notification. + * + * @since 4.0.0 + */ + title: string; + + /** + * The body of the notification, shown below the title. + * + * @since 4.0.0 + */ + body: string; + + /** + * The configured group of the notification. + * + * + * Only available for Android. + * + * @since 4.0.0 + */ + group?: string; + + /** + * If this notification is the summary for a group of notifications. + * + * Only available for Android. + * + * @since 4.0.0 + */ + groupSummary?: boolean; + + /** + * Any additional data that was included in the + * notification payload. + * + * Only available for Android. + * + * @since 4.0.0 + */ + data?: any; + + /** + * Extra data to store within this notification. + * + * Only available for iOS. + * + * @since 4.0.0 + */ + extra?: any; + + /** + * The attachments for this notification. + * + * Only available for iOS. + * + * @since 1.0.0 + */ + attachments?: Attachment[]; + + /** + * Action type ssociated with this notification. + * + * Only available for iOS. + * + * @since 4.0.0 + */ + actionTypeId?: string; + + /** + * Schedule used to fire this notification. + * + * Only available for iOS. + * + * @since 4.0.0 + */ + schedule?: Schedule; + + /** + * Sound that was used when the notification was displayed. + * + * Only available for iOS. + * + * @since 4.0.0 + */ + sound?: string; +} + +export interface DeliveredNotifications { + /** + * List of notifications that are visible on the + * notifications screen. + * + * @since 1.0.0 + */ + notifications: DeliveredNotificationSchema[]; +} + export interface Channel { /** * The channel identifier. @@ -897,9 +1035,10 @@ export interface Channel { /** * The level of interruption for notifications posted to this channel. * + * @default `3` * @since 1.0.0 */ - importance: Importance; + importance?: Importance; /** * The visibility of notifications posted to this channel. diff --git a/local-notifications/src/web.ts b/local-notifications/src/web.ts index a2c7e7a05..87cf4ec98 100644 --- a/local-notifications/src/web.ts +++ b/local-notifications/src/web.ts @@ -2,6 +2,7 @@ import { WebPlugin } from '@capacitor/core'; import type { PermissionState } from '@capacitor/core'; import type { + DeliveredNotifications, EnabledResult, ListChannelsResult, LocalNotificationSchema, @@ -17,7 +18,41 @@ export class LocalNotificationsWeb implements LocalNotificationsPlugin { protected pending: LocalNotificationSchema[] = []; - + protected deliveredNotifications: Notification[] = []; + + async getDeliveredNotifications(): Promise { + const deliveredSchemas = []; + for (const notification of this.deliveredNotifications) { + const deliveredSchema: LocalNotificationSchema = { + title: notification.title, + id: parseInt(notification.tag), + body: notification.body, + }; + deliveredSchemas.push(deliveredSchema); + } + return { + notifications: deliveredSchemas, + }; + } + async removeDeliveredNotifications( + delivered: DeliveredNotifications, + ): Promise { + for (const toRemove of delivered.notifications) { + const found = this.deliveredNotifications.find( + n => n.tag === String(toRemove.id), + ); + found?.close(); + this.deliveredNotifications = this.deliveredNotifications.filter( + () => !found, + ); + } + } + async removeAllDeliveredNotifications(): Promise { + for (const notification of this.deliveredNotifications) { + notification.close(); + } + this.deliveredNotifications = []; + } async createChannel(): Promise { throw this.unimplemented('Not implemented on web.'); } @@ -165,6 +200,7 @@ export class LocalNotificationsWeb ): Notification { const localNotification = new Notification(notification.title, { body: notification.body, + tag: String(notification.id), }); localNotification.addEventListener( 'click', @@ -176,6 +212,16 @@ export class LocalNotificationsWeb this.onShow.bind(this, notification), false, ); + localNotification.addEventListener( + 'close', + () => { + this.deliveredNotifications = this.deliveredNotifications.filter( + () => !this, + ); + }, + false, + ); + this.deliveredNotifications.push(localNotification); return localNotification; } diff --git a/motion/CHANGELOG.md b/motion/CHANGELOG.md index c7c46b839..5798aa3b6 100644 --- a/motion/CHANGELOG.md +++ b/motion/CHANGELOG.md @@ -3,6 +3,75 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [4.0.2](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/motion@1.0.5...@capacitor/motion@4.0.2) (2022-11-16) + + + +## 4.0.1 (2022-07-28) + + + +# 4.0.0 (2022-07-27) + + + +# 4.0.0-beta.2 (2022-07-08) + + + +# 4.0.0-beta.0 (2022-06-27) + +**Note:** Version bump only for package @capacitor/motion + + + + + +## [4.0.1](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0...4.0.1) (2022-07-28) + +**Note:** Version bump only for package @capacitor/motion + + + + + +# [4.0.0](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0-beta.2...4.0.0) (2022-07-27) + +**Note:** Version bump only for package @capacitor/motion + + + + + +# [4.0.0-beta.2](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0-beta.0...4.0.0-beta.2) (2022-07-08) + +**Note:** Version bump only for package @capacitor/motion + + + + + +# 4.0.0-beta.0 (2022-06-27) + + +### Bug Fixes + +* add es2017 lib to tsconfig ([#180](https://github.com/ionic-team/capacitor-plugins/issues/180)) ([2c3776c](https://github.com/ionic-team/capacitor-plugins/commit/2c3776c38ca025c5ee965dec10ccf1cdb6c02e2f)) +* better ignore rules for npm distribution ([#32](https://github.com/ionic-team/capacitor-plugins/issues/32)) ([b8d55b9](https://github.com/ionic-team/capacitor-plugins/commit/b8d55b9233e4ad7b8a1cd41110b4e580fc2a059f)) +* correct addListeners links ([#655](https://github.com/ionic-team/capacitor-plugins/issues/655)) ([f9871e7](https://github.com/ionic-team/capacitor-plugins/commit/f9871e7bd53478addb21155e148829f550c0e457)) +* inline source code in esm map files ([#760](https://github.com/ionic-team/capacitor-plugins/issues/760)) ([a960489](https://github.com/ionic-team/capacitor-plugins/commit/a960489a19db0182b90d187a50deff9dfbe51038)) +* support deprecated types from Capacitor 2 ([#139](https://github.com/ionic-team/capacitor-plugins/issues/139)) ([2d7127a](https://github.com/ionic-team/capacitor-plugins/commit/2d7127a488e26f0287951921a6db47c49d817336)) + + +### Features + +* add commonjs output format ([#179](https://github.com/ionic-team/capacitor-plugins/issues/179)) ([8e9e098](https://github.com/ionic-team/capacitor-plugins/commit/8e9e09862064b3f6771d7facbc4008e995d9b463)) +* Motion plugin ([#17](https://github.com/ionic-team/capacitor-plugins/issues/17)) ([21ace16](https://github.com/ionic-team/capacitor-plugins/commit/21ace1670b803eec3a8d41d06c32933a170bf4be)) + + + + + ## [1.0.5](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/motion@1.0.4...@capacitor/motion@1.0.5) (2022-01-19) diff --git a/motion/package.json b/motion/package.json index 741880f6f..8e8be5810 100644 --- a/motion/package.json +++ b/motion/package.json @@ -1,6 +1,6 @@ { "name": "@capacitor/motion", - "version": "1.0.5", + "version": "4.0.2", "description": "The Motion API tracks accelerometer and device orientation (compass heading, etc.)", "main": "dist/plugin.cjs.js", "module": "dist/esm/index.js", @@ -39,10 +39,10 @@ "prepublishOnly": "npm run build" }, "devDependencies": { - "@capacitor/android": "^3.0.0", - "@capacitor/core": "^3.0.0", - "@capacitor/docgen": "0.0.18", - "@capacitor/ios": "^3.0.0", + "@capacitor/android": "^4.0.0", + "@capacitor/core": "^4.0.0", + "@capacitor/docgen": "0.2.0", + "@capacitor/ios": "^4.0.0", "@ionic/eslint-config": "^0.3.0", "@ionic/prettier-config": "~1.0.1", "eslint": "^7.11.0", @@ -53,7 +53,7 @@ "typescript": "~4.1.5" }, "peerDependencies": { - "@capacitor/core": "^3.0.0" + "@capacitor/core": "^4.0.0" }, "prettier": "@ionic/prettier-config", "eslintConfig": { diff --git a/network/CHANGELOG.md b/network/CHANGELOG.md index 88de1d7d3..2ef46e723 100644 --- a/network/CHANGELOG.md +++ b/network/CHANGELOG.md @@ -3,6 +3,93 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.1.0](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/network@1.0.7...@capacitor/network@4.1.0) (2022-11-16) + + + +## 4.0.1 (2022-07-28) + + + +# 4.0.0 (2022-07-27) + + + +# 4.0.0-beta.2 (2022-07-08) + + + +# 4.0.0-beta.0 (2022-06-27) + + +### Bug Fixes + +* Make removeAllListeners return a promise ([#895](https://github.com/ionic-team/capacitor-plugins/issues/895)) ([e5c49d6](https://github.com/ionic-team/capacitor-plugins/commit/e5c49d64445dca70286334e6a0441d8021197b13)) + + +### Features + +* set targetSDK default value to 31 ([#824](https://github.com/ionic-team/capacitor-plugins/issues/824)) ([3ee10de](https://github.com/ionic-team/capacitor-plugins/commit/3ee10de98067984c1a4e75295d001c5a895c47f4)) +* set targetSDK default value to 32 ([#970](https://github.com/ionic-team/capacitor-plugins/issues/970)) ([fa70d96](https://github.com/ionic-team/capacitor-plugins/commit/fa70d96f141af751aae53ceb5642c46b204f5958)) +* Upgrade gradle to 7.4 ([#826](https://github.com/ionic-team/capacitor-plugins/issues/826)) ([5db0906](https://github.com/ionic-team/capacitor-plugins/commit/5db0906f6264287c4f8e69dbaecf19d4d387824b)) +* Use java 11 ([#910](https://github.com/ionic-team/capacitor-plugins/issues/910)) ([5acb2a2](https://github.com/ionic-team/capacitor-plugins/commit/5acb2a288a413492b163e4e97da46a085d9e4be0)) + + + + + +## [4.0.1](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0...4.0.1) (2022-07-28) + +**Note:** Version bump only for package @capacitor/network + + + + + +# [4.0.0](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0-beta.2...4.0.0) (2022-07-27) + +**Note:** Version bump only for package @capacitor/network + + + + + +# [4.0.0-beta.2](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0-beta.0...4.0.0-beta.2) (2022-07-08) + +**Note:** Version bump only for package @capacitor/network + + + + + +# 4.0.0-beta.0 (2022-06-27) + + +### Bug Fixes + +* inline source code in esm map files ([#760](https://github.com/ionic-team/capacitor-plugins/issues/760)) ([a960489](https://github.com/ionic-team/capacitor-plugins/commit/a960489a19db0182b90d187a50deff9dfbe51038)) +* Make removeAllListeners return a promise ([#895](https://github.com/ionic-team/capacitor-plugins/issues/895)) ([e5c49d6](https://github.com/ionic-team/capacitor-plugins/commit/e5c49d64445dca70286334e6a0441d8021197b13)) +* **network:** Don't add window event listeners if there is no window ([#678](https://github.com/ionic-team/capacitor-plugins/issues/678)) ([0c65780](https://github.com/ionic-team/capacitor-plugins/commit/0c657808083a7f4245027a2248816b3921b813bf)) +* add es2017 lib to tsconfig ([#180](https://github.com/ionic-team/capacitor-plugins/issues/180)) ([2c3776c](https://github.com/ionic-team/capacitor-plugins/commit/2c3776c38ca025c5ee965dec10ccf1cdb6c02e2f)) +* better ignore rules for npm distribution ([#32](https://github.com/ionic-team/capacitor-plugins/issues/32)) ([b8d55b9](https://github.com/ionic-team/capacitor-plugins/commit/b8d55b9233e4ad7b8a1cd41110b4e580fc2a059f)) +* correct addListeners links ([#655](https://github.com/ionic-team/capacitor-plugins/issues/655)) ([f9871e7](https://github.com/ionic-team/capacitor-plugins/commit/f9871e7bd53478addb21155e148829f550c0e457)) +* remove postpublish scripts ([#656](https://github.com/ionic-team/capacitor-plugins/issues/656)) ([ed6ac49](https://github.com/ionic-team/capacitor-plugins/commit/ed6ac499ebf4a47525071ccbfc36c27503e11f60)) +* support deprecated types from Capacitor 2 ([#139](https://github.com/ionic-team/capacitor-plugins/issues/139)) ([2d7127a](https://github.com/ionic-team/capacitor-plugins/commit/2d7127a488e26f0287951921a6db47c49d817336)) + + +### Features + +* add commonjs output format ([#179](https://github.com/ionic-team/capacitor-plugins/issues/179)) ([8e9e098](https://github.com/ionic-team/capacitor-plugins/commit/8e9e09862064b3f6771d7facbc4008e995d9b463)) +* Network plugin ([#8](https://github.com/ionic-team/capacitor-plugins/issues/8)) ([08d9891](https://github.com/ionic-team/capacitor-plugins/commit/08d9891710d576ee3c660b4d8dce89c4169d3e0b)) +* set targetSDK default value to 31 ([#824](https://github.com/ionic-team/capacitor-plugins/issues/824)) ([3ee10de](https://github.com/ionic-team/capacitor-plugins/commit/3ee10de98067984c1a4e75295d001c5a895c47f4)) +* set targetSDK default value to 32 ([#970](https://github.com/ionic-team/capacitor-plugins/issues/970)) ([fa70d96](https://github.com/ionic-team/capacitor-plugins/commit/fa70d96f141af751aae53ceb5642c46b204f5958)) +* Upgrade gradle to 7.4 ([#826](https://github.com/ionic-team/capacitor-plugins/issues/826)) ([5db0906](https://github.com/ionic-team/capacitor-plugins/commit/5db0906f6264287c4f8e69dbaecf19d4d387824b)) +* Use java 11 ([#910](https://github.com/ionic-team/capacitor-plugins/issues/910)) ([5acb2a2](https://github.com/ionic-team/capacitor-plugins/commit/5acb2a288a413492b163e4e97da46a085d9e4be0)) + + + + + ## [1.0.7](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/network@1.0.6...@capacitor/network@1.0.7) (2022-01-19) diff --git a/network/CapacitorNetwork.podspec b/network/CapacitorNetwork.podspec index b6711de98..93a75f381 100644 --- a/network/CapacitorNetwork.podspec +++ b/network/CapacitorNetwork.podspec @@ -11,8 +11,7 @@ Pod::Spec.new do |s| s.author = package['author'] s.source = { :git => 'https://github.com/ionic-team/capacitor-plugins.git', :tag => package['name'] + '@' + package['version'] } s.source_files = 'ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}', 'network/ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}' - s.ios.deployment_target = '12.0' + s.ios.deployment_target = '13.0' s.dependency 'Capacitor' - s.dependency 'ReachabilitySwift', '~> 5.0' s.swift_version = '5.1' end diff --git a/network/android/build.gradle b/network/android/build.gradle index 56ee0b28b..43252f49c 100644 --- a/network/android/build.gradle +++ b/network/android/build.gradle @@ -1,27 +1,39 @@ ext { - junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.1' - androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.2.0' - androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.1.2' - androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.3.0' + capacitorVersion = System.getenv('CAPACITOR_VERSION') + junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.2' + androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.4.2' + androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.1.3' + androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.4.0' } buildscript { repositories { google() mavenCentral() + maven { + url "https://plugins.gradle.org/m2/" + } } dependencies { - classpath 'com.android.tools.build:gradle:4.2.1' + classpath 'com.android.tools.build:gradle:7.2.1' + if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + classpath 'io.github.gradle-nexus:publish-plugin:1.1.0' + } } } apply plugin: 'com.android.library' +if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + apply plugin: 'io.github.gradle-nexus.publish-plugin' + apply from: file('../../scripts/android/publish-root.gradle') + apply from: file('../../scripts/android/publish-module.gradle') +} android { - compileSdkVersion project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 30 + compileSdkVersion project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 32 defaultConfig { - minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 21 - targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 30 + minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 22 + targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 32 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" @@ -36,21 +48,26 @@ android { abortOnError false } compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility JavaVersion.VERSION_11 + targetCompatibility JavaVersion.VERSION_11 } } repositories { google() mavenCentral() - jcenter() } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation project(':capacitor-android') + + if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + implementation "com.capacitorjs:core:$capacitorVersion" + } else { + implementation project(':capacitor-android') + } + implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion" testImplementation "junit:junit:$junitVersion" androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion" diff --git a/network/android/gradle/wrapper/gradle-wrapper.jar b/network/android/gradle/wrapper/gradle-wrapper.jar index e708b1c02..41d9927a4 100644 Binary files a/network/android/gradle/wrapper/gradle-wrapper.jar and b/network/android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/network/android/gradle/wrapper/gradle-wrapper.properties b/network/android/gradle/wrapper/gradle-wrapper.properties index 3c4101c3e..92f06b50f 100644 --- a/network/android/gradle/wrapper/gradle-wrapper.properties +++ b/network/android/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/network/android/gradlew b/network/android/gradlew index 4f906e0c8..1b6c78733 100755 --- a/network/android/gradlew +++ b/network/android/gradlew @@ -1,7 +1,7 @@ -#!/usr/bin/env sh +#!/bin/sh # -# Copyright 2015 the original author or authors. +# Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,67 +17,101 @@ # ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` +APP_BASE_NAME=${0##*/} # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar @@ -87,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -98,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" + JAVACMD=java which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the @@ -106,80 +140,95 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=`expr $i + 1` + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" diff --git a/network/android/src/main/java/com/capacitorjs/plugins/network/Network.java b/network/android/src/main/java/com/capacitorjs/plugins/network/Network.java index 6091faa70..decfd702f 100644 --- a/network/android/src/main/java/com/capacitorjs/plugins/network/Network.java +++ b/network/android/src/main/java/com/capacitorjs/plugins/network/Network.java @@ -1,13 +1,17 @@ package com.capacitorjs.plugins.network; +import android.annotation.TargetApi; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.net.ConnectivityManager; -import android.net.NetworkInfo; +import android.net.ConnectivityManager.NetworkCallback; +import android.net.NetworkCapabilities; +import android.os.Build; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; import androidx.appcompat.app.AppCompatActivity; public class Network { @@ -16,12 +20,29 @@ public class Network { * Interface for callbacks when network status changes. */ interface NetworkStatusChangeListener { - void onNetworkStatusChanged(); + void onNetworkStatusChanged(boolean wasLostEvent); + } + + class ConnectivityCallback extends NetworkCallback { + + @Override + public void onLost(@NonNull android.net.Network network) { + super.onLost(network); + statusChangeListener.onNetworkStatusChanged(true); + } + + @Override + public void onCapabilitiesChanged(@NonNull android.net.Network network, @NonNull NetworkCapabilities networkCapabilities) { + super.onCapabilitiesChanged(network, networkCapabilities); + statusChangeListener.onNetworkStatusChanged(false); + } } @Nullable private NetworkStatusChangeListener statusChangeListener; + private ConnectivityCallback connectivityCallback; + private Context context; private ConnectivityManager connectivityManager; private BroadcastReceiver receiver; @@ -29,15 +50,21 @@ interface NetworkStatusChangeListener { * Create network monitoring object. * @param context */ + @SuppressWarnings("deprecation") public Network(@NonNull Context context) { - connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); - receiver = - new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - statusChangeListener.onNetworkStatusChanged(); - } - }; + this.context = context; + this.connectivityManager = (ConnectivityManager) this.context.getSystemService(Context.CONNECTIVITY_SERVICE); + if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M) { + receiver = + new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + statusChangeListener.onNetworkStatusChanged(false); + } + }; + } else { + this.connectivityCallback = new ConnectivityCallback(); + } } /** @@ -59,25 +86,73 @@ public NetworkStatusChangeListener getStatusChangeListener() { /** * Get the current network information. - * @return NetworkInfo + * @return NetworkStatus */ - public NetworkInfo getNetworkStatus() { - return connectivityManager.getActiveNetworkInfo(); + public NetworkStatus getNetworkStatus() { + NetworkStatus networkStatus = new NetworkStatus(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + if (this.connectivityManager != null) { + android.net.Network activeNetwork = this.connectivityManager.getActiveNetwork(); + NetworkCapabilities capabilities = + this.connectivityManager.getNetworkCapabilities(this.connectivityManager.getActiveNetwork()); + if (activeNetwork != null && capabilities != null) { + networkStatus.connected = + capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED) && + capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); + if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) { + networkStatus.connectionType = NetworkStatus.ConnectionType.WIFI; + } else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) { + networkStatus.connectionType = NetworkStatus.ConnectionType.CELLULAR; + } else { + networkStatus.connectionType = NetworkStatus.ConnectionType.UNKNOWN; + } + } + } + } else { + networkStatus = getAndParseNetworkInfo(); + } + return networkStatus; + } + + @SuppressWarnings("deprecation") + private NetworkStatus getAndParseNetworkInfo() { + NetworkStatus networkStatus = new NetworkStatus(); + android.net.NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo(); + if (networkInfo != null) { + networkStatus.connected = networkInfo.isConnected(); + String typeName = networkInfo.getTypeName(); + if (typeName.equals("WIFI")) { + networkStatus.connectionType = NetworkStatus.ConnectionType.WIFI; + } else if (typeName.equals("MOBILE")) { + networkStatus.connectionType = NetworkStatus.ConnectionType.CELLULAR; + } + } + return networkStatus; } /** - * Register a Intent Receiver in the activity. - * @param activity + * Register a network callback. */ - public void startMonitoring(@NonNull AppCompatActivity activity) { - IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION); + @RequiresApi(api = Build.VERSION_CODES.N) + public void startMonitoring() { + connectivityManager.registerDefaultNetworkCallback(connectivityCallback); + } + + @TargetApi(Build.VERSION_CODES.M) + public void startMonitoring(AppCompatActivity activity) { + IntentFilter filter = new IntentFilter("android.net.conn.CONNECTIVITY_CHANGE"); activity.registerReceiver(receiver, filter); } /** - * Unregister the IntentReceiver to avoid leaking it. - * @param activity + * Unregister the network callback. */ + @RequiresApi(api = Build.VERSION_CODES.N) + public void stopMonitoring() { + connectivityManager.unregisterNetworkCallback(connectivityCallback); + } + + @TargetApi(Build.VERSION_CODES.M) public void stopMonitoring(@NonNull AppCompatActivity activity) { activity.unregisterReceiver(receiver); } diff --git a/network/android/src/main/java/com/capacitorjs/plugins/network/NetworkPlugin.java b/network/android/src/main/java/com/capacitorjs/plugins/network/NetworkPlugin.java index 1c3162c95..93096b08f 100644 --- a/network/android/src/main/java/com/capacitorjs/plugins/network/NetworkPlugin.java +++ b/network/android/src/main/java/com/capacitorjs/plugins/network/NetworkPlugin.java @@ -1,14 +1,11 @@ package com.capacitorjs.plugins.network; -import android.Manifest; -import android.net.NetworkInfo; +import android.os.Build; import com.getcapacitor.JSObject; -import com.getcapacitor.Logger; import com.getcapacitor.Plugin; import com.getcapacitor.PluginCall; import com.getcapacitor.PluginMethod; import com.getcapacitor.annotation.CapacitorPlugin; -import com.getcapacitor.annotation.Permission; @CapacitorPlugin(name = "Network") public class NetworkPlugin extends Plugin { @@ -22,7 +19,17 @@ public class NetworkPlugin extends Plugin { @Override public void load() { implementation = new Network(getContext()); - implementation.setStatusChangeListener(this::updateNetworkStatus); + Network.NetworkStatusChangeListener listener = wasLostEvent -> { + if (wasLostEvent) { + JSObject jsObject = new JSObject(); + jsObject.put("connected", false); + jsObject.put("connectionType", "none"); + notifyListeners(NETWORK_CHANGE_EVENT, jsObject); + } else { + updateNetworkStatus(); + } + }; + implementation.setStatusChangeListener(listener); } /** @@ -39,7 +46,7 @@ protected void handleOnDestroy() { */ @PluginMethod public void getStatus(PluginCall call) { - call.resolve(getStatusJSObject(implementation.getNetworkStatus())); + call.resolve(parseNetworkStatus(implementation.getNetworkStatus())); } /** @@ -47,7 +54,11 @@ public void getStatus(PluginCall call) { */ @Override protected void handleOnResume() { - implementation.startMonitoring(getActivity()); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + implementation.startMonitoring(); + } else { + implementation.startMonitoring(getActivity()); + } } /** @@ -55,43 +66,21 @@ protected void handleOnResume() { */ @Override protected void handleOnPause() { - implementation.stopMonitoring(getActivity()); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + implementation.stopMonitoring(); + } else { + implementation.stopMonitoring(getActivity()); + } } private void updateNetworkStatus() { - notifyListeners(NETWORK_CHANGE_EVENT, getStatusJSObject(implementation.getNetworkStatus())); - } - - /** - * Transform a NetworkInfo object into our JSObject for returning to client - * @param info - * @return - */ - private JSObject getStatusJSObject(NetworkInfo info) { - JSObject ret = new JSObject(); - if (info == null) { - ret.put("connected", false); - ret.put("connectionType", "none"); - } else { - ret.put("connected", info.isConnected()); - ret.put("connectionType", getNormalizedTypeName(info)); - } - return ret; + notifyListeners(NETWORK_CHANGE_EVENT, parseNetworkStatus(implementation.getNetworkStatus())); } - /** - * Convert the Android-specific naming for network types into our cross-platform type - * @param info - * @return - */ - private String getNormalizedTypeName(NetworkInfo info) { - String typeName = info.getTypeName(); - if (typeName.equals("WIFI")) { - return "wifi"; - } - if (typeName.equals("MOBILE")) { - return "cellular"; - } - return "none"; + private JSObject parseNetworkStatus(NetworkStatus networkStatus) { + JSObject jsObject = new JSObject(); + jsObject.put("connected", networkStatus.connected); + jsObject.put("connectionType", networkStatus.connectionType.getConnectionType()); + return jsObject; } } diff --git a/network/android/src/main/java/com/capacitorjs/plugins/network/NetworkStatus.java b/network/android/src/main/java/com/capacitorjs/plugins/network/NetworkStatus.java new file mode 100644 index 000000000..ac0a7a121 --- /dev/null +++ b/network/android/src/main/java/com/capacitorjs/plugins/network/NetworkStatus.java @@ -0,0 +1,24 @@ +package com.capacitorjs.plugins.network; + +public class NetworkStatus { + + public enum ConnectionType { + WIFI("wifi"), + CELLULAR("cellular"), + NONE("none"), + UNKNOWN("unknown"); + + private String connectionType; + + ConnectionType(String connectionType) { + this.connectionType = connectionType; + } + + public String getConnectionType() { + return this.connectionType; + } + } + + public boolean connected = false; + public ConnectionType connectionType = ConnectionType.NONE; +} diff --git a/network/ios/Plugin.xcodeproj/project.pbxproj b/network/ios/Plugin.xcodeproj/project.pbxproj index a3188a5da..0bf836b00 100644 --- a/network/ios/Plugin.xcodeproj/project.pbxproj +++ b/network/ios/Plugin.xcodeproj/project.pbxproj @@ -8,6 +8,7 @@ /* Begin PBXBuildFile section */ 03FC29A292ACC40490383A1F /* Pods_Plugin.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B2A61DA5A1F2DD4F959604D /* Pods_Plugin.framework */; }; + 0F8CFD01284F9CEC00355DD6 /* Reachability.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0F8CFD00284F9CEC00355DD6 /* Reachability.swift */; }; 20C0B05DCFC8E3958A738AF2 /* Pods_PluginTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F6753A823D3815DB436415E3 /* Pods_PluginTests.framework */; }; 2F98D68224C9AAE500613A4C /* Network.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F98D68124C9AAE400613A4C /* Network.swift */; }; 50ADFF92201F53D600D50D53 /* Plugin.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 50ADFF88201F53D600D50D53 /* Plugin.framework */; }; @@ -29,6 +30,7 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 0F8CFD00284F9CEC00355DD6 /* Reachability.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Reachability.swift; sourceTree = ""; }; 2F98D68124C9AAE400613A4C /* Network.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Network.swift; sourceTree = ""; }; 3B2A61DA5A1F2DD4F959604D /* Pods_Plugin.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Plugin.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 50ADFF88201F53D600D50D53 /* Plugin.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Plugin.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -94,6 +96,7 @@ 50ADFF8A201F53D600D50D53 /* Plugin */ = { isa = PBXGroup; children = ( + 0F8CFD00284F9CEC00355DD6 /* Reachability.swift */, 2F98D68124C9AAE400613A4C /* Network.swift */, 50E1A94720377CB70090CE1A /* NetworkPlugin.swift */, 50ADFF8B201F53D600D50D53 /* NetworkPlugin.h */, @@ -272,13 +275,11 @@ "${PODS_ROOT}/Target Support Files/Pods-PluginTests/Pods-PluginTests-frameworks.sh", "${BUILT_PRODUCTS_DIR}/Capacitor/Capacitor.framework", "${BUILT_PRODUCTS_DIR}/CapacitorCordova/Cordova.framework", - "${BUILT_PRODUCTS_DIR}/ReachabilitySwift/Reachability.framework", ); name = "[CP] Embed Pods Frameworks"; outputPaths = ( "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Capacitor.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Cordova.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Reachability.framework", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; @@ -313,6 +314,7 @@ 50E1A94820377CB70090CE1A /* NetworkPlugin.swift in Sources */, 2F98D68224C9AAE500613A4C /* Network.swift in Sources */, 50ADFFA82020EE4F00D50D53 /* NetworkPlugin.m in Sources */, + 0F8CFD01284F9CEC00355DD6 /* Reachability.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -390,7 +392,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -450,7 +452,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; @@ -473,12 +475,13 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Plugin/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks $(FRAMEWORK_SEARCH_PATHS)\n$(FRAMEWORK_SEARCH_PATHS)\n$(FRAMEWORK_SEARCH_PATHS)"; ONLY_ACTIVE_ARCH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.capacitorjs.plugins.network; PRODUCT_NAME = Plugin; SKIP_INSTALL = YES; + SUPPORTS_MACCATALYST = NO; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -498,12 +501,13 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Plugin/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks $(FRAMEWORK_SEARCH_PATHS)"; ONLY_ACTIVE_ARCH = NO; PRODUCT_BUNDLE_IDENTIFIER = com.capacitorjs.plugins.network; PRODUCT_NAME = Plugin; SKIP_INSTALL = YES; + SUPPORTS_MACCATALYST = NO; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; diff --git a/network/ios/Plugin/Network.swift b/network/ios/Plugin/Network.swift index ce18b1674..255b214c8 100644 --- a/network/ios/Plugin/Network.swift +++ b/network/ios/Plugin/Network.swift @@ -1,5 +1,4 @@ import Foundation -import Reachability public typealias NetworkConnectionChangedObserver = (Network.Connection) -> Void @@ -37,7 +36,7 @@ public class Network { fileprivate extension Reachability.Connection { var equivalentEnum: Network.Connection { switch self { - case .unavailable, .none: + case .unavailable: return .unavailable case .wifi: return .wifi diff --git a/network/ios/Plugin/NetworkPlugin.m b/network/ios/Plugin/NetworkPlugin.m index c800b5599..2879575e8 100644 --- a/network/ios/Plugin/NetworkPlugin.m +++ b/network/ios/Plugin/NetworkPlugin.m @@ -5,5 +5,5 @@ // each method the plugin supports using the CAP_PLUGIN_METHOD macro. CAP_PLUGIN(CAPNetworkPlugin, "Network", CAP_PLUGIN_METHOD(getStatus, CAPPluginReturnPromise); - CAP_PLUGIN_METHOD(removeAllListeners, CAPPluginReturnNone); + CAP_PLUGIN_METHOD(removeAllListeners, CAPPluginReturnPromise); ) diff --git a/network/ios/Plugin/Reachability.swift b/network/ios/Plugin/Reachability.swift new file mode 100644 index 000000000..23b09bb88 --- /dev/null +++ b/network/ios/Plugin/Reachability.swift @@ -0,0 +1,395 @@ +/* + Copyright (c) 2014, Ashley Mills + All rights reserved. + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + */ + +import SystemConfiguration +import Foundation + +public enum ReachabilityError: Error { + case failedToCreateWithAddress(sockaddr, Int32) + case failedToCreateWithHostname(String, Int32) + case unableToSetCallback(Int32) + case unableToSetDispatchQueue(Int32) + case unableToGetFlags(Int32) +} + +@available(*, unavailable, renamed: "Notification.Name.reachabilityChanged") +public let reachabilityChangedNotification = NSNotification.Name("ReachabilityChangedNotification") + +public extension Notification.Name { + static let reachabilityChanged = Notification.Name("reachabilityChanged") +} + +public class Reachability { + + public typealias NetworkReachable = (Reachability) -> Void + public typealias NetworkUnreachable = (Reachability) -> Void + + @available(*, unavailable, renamed: "Connection") + public enum NetworkStatus: CustomStringConvertible { + case notReachable, reachableViaWiFi, reachableViaWWAN + public var description: String { + switch self { + case .reachableViaWWAN: return "Cellular" + case .reachableViaWiFi: return "WiFi" + case .notReachable: return "No Connection" + } + } + } + + public enum Connection: CustomStringConvertible { + case unavailable, wifi, cellular + public var description: String { + switch self { + case .cellular: return "Cellular" + case .wifi: return "WiFi" + case .unavailable: return "No Connection" + } + } + + @available(*, deprecated, renamed: "unavailable") + public static let none: Connection = .unavailable + } + + public var whenReachable: NetworkReachable? + public var whenUnreachable: NetworkUnreachable? + + @available(*, deprecated, renamed: "allowsCellularConnection") + public let reachableOnWWAN: Bool = true + + /// Set to `false` to force Reachability.connection to .none when on cellular connection (default value `true`) + public var allowsCellularConnection: Bool + + // The notification center on which "reachability changed" events are being posted + public var notificationCenter: NotificationCenter = NotificationCenter.default + + @available(*, deprecated, renamed: "connection.description") + public var currentReachabilityString: String { + return "\(connection)" + } + + @available(*, unavailable, renamed: "connection") + public var currentReachabilityStatus: Connection { + return connection + } + + public var connection: Connection { + if flags == nil { + try? setReachabilityFlags() + } + + switch flags?.connection { + case .unavailable?, nil: return .unavailable + case .cellular?: return allowsCellularConnection ? .cellular : .unavailable + case .wifi?: return .wifi + } + } + + fileprivate var isRunningOnDevice: Bool = { + #if targetEnvironment(simulator) + return false + #else + return true + #endif + }() + + fileprivate(set) var notifierRunning = false + fileprivate let reachabilityRef: SCNetworkReachability + fileprivate let reachabilitySerialQueue: DispatchQueue + fileprivate let notificationQueue: DispatchQueue? + fileprivate(set) var flags: SCNetworkReachabilityFlags? { + didSet { + guard flags != oldValue else { return } + notifyReachabilityChanged() + } + } + + public required init(reachabilityRef: SCNetworkReachability, + queueQoS: DispatchQoS = .default, + targetQueue: DispatchQueue? = nil, + notificationQueue: DispatchQueue? = .main) { + self.allowsCellularConnection = true + self.reachabilityRef = reachabilityRef + self.reachabilitySerialQueue = DispatchQueue(label: "uk.co.ashleymills.reachability", qos: queueQoS, target: targetQueue) + self.notificationQueue = notificationQueue + } + + public convenience init(hostname: String, + queueQoS: DispatchQoS = .default, + targetQueue: DispatchQueue? = nil, + notificationQueue: DispatchQueue? = .main) throws { + guard let ref = SCNetworkReachabilityCreateWithName(nil, hostname) else { + throw ReachabilityError.failedToCreateWithHostname(hostname, SCError()) + } + self.init(reachabilityRef: ref, queueQoS: queueQoS, targetQueue: targetQueue, notificationQueue: notificationQueue) + } + + public convenience init(queueQoS: DispatchQoS = .default, + targetQueue: DispatchQueue? = nil, + notificationQueue: DispatchQueue? = .main) throws { + var zeroAddress = sockaddr() + zeroAddress.sa_len = UInt8(MemoryLayout.size) + zeroAddress.sa_family = sa_family_t(AF_INET) + + guard let ref = SCNetworkReachabilityCreateWithAddress(nil, &zeroAddress) else { + throw ReachabilityError.failedToCreateWithAddress(zeroAddress, SCError()) + } + + self.init(reachabilityRef: ref, queueQoS: queueQoS, targetQueue: targetQueue, notificationQueue: notificationQueue) + } + + deinit { + stopNotifier() + } +} + +public extension Reachability { + + // MARK: - *** Notifier methods *** + func startNotifier() throws { + guard !notifierRunning else { return } + + let callback: SCNetworkReachabilityCallBack = { (reachability, flags, info) in + guard let info = info else { return } + + // `weakifiedReachability` is guaranteed to exist by virtue of our + // retain/release callbacks which we provided to the `SCNetworkReachabilityContext`. + let weakifiedReachability = Unmanaged.fromOpaque(info).takeUnretainedValue() + + // The weak `reachability` _may_ no longer exist if the `Reachability` + // object has since been deallocated but a callback was already in flight. + weakifiedReachability.reachability?.flags = flags + } + + let weakifiedReachability = ReachabilityWeakifier(reachability: self) + let opaqueWeakifiedReachability = Unmanaged.passUnretained(weakifiedReachability).toOpaque() + + var context = SCNetworkReachabilityContext( + version: 0, + info: UnsafeMutableRawPointer(opaqueWeakifiedReachability), + retain: { (info: UnsafeRawPointer) -> UnsafeRawPointer in + let unmanagedWeakifiedReachability = Unmanaged.fromOpaque(info) + _ = unmanagedWeakifiedReachability.retain() + return UnsafeRawPointer(unmanagedWeakifiedReachability.toOpaque()) + }, + release: { (info: UnsafeRawPointer) -> Void in + let unmanagedWeakifiedReachability = Unmanaged.fromOpaque(info) + unmanagedWeakifiedReachability.release() + }, + copyDescription: { (info: UnsafeRawPointer) -> Unmanaged in + let unmanagedWeakifiedReachability = Unmanaged.fromOpaque(info) + let weakifiedReachability = unmanagedWeakifiedReachability.takeUnretainedValue() + let description = weakifiedReachability.reachability?.description ?? "nil" + return Unmanaged.passRetained(description as CFString) + } + ) + + if !SCNetworkReachabilitySetCallback(reachabilityRef, callback, &context) { + stopNotifier() + throw ReachabilityError.unableToSetCallback(SCError()) + } + + if !SCNetworkReachabilitySetDispatchQueue(reachabilityRef, reachabilitySerialQueue) { + stopNotifier() + throw ReachabilityError.unableToSetDispatchQueue(SCError()) + } + + // Perform an initial check + try setReachabilityFlags() + + notifierRunning = true + } + + func stopNotifier() { + defer { notifierRunning = false } + + SCNetworkReachabilitySetCallback(reachabilityRef, nil, nil) + SCNetworkReachabilitySetDispatchQueue(reachabilityRef, nil) + } + + // MARK: - *** Connection test methods *** + @available(*, deprecated, message: "Please use `connection != .none`") + var isReachable: Bool { + return connection != .unavailable + } + + @available(*, deprecated, message: "Please use `connection == .cellular`") + var isReachableViaWWAN: Bool { + // Check we're not on the simulator, we're REACHABLE and check we're on WWAN + return connection == .cellular + } + + @available(*, deprecated, message: "Please use `connection == .wifi`") + var isReachableViaWiFi: Bool { + return connection == .wifi + } + + var description: String { + return flags?.description ?? "unavailable flags" + } +} + +fileprivate extension Reachability { + + func setReachabilityFlags() throws { + try reachabilitySerialQueue.sync { [unowned self] in + var flags = SCNetworkReachabilityFlags() + if !SCNetworkReachabilityGetFlags(self.reachabilityRef, &flags) { + self.stopNotifier() + throw ReachabilityError.unableToGetFlags(SCError()) + } + + self.flags = flags + } + } + + func notifyReachabilityChanged() { + let notify = { [weak self] in + guard let self = self else { return } + self.connection != .unavailable ? self.whenReachable?(self) : self.whenUnreachable?(self) + self.notificationCenter.post(name: .reachabilityChanged, object: self) + } + + // notify on the configured `notificationQueue`, or the caller's (i.e. `reachabilitySerialQueue`) + notificationQueue?.async(execute: notify) ?? notify() + } +} + +extension SCNetworkReachabilityFlags { + + typealias Connection = Reachability.Connection + + var connection: Connection { + guard isReachableFlagSet else { return .unavailable } + + // If we're reachable, but not on an iOS device (i.e. simulator), we must be on WiFi + #if targetEnvironment(simulator) + return .wifi + #else + var connection = Connection.unavailable + + if !isConnectionRequiredFlagSet { + connection = .wifi + } + + if isConnectionOnTrafficOrDemandFlagSet { + if !isInterventionRequiredFlagSet { + connection = .wifi + } + } + + if isOnWWANFlagSet { + connection = .cellular + } + + return connection + #endif + } + + var isOnWWANFlagSet: Bool { + #if os(iOS) + return contains(.isWWAN) + #else + return false + #endif + } + var isReachableFlagSet: Bool { + return contains(.reachable) + } + var isConnectionRequiredFlagSet: Bool { + return contains(.connectionRequired) + } + var isInterventionRequiredFlagSet: Bool { + return contains(.interventionRequired) + } + var isConnectionOnTrafficFlagSet: Bool { + return contains(.connectionOnTraffic) + } + var isConnectionOnDemandFlagSet: Bool { + return contains(.connectionOnDemand) + } + var isConnectionOnTrafficOrDemandFlagSet: Bool { + return !intersection([.connectionOnTraffic, .connectionOnDemand]).isEmpty + } + var isTransientConnectionFlagSet: Bool { + return contains(.transientConnection) + } + var isLocalAddressFlagSet: Bool { + return contains(.isLocalAddress) + } + var isDirectFlagSet: Bool { + return contains(.isDirect) + } + var isConnectionRequiredAndTransientFlagSet: Bool { + return intersection([.connectionRequired, .transientConnection]) == [.connectionRequired, .transientConnection] + } + + // swiftlint:disable identifier_name + var description: String { + let W = isOnWWANFlagSet ? "W" : "-" + let R = isReachableFlagSet ? "R" : "-" + let c = isConnectionRequiredFlagSet ? "c" : "-" + let t = isTransientConnectionFlagSet ? "t" : "-" + let i = isInterventionRequiredFlagSet ? "i" : "-" + let C = isConnectionOnTrafficFlagSet ? "C" : "-" + let D = isConnectionOnDemandFlagSet ? "D" : "-" + let l = isLocalAddressFlagSet ? "l" : "-" + let d = isDirectFlagSet ? "d" : "-" + + return "\(W)\(R) \(c)\(t)\(i)\(C)\(D)\(l)\(d)" + } + // swiftlint:enable identifier_name +} + +/** + `ReachabilityWeakifier` weakly wraps the `Reachability` class + in order to break retain cycles when interacting with CoreFoundation. + CoreFoundation callbacks expect a pair of retain/release whenever an + opaque `info` parameter is provided. These callbacks exist to guard + against memory management race conditions when invoking the callbacks. + #### Race Condition + If we passed `SCNetworkReachabilitySetCallback` a direct reference to our + `Reachability` class without also providing corresponding retain/release + callbacks, then a race condition can lead to crashes when: + - `Reachability` is deallocated on thread X + - A `SCNetworkReachability` callback(s) is already in flight on thread Y + #### Retain Cycle + If we pass `Reachability` to CoreFoundtion while also providing retain/ + release callbacks, we would create a retain cycle once CoreFoundation + retains our `Reachability` class. This fixes the crashes and his how + CoreFoundation expects the API to be used, but doesn't play nicely with + Swift/ARC. This cycle would only be broken after manually calling + `stopNotifier()` — `deinit` would never be called. + #### ReachabilityWeakifier + By providing both retain/release callbacks and wrapping `Reachability` in + a weak wrapper, we: + - interact correctly with CoreFoundation, thereby avoiding a crash. + See "Memory Management Programming Guide for Core Foundation". + - don't alter the public API of `Reachability.swift` in any way + - still allow for automatic stopping of the notifier on `deinit`. + */ +private class ReachabilityWeakifier { + weak var reachability: Reachability? + init(reachability: Reachability) { + self.reachability = reachability + } +} diff --git a/network/ios/Podfile b/network/ios/Podfile index 11d5b28f3..dee40960f 100644 --- a/network/ios/Podfile +++ b/network/ios/Podfile @@ -1,11 +1,10 @@ -platform :ios, '12.0' +platform :ios, '13.0' def capacitor_pods # Comment the next line if you're not using Swift and don't want to use dynamic frameworks use_frameworks! pod 'Capacitor', :path => '../node_modules/@capacitor/ios' pod 'CapacitorCordova', :path => '../node_modules/@capacitor/ios' - pod 'ReachabilitySwift', '~> 5.0' end target 'Plugin' do diff --git a/network/package.json b/network/package.json index e5193c834..f411a88e5 100644 --- a/network/package.json +++ b/network/package.json @@ -1,6 +1,6 @@ { "name": "@capacitor/network", - "version": "1.0.7", + "version": "4.1.0", "description": "The Network API provides network and connectivity information.", "main": "dist/plugin.cjs.js", "module": "dist/esm/index.js", @@ -29,7 +29,7 @@ ], "scripts": { "verify": "npm run verify:ios && npm run verify:android && npm run verify:web", - "verify:ios": "cd ios && pod install && xcodebuild -workspace Plugin.xcworkspace -scheme Plugin && cd ..", + "verify:ios": "cd ios && pod install && xcodebuild -workspace Plugin.xcworkspace -scheme Plugin -destination generic/platform=iOS && cd ..", "verify:android": "cd android && ./gradlew clean build test && cd ..", "verify:web": "npm run build", "lint": "npm run eslint && npm run prettier -- --check && npm run swiftlint -- lint", @@ -45,10 +45,10 @@ "publish:cocoapod": "pod trunk push ./CapacitorNetwork.podspec --allow-warnings" }, "devDependencies": { - "@capacitor/android": "^3.0.0", - "@capacitor/core": "^3.0.0", - "@capacitor/docgen": "0.0.18", - "@capacitor/ios": "^3.0.0", + "@capacitor/android": "^4.0.0", + "@capacitor/core": "^4.0.0", + "@capacitor/docgen": "0.2.0", + "@capacitor/ios": "^4.0.0", "@ionic/eslint-config": "^0.3.0", "@ionic/prettier-config": "~1.0.1", "@ionic/swiftlint-config": "^1.1.2", @@ -61,7 +61,7 @@ "typescript": "~4.1.5" }, "peerDependencies": { - "@capacitor/core": "^3.0.0" + "@capacitor/core": "^4.0.0" }, "prettier": "@ionic/prettier-config", "swiftlint": "@ionic/swiftlint-config", diff --git a/package.json b/package.json index a5b9271d6..ec9a371f6 100644 --- a/package.json +++ b/package.json @@ -12,11 +12,16 @@ "update-all": "node ./scripts/update-all.mjs", "set-capacitor-version": "node ./scripts/set-capacitor-version.mjs", "postinstall": "lerna bootstrap", - "release": "lerna publish", - "publish:cocoapod": "lerna run publish:cocoapod --concurrency 1" + "publish:cocoapod": "lerna run publish:cocoapod --concurrency 1", + "ci:publish:nightly": "lerna publish prerelease --conventional-commits --conventional-prerelease --preid nightly-$(date +\"%Y%m%dT%H%M%S\") --dist-tag nightly --force-publish --no-verify-access --no-changelog --no-git-tag-version --no-push --yes", + "ci:publish:alpha": "lerna publish prerelease --conventional-commits --conventional-prerelease --preid alpha --dist-tag next --force-publish --no-verify-access --yes", + "ci:publish:beta": "lerna publish prerelease --conventional-commits --conventional-prerelease --preid beta --dist-tag next --force-publish --no-verify-access --yes", + "ci:publish:rc": "lerna publish prerelease --conventional-commits --conventional-prerelease --preid rc --dist-tag next --force-publish --no-verify-access --yes", + "ci:publish:latest": "lerna publish --conventional-graduate --conventional-commits --dist-tag latest --force-publish --no-verify-access --yes", + "ci:publish:dev": "lerna publish prerelease --conventional-commits --conventional-prerelease --preid dev-$(date +\"%Y%m%dT%H%M%S\") --dist-tag dev --force-publish --no-verify-access --no-changelog --no-git-tag-version --no-push --yes" }, "devDependencies": { - "@actions/core": "^1.2.6", + "@actions/core": "^1.9.1", "@ionic/prettier-config": "^1.0.1", "@types/prompts": "^2.0.8", "esm": "^3.2.25", @@ -24,5 +29,9 @@ "prettier": "~2.3.0", "prompts": "^2.3.2" }, - "prettier": "@ionic/prettier-config" + "prettier": "@ionic/prettier-config", + "volta": { + "node": "14.18.2", + "npm": "6.14.15" + } } diff --git a/storage/.eslintignore b/preferences/.eslintignore similarity index 100% rename from storage/.eslintignore rename to preferences/.eslintignore diff --git a/storage/.gitignore b/preferences/.gitignore similarity index 100% rename from storage/.gitignore rename to preferences/.gitignore diff --git a/storage/.prettierignore b/preferences/.prettierignore similarity index 100% rename from storage/.prettierignore rename to preferences/.prettierignore diff --git a/storage/CHANGELOG.md b/preferences/CHANGELOG.md similarity index 89% rename from storage/CHANGELOG.md rename to preferences/CHANGELOG.md index 87c7cc86e..b5489f8ed 100644 --- a/storage/CHANGELOG.md +++ b/preferences/CHANGELOG.md @@ -3,6 +3,70 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## 4.0.2 (2022-11-16) + + + +## 4.0.1 (2022-07-28) + + + +# 4.0.0 (2022-07-27) + + + +# 4.0.0-beta.2 (2022-07-08) + + + +# 4.0.0-beta.0 (2022-06-27) + +**Note:** Version bump only for package @capacitor/preferences + + + + + +## [4.0.1](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0...4.0.1) (2022-07-28) + +**Note:** Version bump only for package @capacitor/preferences + + + + + +# [4.0.0](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0-beta.2...4.0.0) (2022-07-27) + +**Note:** Version bump only for package @capacitor/preferences + + + + + +# [4.0.0-beta.2](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0-beta.0...4.0.0-beta.2) (2022-07-08) + +**Note:** Version bump only for package @capacitor/preferences + + + + + +# 4.0.0-beta.0 (2022-06-27) + +**Note:** Version bump only for package @capacitor/preferences + + + + + +## [1.2.5](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/storage@1.2.4...@capacitor/storage@1.2.5) (2022-03-03) + +**Note:** Version bump only for package @capacitor/storage + + + + + ## [1.2.4](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/storage@1.2.3...@capacitor/storage@1.2.4) (2022-01-19) diff --git a/storage/CapacitorStorage.podspec b/preferences/CapacitorPreferences.podspec similarity index 71% rename from storage/CapacitorStorage.podspec rename to preferences/CapacitorPreferences.podspec index 1e1784a50..e3f6189a1 100644 --- a/storage/CapacitorStorage.podspec +++ b/preferences/CapacitorPreferences.podspec @@ -3,15 +3,15 @@ require 'json' package = JSON.parse(File.read(File.join(__dir__, 'package.json'))) Pod::Spec.new do |s| - s.name = 'CapacitorStorage' + s.name = 'CapacitorPreferences' s.version = package['version'] s.summary = package['description'] s.license = package['license'] s.homepage = 'https://capacitorjs.com' s.author = package['author'] s.source = { :git => 'https://github.com/ionic-team/capacitor-plugins.git', :tag => package['name'] + '@' + package['version'] } - s.source_files = 'ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}', 'storage/ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}' - s.ios.deployment_target = '12.0' + s.source_files = 'ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}', 'preferences/ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}' + s.ios.deployment_target = '13.0' s.dependency 'Capacitor' s.swift_version = '5.1' end diff --git a/storage/LICENSE b/preferences/LICENSE similarity index 100% rename from storage/LICENSE rename to preferences/LICENSE diff --git a/storage/README.md b/preferences/README.md similarity index 70% rename from storage/README.md rename to preferences/README.md index 9a1bd3dbd..5203a84b0 100644 --- a/storage/README.md +++ b/preferences/README.md @@ -1,6 +1,6 @@ -# @capacitor/storage +# @capacitor/preferences -The Storage API provides a simple key/value persistent store for lightweight data. +The Preferences API provides a simple key/value persistent store for lightweight data. Mobile OSs may periodically clear data set in `window.localStorage`, so this API should be used instead. This API will fall back to using `localStorage` @@ -19,36 +19,36 @@ we recommend taking a look at a SQLite-based solution. One such solution is [Ion ## Install ```bash -npm install @capacitor/storage +npm install @capacitor/preferences npx cap sync ``` ## Example ```typescript -import { Storage } from '@capacitor/storage'; +import { Preferences } from '@capacitor/preferences'; const setName = async () => { - await Storage.set({ + await Preferences.set({ key: 'name', value: 'Max', }); }; const checkName = async () => { - const { value } = await Storage.get({ key: 'name' }); + const { value } = await Preferences.get({ key: 'name' }); - alert(`Hello ${value}!`); + console.log(`Hello ${value}!`); }; const removeName = async () => { - await Storage.remove({ key: 'name' }); + await Preferences.remove({ key: 'name' }); }; ``` ## Working with JSON -The Storage API only supports string values. You can, however, use JSON if you `JSON.stringify` the object before calling `set()`, then `JSON.parse` the value returned from `get()`. +The Preferences API only supports string values. You can, however, use JSON if you `JSON.stringify` the object before calling `set()`, then `JSON.parse` the value returned from `get()`. This method can also be used to store non-string values, such as numbers and booleans. @@ -77,7 +77,7 @@ This method can also be used to store non-string values, such as numbers and boo configure(options: ConfigureOptions) => Promise ``` -Configure the storage plugin at runtime. +Configure the preferences plugin at runtime. Options that are `undefined` will not be used. @@ -96,7 +96,7 @@ Options that are `undefined` will not be used. get(options: GetOptions) => Promise ``` -Get the value from storage of a given key. +Get the value from preferences of a given key. | Param | Type | | ------------- | ------------------------------------------------- | @@ -115,7 +115,7 @@ Get the value from storage of a given key. set(options: SetOptions) => Promise ``` -Set the value in storage for a given key. +Set the value in preferences for a given key. | Param | Type | | ------------- | ------------------------------------------------- | @@ -132,7 +132,7 @@ Set the value in storage for a given key. remove(options: RemoveOptions) => Promise ``` -Remove the value from storage for a given key, if any. +Remove the value from preferences for a given key, if any. | Param | Type | | ------------- | ------------------------------------------------------- | @@ -149,7 +149,7 @@ Remove the value from storage for a given key, if any. clear() => Promise ``` -Clear keys and values from storage. +Clear keys and values from preferences. **Since:** 1.0.0 @@ -162,7 +162,7 @@ Clear keys and values from storage. keys() => Promise ``` -Return the list of known keys in storage. +Return the list of known keys in preferences. **Returns:** Promise<KeysResult> @@ -208,52 +208,52 @@ Removes old data with `_cap_` prefix from the Capacitor 2 Storage plugin. #### ConfigureOptions -| Prop | Type | Description | Default | Since | -| ----------- | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------- | ----- | -| **`group`** | string | Set the storage group. Storage groups are used to organize key/value pairs. Using the value 'NativeStorage' provides backwards-compatibility with [`cordova-plugin-nativestorage`](https://www.npmjs.com/package/cordova-plugin-nativestorage). WARNING: The `clear()` method can delete unintended values when using the 'NativeStorage' group. | CapacitorStorage | 1.0.0 | +| Prop | Type | Description | Default | Since | +| ----------- | ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------- | ----- | +| **`group`** | string | Set the preferences group. Preferences groups are used to organize key/value pairs. Using the value 'NativeStorage' provides backwards-compatibility with [`cordova-plugin-nativestorage`](https://www.npmjs.com/package/cordova-plugin-nativestorage). WARNING: The `clear()` method can delete unintended values when using the 'NativeStorage' group. | CapacitorStorage | 1.0.0 | #### GetResult -| Prop | Type | Description | Since | -| ----------- | --------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | ----- | -| **`value`** | string \| null | The value from storage associated with the given key. If a value was not previously set or was removed, value will be `null`. | 1.0.0 | +| Prop | Type | Description | Since | +| ----------- | --------------------------- | --------------------------------------------------------------------------------------------------------------------------------- | ----- | +| **`value`** | string \| null | The value from preferences associated with the given key. If a value was not previously set or was removed, value will be `null`. | 1.0.0 | #### GetOptions -| Prop | Type | Description | Since | -| --------- | ------------------- | --------------------------------------------- | ----- | -| **`key`** | string | The key whose value to retrieve from storage. | 1.0.0 | +| Prop | Type | Description | Since | +| --------- | ------------------- | ------------------------------------------------- | ----- | +| **`key`** | string | The key whose value to retrieve from preferences. | 1.0.0 | #### SetOptions -| Prop | Type | Description | Since | -| ----------- | ------------------- | --------------------------------------------------------- | ----- | -| **`key`** | string | The key to associate with the value being set in storage. | 1.0.0 | -| **`value`** | string | The value to set in storage with the associated key. | 1.0.0 | +| Prop | Type | Description | Since | +| ----------- | ------------------- | ------------------------------------------------------------- | ----- | +| **`key`** | string | The key to associate with the value being set in preferences. | 1.0.0 | +| **`value`** | string | The value to set in preferences with the associated key. | 1.0.0 | #### RemoveOptions -| Prop | Type | Description | Since | -| --------- | ------------------- | ------------------------------------------- | ----- | -| **`key`** | string | The key whose value to remove from storage. | 1.0.0 | +| Prop | Type | Description | Since | +| --------- | ------------------- | ----------------------------------------------- | ----- | +| **`key`** | string | The key whose value to remove from preferences. | 1.0.0 | #### KeysResult -| Prop | Type | Description | Since | -| ---------- | --------------------- | -------------------------- | ----- | -| **`keys`** | string[] | The known keys in storage. | 1.0.0 | +| Prop | Type | Description | Since | +| ---------- | --------------------- | ------------------------------ | ----- | +| **`keys`** | string[] | The known keys in preferences. | 1.0.0 | #### MigrateResult -| Prop | Type | Description | Since | -| -------------- | --------------------- | ----------------------------------------------------------------------------------------------------------------------------- | ----- | -| **`migrated`** | string[] | An array of keys that were migrated. | 1.0.0 | -| **`existing`** | string[] | An array of keys that were already migrated or otherwise exist in storage that had a value in the Capacitor 2 Storage plugin. | 1.0.0 | +| Prop | Type | Description | Since | +| -------------- | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | ----- | +| **`migrated`** | string[] | An array of keys that were migrated. | 1.0.0 | +| **`existing`** | string[] | An array of keys that were already migrated or otherwise exist in preferences that had a value in the Capacitor 2 Preferences plugin. | 1.0.0 | diff --git a/preferences/android/.gitignore b/preferences/android/.gitignore new file mode 100644 index 000000000..796b96d1c --- /dev/null +++ b/preferences/android/.gitignore @@ -0,0 +1 @@ +/build diff --git a/storage/android/build.gradle b/preferences/android/build.gradle similarity index 56% rename from storage/android/build.gradle rename to preferences/android/build.gradle index 56ee0b28b..43252f49c 100644 --- a/storage/android/build.gradle +++ b/preferences/android/build.gradle @@ -1,27 +1,39 @@ ext { - junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.1' - androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.2.0' - androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.1.2' - androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.3.0' + capacitorVersion = System.getenv('CAPACITOR_VERSION') + junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.2' + androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.4.2' + androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.1.3' + androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.4.0' } buildscript { repositories { google() mavenCentral() + maven { + url "https://plugins.gradle.org/m2/" + } } dependencies { - classpath 'com.android.tools.build:gradle:4.2.1' + classpath 'com.android.tools.build:gradle:7.2.1' + if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + classpath 'io.github.gradle-nexus:publish-plugin:1.1.0' + } } } apply plugin: 'com.android.library' +if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + apply plugin: 'io.github.gradle-nexus.publish-plugin' + apply from: file('../../scripts/android/publish-root.gradle') + apply from: file('../../scripts/android/publish-module.gradle') +} android { - compileSdkVersion project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 30 + compileSdkVersion project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 32 defaultConfig { - minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 21 - targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 30 + minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 22 + targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 32 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" @@ -36,21 +48,26 @@ android { abortOnError false } compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility JavaVersion.VERSION_11 + targetCompatibility JavaVersion.VERSION_11 } } repositories { google() mavenCentral() - jcenter() } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation project(':capacitor-android') + + if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + implementation "com.capacitorjs:core:$capacitorVersion" + } else { + implementation project(':capacitor-android') + } + implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion" testImplementation "junit:junit:$junitVersion" androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion" diff --git a/preferences/android/gradle.properties b/preferences/android/gradle.properties new file mode 100644 index 000000000..0566c221d --- /dev/null +++ b/preferences/android/gradle.properties @@ -0,0 +1,24 @@ +# Project-wide Gradle settings. + +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. + +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html + +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx1536m + +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true + +# AndroidX package structure to make it clearer which packages are bundled with the +# Android operating system, and which are packaged with your app's APK +# https://developer.android.com/topic/libraries/support-library/androidx-rn +android.useAndroidX=true +# Automatically convert third-party libraries to use AndroidX +android.enableJetifier=true diff --git a/preferences/android/gradle/wrapper/gradle-wrapper.jar b/preferences/android/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 000000000..41d9927a4 Binary files /dev/null and b/preferences/android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/preferences/android/gradle/wrapper/gradle-wrapper.properties b/preferences/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..92f06b50f --- /dev/null +++ b/preferences/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-all.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/preferences/android/gradlew b/preferences/android/gradlew new file mode 100755 index 000000000..1b6c78733 --- /dev/null +++ b/preferences/android/gradlew @@ -0,0 +1,234 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +APP_NAME="Gradle" +APP_BASE_NAME=${0##*/} + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/preferences/android/gradlew.bat b/preferences/android/gradlew.bat new file mode 100644 index 000000000..ac1b06f93 --- /dev/null +++ b/preferences/android/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/preferences/android/proguard-rules.pro b/preferences/android/proguard-rules.pro new file mode 100644 index 000000000..f1b424510 --- /dev/null +++ b/preferences/android/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/preferences/android/settings.gradle b/preferences/android/settings.gradle new file mode 100644 index 000000000..1e5b8431f --- /dev/null +++ b/preferences/android/settings.gradle @@ -0,0 +1,2 @@ +include ':capacitor-android' +project(':capacitor-android').projectDir = new File('../node_modules/@capacitor/android/capacitor') \ No newline at end of file diff --git a/storage/android/src/androidTest/java/com/getcapacitor/android/ExampleInstrumentedTest.java b/preferences/android/src/androidTest/java/com/getcapacitor/android/ExampleInstrumentedTest.java similarity index 100% rename from storage/android/src/androidTest/java/com/getcapacitor/android/ExampleInstrumentedTest.java rename to preferences/android/src/androidTest/java/com/getcapacitor/android/ExampleInstrumentedTest.java diff --git a/preferences/android/src/main/AndroidManifest.xml b/preferences/android/src/main/AndroidManifest.xml new file mode 100644 index 000000000..bf3a90ee6 --- /dev/null +++ b/preferences/android/src/main/AndroidManifest.xml @@ -0,0 +1,3 @@ + + diff --git a/storage/android/src/main/java/com/capacitorjs/plugins/storage/Storage.java b/preferences/android/src/main/java/com/capacitorjs/plugins/preferences/Preferences.java similarity index 79% rename from storage/android/src/main/java/com/capacitorjs/plugins/storage/Storage.java rename to preferences/android/src/main/java/com/capacitorjs/plugins/preferences/Preferences.java index 6acb6a26e..06d44b583 100644 --- a/storage/android/src/main/java/com/capacitorjs/plugins/storage/Storage.java +++ b/preferences/android/src/main/java/com/capacitorjs/plugins/preferences/Preferences.java @@ -1,19 +1,19 @@ -package com.capacitorjs.plugins.storage; +package com.capacitorjs.plugins.preferences; import android.app.Activity; import android.content.Context; import android.content.SharedPreferences; import java.util.Set; -public class Storage { +public class Preferences { private SharedPreferences preferences; - private interface StorageOperation { + private interface PreferencesOperation { void execute(SharedPreferences.Editor editor); } - Storage(Context context, StorageConfiguration configuration) { + Preferences(Context context, PreferencesConfiguration configuration) { this.preferences = context.getSharedPreferences(configuration.group, Activity.MODE_PRIVATE); } @@ -37,7 +37,7 @@ public void clear() { executeOperation(SharedPreferences.Editor::clear); } - private void executeOperation(StorageOperation op) { + private void executeOperation(PreferencesOperation op) { SharedPreferences.Editor editor = preferences.edit(); op.execute(editor); editor.apply(); diff --git a/preferences/android/src/main/java/com/capacitorjs/plugins/preferences/PreferencesConfiguration.java b/preferences/android/src/main/java/com/capacitorjs/plugins/preferences/PreferencesConfiguration.java new file mode 100644 index 000000000..373cf9e65 --- /dev/null +++ b/preferences/android/src/main/java/com/capacitorjs/plugins/preferences/PreferencesConfiguration.java @@ -0,0 +1,18 @@ +package com.capacitorjs.plugins.preferences; + +public class PreferencesConfiguration implements Cloneable { + + static final PreferencesConfiguration DEFAULTS; + + static { + DEFAULTS = new PreferencesConfiguration(); + DEFAULTS.group = "CapacitorStorage"; + } + + String group; + + @Override + public PreferencesConfiguration clone() throws CloneNotSupportedException { + return (PreferencesConfiguration) super.clone(); + } +} diff --git a/storage/android/src/main/java/com/capacitorjs/plugins/storage/StoragePlugin.java b/preferences/android/src/main/java/com/capacitorjs/plugins/preferences/PreferencesPlugin.java similarity index 71% rename from storage/android/src/main/java/com/capacitorjs/plugins/storage/StoragePlugin.java rename to preferences/android/src/main/java/com/capacitorjs/plugins/preferences/PreferencesPlugin.java index 9faaa41d5..05f328bcf 100644 --- a/storage/android/src/main/java/com/capacitorjs/plugins/storage/StoragePlugin.java +++ b/preferences/android/src/main/java/com/capacitorjs/plugins/preferences/PreferencesPlugin.java @@ -1,4 +1,4 @@ -package com.capacitorjs.plugins.storage; +package com.capacitorjs.plugins.preferences; import com.getcapacitor.JSArray; import com.getcapacitor.JSObject; @@ -11,23 +11,23 @@ import java.util.Set; import org.json.JSONException; -@CapacitorPlugin(name = "Storage") -public class StoragePlugin extends Plugin { +@CapacitorPlugin(name = "Preferences") +public class PreferencesPlugin extends Plugin { - private Storage storage; + private Preferences preferences; @Override public void load() { - storage = new Storage(getContext(), StorageConfiguration.DEFAULTS); + preferences = new Preferences(getContext(), PreferencesConfiguration.DEFAULTS); } @PluginMethod public void configure(PluginCall call) { try { - StorageConfiguration configuration = StorageConfiguration.DEFAULTS.clone(); - configuration.group = call.getString("group", StorageConfiguration.DEFAULTS.group); + PreferencesConfiguration configuration = PreferencesConfiguration.DEFAULTS.clone(); + configuration.group = call.getString("group", PreferencesConfiguration.DEFAULTS.group); - storage = new Storage(getContext(), configuration); + preferences = new Preferences(getContext(), configuration); } catch (CloneNotSupportedException e) { call.reject("Error while configuring", e); return; @@ -43,7 +43,7 @@ public void get(PluginCall call) { return; } - String value = storage.get(key); + String value = preferences.get(key); JSObject ret = new JSObject(); ret.put("value", value == null ? JSObject.NULL : value); @@ -59,7 +59,7 @@ public void set(PluginCall call) { } String value = call.getString("value"); - storage.set(key, value); + preferences.set(key, value); call.resolve(); } @@ -72,14 +72,14 @@ public void remove(PluginCall call) { return; } - storage.remove(key); + preferences.remove(key); call.resolve(); } @PluginMethod public void keys(PluginCall call) { - Set keySet = storage.keys(); + Set keySet = preferences.keys(); String[] keys = keySet.toArray(new String[0]); JSObject ret = new JSObject(); @@ -94,7 +94,7 @@ public void keys(PluginCall call) { @PluginMethod public void clear(PluginCall call) { - storage.clear(); + preferences.clear(); call.resolve(); } @@ -102,14 +102,14 @@ public void clear(PluginCall call) { public void migrate(PluginCall call) { List migrated = new ArrayList<>(); List existing = new ArrayList<>(); - Storage oldStorage = new Storage(getContext(), StorageConfiguration.DEFAULTS); + Preferences oldPreferences = new Preferences(getContext(), PreferencesConfiguration.DEFAULTS); - for (String key : oldStorage.keys()) { - String value = oldStorage.get(key); - String currentValue = storage.get(key); + for (String key : oldPreferences.keys()) { + String value = oldPreferences.get(key); + String currentValue = preferences.get(key); if (currentValue == null) { - storage.set(key, value); + preferences.set(key, value); migrated.add(key); } else { existing.add(key); diff --git a/storage/android/src/test/java/com/getcapacitor/ExampleUnitTest.java b/preferences/android/src/test/java/com/getcapacitor/ExampleUnitTest.java similarity index 100% rename from storage/android/src/test/java/com/getcapacitor/ExampleUnitTest.java rename to preferences/android/src/test/java/com/getcapacitor/ExampleUnitTest.java diff --git a/storage/ios/Plugin.xcodeproj/project.pbxproj b/preferences/ios/Plugin.xcodeproj/project.pbxproj similarity index 91% rename from storage/ios/Plugin.xcodeproj/project.pbxproj rename to preferences/ios/Plugin.xcodeproj/project.pbxproj index d7bba6466..5eaae2144 100644 --- a/storage/ios/Plugin.xcodeproj/project.pbxproj +++ b/preferences/ios/Plugin.xcodeproj/project.pbxproj @@ -9,13 +9,13 @@ /* Begin PBXBuildFile section */ 03FC29A292ACC40490383A1F /* Pods_Plugin.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B2A61DA5A1F2DD4F959604D /* Pods_Plugin.framework */; }; 20C0B05DCFC8E3958A738AF2 /* Pods_PluginTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F6753A823D3815DB436415E3 /* Pods_PluginTests.framework */; }; - 2F98D68224C9AAE500613A4C /* Storage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F98D68124C9AAE400613A4C /* Storage.swift */; }; + 2F98D68224C9AAE500613A4C /* Preferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F98D68124C9AAE400613A4C /* Preferences.swift */; }; 50ADFF92201F53D600D50D53 /* Plugin.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 50ADFF88201F53D600D50D53 /* Plugin.framework */; }; 50ADFF97201F53D600D50D53 /* PluginTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50ADFF96201F53D600D50D53 /* PluginTests.swift */; }; - 50ADFF99201F53D600D50D53 /* StoragePlugin.h in Headers */ = {isa = PBXBuildFile; fileRef = 50ADFF8B201F53D600D50D53 /* StoragePlugin.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 50ADFF99201F53D600D50D53 /* PreferencesPlugin.h in Headers */ = {isa = PBXBuildFile; fileRef = 50ADFF8B201F53D600D50D53 /* PreferencesPlugin.h */; settings = {ATTRIBUTES = (Public, ); }; }; 50ADFFA42020D75100D50D53 /* Capacitor.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 50ADFFA52020D75100D50D53 /* Capacitor.framework */; }; - 50ADFFA82020EE4F00D50D53 /* StoragePlugin.m in Sources */ = {isa = PBXBuildFile; fileRef = 50ADFFA72020EE4F00D50D53 /* StoragePlugin.m */; }; - 50E1A94820377CB70090CE1A /* StoragePlugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50E1A94720377CB70090CE1A /* StoragePlugin.swift */; }; + 50ADFFA82020EE4F00D50D53 /* PreferencesPlugin.m in Sources */ = {isa = PBXBuildFile; fileRef = 50ADFFA72020EE4F00D50D53 /* PreferencesPlugin.m */; }; + 50E1A94820377CB70090CE1A /* PreferencesPlugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50E1A94720377CB70090CE1A /* PreferencesPlugin.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -29,17 +29,17 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ - 2F98D68124C9AAE400613A4C /* Storage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Storage.swift; sourceTree = ""; }; + 2F98D68124C9AAE400613A4C /* Preferences.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Preferences.swift; sourceTree = ""; }; 3B2A61DA5A1F2DD4F959604D /* Pods_Plugin.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Plugin.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 50ADFF88201F53D600D50D53 /* Plugin.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Plugin.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 50ADFF8B201F53D600D50D53 /* StoragePlugin.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = StoragePlugin.h; sourceTree = ""; }; + 50ADFF8B201F53D600D50D53 /* PreferencesPlugin.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PreferencesPlugin.h; sourceTree = ""; }; 50ADFF8C201F53D600D50D53 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 50ADFF91201F53D600D50D53 /* PluginTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PluginTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 50ADFF96201F53D600D50D53 /* PluginTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PluginTests.swift; sourceTree = ""; }; 50ADFF98201F53D600D50D53 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 50ADFFA52020D75100D50D53 /* Capacitor.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Capacitor.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 50ADFFA72020EE4F00D50D53 /* StoragePlugin.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = StoragePlugin.m; sourceTree = ""; }; - 50E1A94720377CB70090CE1A /* StoragePlugin.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StoragePlugin.swift; sourceTree = ""; }; + 50ADFFA72020EE4F00D50D53 /* PreferencesPlugin.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PreferencesPlugin.m; sourceTree = ""; }; + 50E1A94720377CB70090CE1A /* PreferencesPlugin.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PreferencesPlugin.swift; sourceTree = ""; }; 5E23F77F099397094342571A /* Pods-Plugin.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Plugin.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Plugin/Pods-Plugin.debug.xcconfig"; sourceTree = ""; }; 91781294A431A2A7CC6EB714 /* Pods-Plugin.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Plugin.release.xcconfig"; path = "Pods/Target Support Files/Pods-Plugin/Pods-Plugin.release.xcconfig"; sourceTree = ""; }; 96ED1B6440D6672E406C8D19 /* Pods-PluginTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PluginTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-PluginTests/Pods-PluginTests.debug.xcconfig"; sourceTree = ""; }; @@ -92,10 +92,10 @@ 50ADFF8A201F53D600D50D53 /* Plugin */ = { isa = PBXGroup; children = ( - 50E1A94720377CB70090CE1A /* StoragePlugin.swift */, - 2F98D68124C9AAE400613A4C /* Storage.swift */, - 50ADFF8B201F53D600D50D53 /* StoragePlugin.h */, - 50ADFFA72020EE4F00D50D53 /* StoragePlugin.m */, + 50E1A94720377CB70090CE1A /* PreferencesPlugin.swift */, + 2F98D68124C9AAE400613A4C /* Preferences.swift */, + 50ADFF8B201F53D600D50D53 /* PreferencesPlugin.h */, + 50ADFFA72020EE4F00D50D53 /* PreferencesPlugin.m */, 50ADFF8C201F53D600D50D53 /* Info.plist */, ); path = Plugin; @@ -138,7 +138,7 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - 50ADFF99201F53D600D50D53 /* StoragePlugin.h in Headers */, + 50ADFF99201F53D600D50D53 /* PreferencesPlugin.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -306,9 +306,9 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 50E1A94820377CB70090CE1A /* StoragePlugin.swift in Sources */, - 2F98D68224C9AAE500613A4C /* Storage.swift in Sources */, - 50ADFFA82020EE4F00D50D53 /* StoragePlugin.m in Sources */, + 50E1A94820377CB70090CE1A /* PreferencesPlugin.swift in Sources */, + 2F98D68224C9AAE500613A4C /* Preferences.swift in Sources */, + 50ADFFA82020EE4F00D50D53 /* PreferencesPlugin.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -386,7 +386,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -446,7 +446,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; @@ -469,12 +469,13 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Plugin/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks $(FRAMEWORK_SEARCH_PATHS)\n$(FRAMEWORK_SEARCH_PATHS)\n$(FRAMEWORK_SEARCH_PATHS)"; ONLY_ACTIVE_ARCH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.getcapacitor.Plugin; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; + SUPPORTS_MACCATALYST = NO; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -494,12 +495,13 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Plugin/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks $(FRAMEWORK_SEARCH_PATHS)"; ONLY_ACTIVE_ARCH = NO; PRODUCT_BUNDLE_IDENTIFIER = com.getcapacitor.Plugin; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; + SUPPORTS_MACCATALYST = NO; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; diff --git a/preferences/ios/Plugin.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/preferences/ios/Plugin.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/preferences/ios/Plugin.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/preferences/ios/Plugin.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/preferences/ios/Plugin.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/preferences/ios/Plugin.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/preferences/ios/Plugin.xcodeproj/xcshareddata/xcschemes/Plugin.xcscheme b/preferences/ios/Plugin.xcodeproj/xcshareddata/xcschemes/Plugin.xcscheme new file mode 100644 index 000000000..303f2621b --- /dev/null +++ b/preferences/ios/Plugin.xcodeproj/xcshareddata/xcschemes/Plugin.xcscheme @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/preferences/ios/Plugin.xcodeproj/xcshareddata/xcschemes/PluginTests.xcscheme b/preferences/ios/Plugin.xcodeproj/xcshareddata/xcschemes/PluginTests.xcscheme new file mode 100644 index 000000000..3d8c88d25 --- /dev/null +++ b/preferences/ios/Plugin.xcodeproj/xcshareddata/xcschemes/PluginTests.xcscheme @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/preferences/ios/Plugin.xcworkspace/contents.xcworkspacedata b/preferences/ios/Plugin.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..afad624ec --- /dev/null +++ b/preferences/ios/Plugin.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/preferences/ios/Plugin.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/preferences/ios/Plugin.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/preferences/ios/Plugin.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/preferences/ios/Plugin/Info.plist b/preferences/ios/Plugin/Info.plist new file mode 100644 index 000000000..1007fd9dd --- /dev/null +++ b/preferences/ios/Plugin/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSPrincipalClass + + + diff --git a/storage/ios/Plugin/Storage.swift b/preferences/ios/Plugin/Preferences.swift similarity index 87% rename from storage/ios/Plugin/Storage.swift rename to preferences/ios/Plugin/Preferences.swift index 861dcaf45..e24a0ed6d 100644 --- a/storage/ios/Plugin/Storage.swift +++ b/preferences/ios/Plugin/Preferences.swift @@ -1,6 +1,6 @@ import Foundation -public struct StorageConfiguration { +public struct PreferencesConfiguration { public enum Group { case named(String), cordovaNativeStorage } @@ -12,8 +12,8 @@ public struct StorageConfiguration { } } -public class Storage { - private let configuration: StorageConfiguration +public class Preferences { + private let configuration: PreferencesConfiguration private var defaults: UserDefaults { return UserDefaults.standard @@ -32,7 +32,7 @@ public class Storage { return defaults.dictionaryRepresentation().keys.filter { $0.hasPrefix(prefix) } } - public init(with configuration: StorageConfiguration) { + public init(with configuration: PreferencesConfiguration) { self.configuration = configuration } diff --git a/preferences/ios/Plugin/PreferencesPlugin.h b/preferences/ios/Plugin/PreferencesPlugin.h new file mode 100644 index 000000000..f2bd9e0bb --- /dev/null +++ b/preferences/ios/Plugin/PreferencesPlugin.h @@ -0,0 +1,10 @@ +#import + +//! Project version number for Plugin. +FOUNDATION_EXPORT double PluginVersionNumber; + +//! Project version string for Plugin. +FOUNDATION_EXPORT const unsigned char PluginVersionString[]; + +// In this header, you should import all the public headers of your framework using statements like #import + diff --git a/storage/ios/Plugin/StoragePlugin.m b/preferences/ios/Plugin/PreferencesPlugin.m similarity index 93% rename from storage/ios/Plugin/StoragePlugin.m rename to preferences/ios/Plugin/PreferencesPlugin.m index 83eece846..8449cffcd 100644 --- a/storage/ios/Plugin/StoragePlugin.m +++ b/preferences/ios/Plugin/PreferencesPlugin.m @@ -3,7 +3,7 @@ // Define the plugin using the CAP_PLUGIN Macro, and // each method the plugin supports using the CAP_PLUGIN_METHOD macro. -CAP_PLUGIN(StoragePlugin, "Storage", +CAP_PLUGIN(PreferencesPlugin, "Preferences", CAP_PLUGIN_METHOD(configure, CAPPluginReturnPromise); CAP_PLUGIN_METHOD(get, CAPPluginReturnPromise); CAP_PLUGIN_METHOD(set, CAPPluginReturnPromise); diff --git a/storage/ios/Plugin/StoragePlugin.swift b/preferences/ios/Plugin/PreferencesPlugin.swift similarity index 74% rename from storage/ios/Plugin/StoragePlugin.swift rename to preferences/ios/Plugin/PreferencesPlugin.swift index c2b0d4de9..3c840f49f 100644 --- a/storage/ios/Plugin/StoragePlugin.swift +++ b/preferences/ios/Plugin/PreferencesPlugin.swift @@ -1,25 +1,25 @@ import Foundation import Capacitor -@objc(StoragePlugin) -public class StoragePlugin: CAPPlugin { - private var storage = Storage(with: StorageConfiguration()) +@objc(PreferencesPlugin) +public class PreferencesPlugin: CAPPlugin { + private var preferences = Preferences(with: PreferencesConfiguration()) @objc func configure(_ call: CAPPluginCall) { let group = call.getString("group") - let configuration: StorageConfiguration + let configuration: PreferencesConfiguration if let group = group { if group == "NativeStorage" { - configuration = StorageConfiguration(for: .cordovaNativeStorage) + configuration = PreferencesConfiguration(for: .cordovaNativeStorage) } else { - configuration = StorageConfiguration(for: .named(group)) + configuration = PreferencesConfiguration(for: .named(group)) } } else { - configuration = StorageConfiguration() + configuration = PreferencesConfiguration() } - storage = Storage(with: configuration) + preferences = Preferences(with: configuration) call.resolve() } @@ -29,7 +29,7 @@ public class StoragePlugin: CAPPlugin { return } - let value = storage.get(by: key) + let value = preferences.get(by: key) call.resolve([ "value": value as Any @@ -43,7 +43,7 @@ public class StoragePlugin: CAPPlugin { } let value = call.getString("value", "") - storage.set(value, for: key) + preferences.set(value, for: key) call.resolve() } @@ -53,12 +53,12 @@ public class StoragePlugin: CAPPlugin { return } - storage.remove(by: key) + preferences.remove(by: key) call.resolve() } @objc func keys(_ call: CAPPluginCall) { - let keys = storage.keys() + let keys = preferences.keys() call.resolve([ "keys": keys @@ -66,7 +66,7 @@ public class StoragePlugin: CAPPlugin { } @objc func clear(_ call: CAPPluginCall) { - storage.removeAll() + preferences.removeAll() call.resolve() } @@ -79,10 +79,10 @@ public class StoragePlugin: CAPPlugin { for oldKey in oldKeys { let key = String(oldKey.dropFirst(oldPrefix.count)) let value = UserDefaults.standard.string(forKey: oldKey) ?? "" - let currentValue = storage.get(by: key) + let currentValue = preferences.get(by: key) if currentValue == nil { - storage.set(value, for: key) + preferences.set(value, for: key) migrated.append(key) } else { existing.append(key) diff --git a/preferences/ios/PluginTests/Info.plist b/preferences/ios/PluginTests/Info.plist new file mode 100644 index 000000000..6c40a6cd0 --- /dev/null +++ b/preferences/ios/PluginTests/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/storage/ios/PluginTests/PluginTests.swift b/preferences/ios/PluginTests/PluginTests.swift similarity index 91% rename from storage/ios/PluginTests/PluginTests.swift rename to preferences/ios/PluginTests/PluginTests.swift index 7f3da79ec..ca47260f4 100644 --- a/storage/ios/PluginTests/PluginTests.swift +++ b/preferences/ios/PluginTests/PluginTests.swift @@ -1,7 +1,7 @@ import XCTest @testable import Plugin -class StorageTests: XCTestCase { +class PreferencesTests: XCTestCase { override func setUp() { super.setUp() diff --git a/storage/ios/Podfile b/preferences/ios/Podfile similarity index 94% rename from storage/ios/Podfile rename to preferences/ios/Podfile index 54a00c161..dee40960f 100644 --- a/storage/ios/Podfile +++ b/preferences/ios/Podfile @@ -1,4 +1,4 @@ -platform :ios, '12.0' +platform :ios, '13.0' def capacitor_pods # Comment the next line if you're not using Swift and don't want to use dynamic frameworks diff --git a/storage/package.json b/preferences/package.json similarity index 75% rename from storage/package.json rename to preferences/package.json index 02cceed9a..8685117da 100644 --- a/storage/package.json +++ b/preferences/package.json @@ -1,7 +1,7 @@ { - "name": "@capacitor/storage", - "version": "1.2.4", - "description": "The Storage API provides a simple key/value persistent store for lightweight data.", + "name": "@capacitor/preferences", + "version": "4.0.2", + "description": "The Preferences API provides a simple key/value persistent store for lightweight data.", "main": "dist/plugin.cjs.js", "module": "dist/esm/index.js", "types": "dist/esm/index.d.ts", @@ -11,7 +11,7 @@ "android/build.gradle", "dist/", "ios/Plugin/", - "CapacitorStorage.podspec" + "CapacitorPreferences.podspec" ], "author": "Ionic ", "license": "MIT", @@ -29,7 +29,7 @@ ], "scripts": { "verify": "npm run verify:ios && npm run verify:android && npm run verify:web", - "verify:ios": "cd ios && pod install && xcodebuild -workspace Plugin.xcworkspace -scheme Plugin && cd ..", + "verify:ios": "cd ios && pod install && xcodebuild -workspace Plugin.xcworkspace -scheme Plugin -destination generic/platform=iOS && cd ..", "verify:android": "cd android && ./gradlew clean build test && cd ..", "verify:web": "npm run build", "lint": "npm run eslint && npm run prettier -- --check && npm run swiftlint -- lint", @@ -37,18 +37,18 @@ "eslint": "eslint . --ext ts", "prettier": "prettier \"**/*.{css,html,ts,js,java}\"", "swiftlint": "node-swiftlint", - "docgen": "docgen --api StoragePlugin --output-readme README.md --output-json dist/docs.json", + "docgen": "docgen --api PreferencesPlugin --output-readme README.md --output-json dist/docs.json", "build": "npm run clean && npm run docgen && tsc && rollup -c rollup.config.js", "clean": "rimraf ./dist", "watch": "tsc --watch", "prepublishOnly": "npm run build", - "publish:cocoapod": "pod trunk push ./CapacitorStorage.podspec --allow-warnings" + "publish:cocoapod": "pod trunk push ./CapacitorPreferences.podspec --allow-warnings" }, "devDependencies": { - "@capacitor/android": "^3.0.0", - "@capacitor/core": "^3.0.0", - "@capacitor/docgen": "0.0.18", - "@capacitor/ios": "^3.0.0", + "@capacitor/android": "^4.0.0", + "@capacitor/core": "^4.0.0", + "@capacitor/docgen": "0.2.0", + "@capacitor/ios": "^4.0.0", "@ionic/eslint-config": "^0.3.0", "@ionic/prettier-config": "~1.0.1", "@ionic/swiftlint-config": "^1.1.2", @@ -61,7 +61,7 @@ "typescript": "~4.1.5" }, "peerDependencies": { - "@capacitor/core": "^3.0.0" + "@capacitor/core": "^4.0.0" }, "prettier": "@ionic/prettier-config", "swiftlint": "@ionic/swiftlint-config", diff --git a/storage/rollup.config.js b/preferences/rollup.config.js similarity index 92% rename from storage/rollup.config.js rename to preferences/rollup.config.js index b43b22f83..663585c83 100644 --- a/storage/rollup.config.js +++ b/preferences/rollup.config.js @@ -4,7 +4,7 @@ export default { { file: 'dist/plugin.js', format: 'iife', - name: 'capacitorStorage', + name: 'capacitorPreferences', globals: { '@capacitor/core': 'capacitorExports', }, diff --git a/storage/src/definitions.ts b/preferences/src/definitions.ts similarity index 72% rename from storage/src/definitions.ts rename to preferences/src/definitions.ts index 4509e9df5..3b690fb1c 100644 --- a/storage/src/definitions.ts +++ b/preferences/src/definitions.ts @@ -1,8 +1,8 @@ export interface ConfigureOptions { /** - * Set the storage group. + * Set the preferences group. * - * Storage groups are used to organize key/value pairs. + * Preferences groups are used to organize key/value pairs. * * Using the value 'NativeStorage' provides backwards-compatibility with * [`cordova-plugin-nativestorage`](https://www.npmjs.com/package/cordova-plugin-nativestorage). @@ -17,7 +17,7 @@ export interface ConfigureOptions { export interface GetOptions { /** - * The key whose value to retrieve from storage. + * The key whose value to retrieve from preferences. * * @since 1.0.0 */ @@ -26,7 +26,7 @@ export interface GetOptions { export interface GetResult { /** - * The value from storage associated with the given key. + * The value from preferences associated with the given key. * * If a value was not previously set or was removed, value will be `null`. * @@ -37,14 +37,14 @@ export interface GetResult { export interface SetOptions { /** - * The key to associate with the value being set in storage. + * The key to associate with the value being set in preferences. * * @since 1.0.0 */ key: string; /** - * The value to set in storage with the associated key. + * The value to set in preferences with the associated key. * * @since 1.0.0 */ @@ -53,7 +53,7 @@ export interface SetOptions { export interface RemoveOptions { /** - * The key whose value to remove from storage. + * The key whose value to remove from preferences. * * @since 1.0.0 */ @@ -62,7 +62,7 @@ export interface RemoveOptions { export interface KeysResult { /** - * The known keys in storage. + * The known keys in preferences. * * @since 1.0.0 */ @@ -78,17 +78,17 @@ export interface MigrateResult { migrated: string[]; /** - * An array of keys that were already migrated or otherwise exist in storage - * that had a value in the Capacitor 2 Storage plugin. + * An array of keys that were already migrated or otherwise exist in preferences + * that had a value in the Capacitor 2 Preferences plugin. * * @since 1.0.0 */ existing: string[]; } -export interface StoragePlugin { +export interface PreferencesPlugin { /** - * Configure the storage plugin at runtime. + * Configure the preferences plugin at runtime. * * Options that are `undefined` will not be used. * @@ -97,35 +97,35 @@ export interface StoragePlugin { configure(options: ConfigureOptions): Promise; /** - * Get the value from storage of a given key. + * Get the value from preferences of a given key. * * @since 1.0.0 */ get(options: GetOptions): Promise; /** - * Set the value in storage for a given key. + * Set the value in preferences for a given key. * * @since 1.0.0 */ set(options: SetOptions): Promise; /** - * Remove the value from storage for a given key, if any. + * Remove the value from preferences for a given key, if any. * * @since 1.0.0 */ remove(options: RemoveOptions): Promise; /** - * Clear keys and values from storage. + * Clear keys and values from preferences. * * @since 1.0.0 */ clear(): Promise; /** - * Return the list of known keys in storage. + * Return the list of known keys in preferences. * * @since 1.0.0 */ diff --git a/preferences/src/index.ts b/preferences/src/index.ts new file mode 100644 index 000000000..5a9196963 --- /dev/null +++ b/preferences/src/index.ts @@ -0,0 +1,10 @@ +import { registerPlugin } from '@capacitor/core'; + +import type { PreferencesPlugin } from './definitions'; + +const Preferences = registerPlugin('Preferences', { + web: () => import('./web').then(m => new m.PreferencesWeb()), +}); + +export * from './definitions'; +export { Preferences }; diff --git a/storage/src/web.ts b/preferences/src/web.ts similarity index 95% rename from storage/src/web.ts rename to preferences/src/web.ts index b8ca0e2fe..c533119df 100644 --- a/storage/src/web.ts +++ b/preferences/src/web.ts @@ -1,7 +1,7 @@ import { WebPlugin } from '@capacitor/core'; import type { - StoragePlugin, + PreferencesPlugin, ConfigureOptions, GetOptions, GetResult, @@ -11,7 +11,7 @@ import type { MigrateResult, } from './definitions'; -export class StorageWeb extends WebPlugin implements StoragePlugin { +export class PreferencesWeb extends WebPlugin implements PreferencesPlugin { private group = 'CapacitorStorage'; public async configure({ group }: ConfigureOptions): Promise { diff --git a/storage/tsconfig.json b/preferences/tsconfig.json similarity index 100% rename from storage/tsconfig.json rename to preferences/tsconfig.json diff --git a/push-notifications/CHANGELOG.md b/push-notifications/CHANGELOG.md index 7fc5ad8a4..4ce41bc9e 100644 --- a/push-notifications/CHANGELOG.md +++ b/push-notifications/CHANGELOG.md @@ -3,6 +3,94 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [4.1.2](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/push-notifications@4.1.1...@capacitor/push-notifications@4.1.2) (2022-11-16) + +**Note:** Version bump only for package @capacitor/push-notifications + + + + + +## [4.1.1](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/push-notifications@4.1.0...@capacitor/push-notifications@4.1.1) (2022-10-21) + +**Note:** Version bump only for package @capacitor/push-notifications + + + + + +# [4.1.0](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/push-notifications@1.0.9...@capacitor/push-notifications@4.1.0) (2022-09-12) + + +### Bug Fixes + +* **push-notifications:** properly get the configured icon from manifest ([#1118](https://github.com/ionic-team/capacitor-plugins/issues/1118)) ([20e87d3](https://github.com/ionic-team/capacitor-plugins/commit/20e87d3da337e12050cbfd6d7dd336b369b558b7)) + + + + + +## [4.0.1](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0...4.0.1) (2022-07-28) + +**Note:** Version bump only for package @capacitor/push-notifications + + + + + +# [4.0.0](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0-beta.2...4.0.0) (2022-07-27) + +**Note:** Version bump only for package @capacitor/push-notifications + + + + + +# [4.0.0-beta.2](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0-beta.0...4.0.0-beta.2) (2022-07-08) + +**Note:** Version bump only for package @capacitor/push-notifications + + + + + +# 4.0.0-beta.0 (2022-06-27) + + +### Bug Fixes + +* **push-notifications:** use id and tag for canceling active notification ([#1041](https://github.com/ionic-team/capacitor-plugins/issues/1041)) ([fa710a6](https://github.com/ionic-team/capacitor-plugins/commit/fa710a63ea87f0ec0a7b0059baacfad7a45f8558)) +* correct addListeners links ([#655](https://github.com/ionic-team/capacitor-plugins/issues/655)) ([f9871e7](https://github.com/ionic-team/capacitor-plugins/commit/f9871e7bd53478addb21155e148829f550c0e457)) +* inline source code in esm map files ([#760](https://github.com/ionic-team/capacitor-plugins/issues/760)) ([a960489](https://github.com/ionic-team/capacitor-plugins/commit/a960489a19db0182b90d187a50deff9dfbe51038)) +* Make removeAllListeners return a promise ([#895](https://github.com/ionic-team/capacitor-plugins/issues/895)) ([e5c49d6](https://github.com/ionic-team/capacitor-plugins/commit/e5c49d64445dca70286334e6a0441d8021197b13)) +* remove postpublish scripts ([#656](https://github.com/ionic-team/capacitor-plugins/issues/656)) ([ed6ac49](https://github.com/ionic-team/capacitor-plugins/commit/ed6ac499ebf4a47525071ccbfc36c27503e11f60)) +* **ios:** Coerce 'extra' field to add missing notification data on events ([#231](https://github.com/ionic-team/capacitor-plugins/issues/231)) ([46ce6b2](https://github.com/ionic-team/capacitor-plugins/commit/46ce6b2a72e4b107702b0cfb97007aaf385a3106)) +* **ios:** do not show notifications when in foreground ([#209](https://github.com/ionic-team/capacitor-plugins/issues/209)) ([1994997](https://github.com/ionic-team/capacitor-plugins/commit/1994997a100d7c57477305d933fb835cf9f7c9c8)) +* **push-notifications:** bump iOS deployment target to 12.0 ([#183](https://github.com/ionic-team/capacitor-plugins/issues/183)) ([d5b6503](https://github.com/ionic-team/capacitor-plugins/commit/d5b650312cded1606e39bbddc62acc6af9545997)) +* **push-notifications:** make removeAllListeners available ([#454](https://github.com/ionic-team/capacitor-plugins/issues/454)) ([d92c925](https://github.com/ionic-team/capacitor-plugins/commit/d92c92566b15d3b339e9a4c54471b65fda49a7f0)) +* **push-notifications:** proper return of push notification object properties ([#349](https://github.com/ionic-team/capacitor-plugins/issues/349)) ([733fc06](https://github.com/ionic-team/capacitor-plugins/commit/733fc06af7b62a576fb6214a7fe42838a3bcb93a)) +* **push-notifications:** Throw errors if missing mandatory channel fields ([#576](https://github.com/ionic-team/capacitor-plugins/issues/576)) ([50f4e70](https://github.com/ionic-team/capacitor-plugins/commit/50f4e7026e5cae5f0871d4863bfab36989208064)) +* add es2017 lib to tsconfig ([#180](https://github.com/ionic-team/capacitor-plugins/issues/180)) ([2c3776c](https://github.com/ionic-team/capacitor-plugins/commit/2c3776c38ca025c5ee965dec10ccf1cdb6c02e2f)) +* export all TS definitions ([6cd2996](https://github.com/ionic-team/capacitor-plugins/commit/6cd299660fdeb27382ec7f45f0b3a55224cd0ad1)) +* support deprecated types from Capacitor 2 ([#210](https://github.com/ionic-team/capacitor-plugins/issues/210)) ([b559e24](https://github.com/ionic-team/capacitor-plugins/commit/b559e24b24174be60129217e87c0bff14bcdd573)) +* **push-notifications:** remove unused Firebase/Messaging dependency ([#186](https://github.com/ionic-team/capacitor-plugins/issues/186)) ([0f4ca7c](https://github.com/ionic-team/capacitor-plugins/commit/0f4ca7ceaf67ced40b2cf2b359001b1ab060a3a6)) + + +### Features + +* set targetSDK default value to 32 ([#970](https://github.com/ionic-team/capacitor-plugins/issues/970)) ([fa70d96](https://github.com/ionic-team/capacitor-plugins/commit/fa70d96f141af751aae53ceb5642c46b204f5958)) +* **push-notifications:** Allow to show while in foreground ([#919](https://github.com/ionic-team/capacitor-plugins/issues/919)) ([a90b5fd](https://github.com/ionic-team/capacitor-plugins/commit/a90b5fd4fe82d660c96a8be55e360d15f9e5e8c6)) +* Use java 11 ([#910](https://github.com/ionic-team/capacitor-plugins/issues/910)) ([5acb2a2](https://github.com/ionic-team/capacitor-plugins/commit/5acb2a288a413492b163e4e97da46a085d9e4be0)) +* **push-notifications:** Add new type for registrationError ([#808](https://github.com/ionic-team/capacitor-plugins/issues/808)) ([e5e78bb](https://github.com/ionic-team/capacitor-plugins/commit/e5e78bbbff020e625ccfd49c8ae36b4f1609a242)) +* add commonjs output format ([#179](https://github.com/ionic-team/capacitor-plugins/issues/179)) ([8e9e098](https://github.com/ionic-team/capacitor-plugins/commit/8e9e09862064b3f6771d7facbc4008e995d9b463)) +* Push Notifications plugin ([#126](https://github.com/ionic-team/capacitor-plugins/issues/126)) ([0bcd833](https://github.com/ionic-team/capacitor-plugins/commit/0bcd833a6503061be45253b21fca9bd75576efc8)) +* set targetSDK default value to 31 ([#824](https://github.com/ionic-team/capacitor-plugins/issues/824)) ([3ee10de](https://github.com/ionic-team/capacitor-plugins/commit/3ee10de98067984c1a4e75295d001c5a895c47f4)) +* Upgrade gradle to 7.4 ([#826](https://github.com/ionic-team/capacitor-plugins/issues/826)) ([5db0906](https://github.com/ionic-team/capacitor-plugins/commit/5db0906f6264287c4f8e69dbaecf19d4d387824b)) + + + + + ## [1.0.9](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/push-notifications@1.0.8...@capacitor/push-notifications@1.0.9) (2022-01-19) diff --git a/push-notifications/CapacitorPushNotifications.podspec b/push-notifications/CapacitorPushNotifications.podspec index 22f681fbe..1dc3b5c2c 100644 --- a/push-notifications/CapacitorPushNotifications.podspec +++ b/push-notifications/CapacitorPushNotifications.podspec @@ -11,7 +11,7 @@ Pod::Spec.new do |s| s.author = package['author'] s.source = { :git => 'https://github.com/ionic-team/capacitor-plugins.git', :tag => package['name'] + '@' + package['version'] } s.source_files = 'ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}', 'push-notifications/ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}' - s.ios.deployment_target = '12.0' + s.ios.deployment_target = '13.0' s.dependency 'Capacitor' s.swift_version = '5.1' end diff --git a/push-notifications/README.md b/push-notifications/README.md index 3ee397042..53af165bf 100644 --- a/push-notifications/README.md +++ b/push-notifications/README.md @@ -33,7 +33,7 @@ The Push Notification API uses [Firebase Cloud Messaging](https://firebase.googl This plugin will use the following project variables (defined in your app's `variables.gradle` file): -- `$firebaseMessagingVersion` version of `com.google.firebase:firebase-messaging` (default: `21.0.1`) +- `$firebaseMessagingVersion` version of `com.google.firebase:firebase-messaging` (default: `23.0.5`) --- @@ -54,11 +54,11 @@ Android Studio has an icon generator you can use to create your Push Notificatio -On iOS you can configure the way the push notifications are displayed when the app is in foreground. +You can configure the way the push notifications are displayed when the app is in foreground. -| Prop | Type | Description | Since | -| ------------------------- | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----- | -| **`presentationOptions`** | PresentationOption[] | This is an array of strings you can combine. Possible values in the array are: - `badge`: badge count on the app icon is updated (default value) - `sound`: the device will ring/vibrate when the push notification is received - `alert`: the push notification is displayed in a native dialog An empty array can be provided if none of the options are desired. Only available for iOS. | 1.0.0 | +| Prop | Type | Description | Since | +| ------------------------- | --------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----- | +| **`presentationOptions`** | PresentationOption[] | This is an array of strings you can combine. Possible values in the array are: - `badge`: badge count on the app icon is updated (default value) - `sound`: the device will ring/vibrate when the push notification is received - `alert`: the push notification is displayed in a native dialog An empty array can be provided if none of the options are desired. badge is only available for iOS. | 1.0.0 | ### Examples @@ -262,16 +262,16 @@ Only available on Android O or newer (SDK 26+). ### deleteChannel(...) ```typescript -deleteChannel(channel: Channel) => Promise +deleteChannel(args: { id: string; }) => Promise ``` Delete a notification channel. Only available on Android O or newer (SDK 26+). -| Param | Type | -| ------------- | ------------------------------------------- | -| **`channel`** | Channel | +| Param | Type | +| ---------- | ---------------------------- | +| **`args`** | { id: string; } | **Since:** 1.0.0 @@ -327,7 +327,7 @@ receive push notifications. On iOS, the first time you use the function, it will prompt the user for push notification permission and return granted or denied based -on the user selection. On following calls it will currect status of +on the user selection. On following calls it will get the current status of the permission without prompting again. **Returns:** Promise<PermissionStatus> @@ -362,17 +362,17 @@ Provides the push notification token. ### addListener('registrationError', ...) ```typescript -addListener(eventName: 'registrationError', listenerFunc: (error: any) => void) => Promise & PluginListenerHandle +addListener(eventName: 'registrationError', listenerFunc: (error: RegistrationError) => void) => Promise & PluginListenerHandle ``` Called when the push notification registration finished with problems. Provides an error with the registration problem. -| Param | Type | -| ------------------ | ------------------------------------ | -| **`eventName`** | 'registrationError' | -| **`listenerFunc`** | (error: any) => void | +| Param | Type | +| ------------------ | ----------------------------------------------------------------------------------- | +| **`eventName`** | 'registrationError' | +| **`listenerFunc`** | (error: RegistrationError) => void | **Returns:** Promise<PluginListenerHandle> & PluginListenerHandle @@ -452,6 +452,7 @@ Remove all native listeners for this plugin. | **`subtitle`** | string | The notification subtitle. | 1.0.0 | | **`body`** | string | The main text payload for the notification. | 1.0.0 | | **`id`** | string | The notification identifier. | 1.0.0 | +| **`tag`** | string | The notification tag. Only available on Android (from push notifications). | 4.0.0 | | **`badge`** | number | The number to display for the app icon badge. | 1.0.0 | | **`notification`** | any | It's not being returned. | 1.0.0 | | **`data`** | any | Any additional data that was included in the push notification payload. | 1.0.0 | @@ -463,17 +464,17 @@ Remove all native listeners for this plugin. #### Channel -| Prop | Type | Description | Since | -| ----------------- | ------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----- | -| **`id`** | string | The channel identifier. | 1.0.0 | -| **`name`** | string | The human-friendly name of this channel (presented to the user). | 1.0.0 | -| **`description`** | string | The description of this channel (presented to the user). | 1.0.0 | -| **`sound`** | string | The sound that should be played for notifications posted to this channel. Notification channels with an importance of at least `3` should have a sound. The file name of a sound file should be specified relative to the android app `res/raw` directory. | 1.0.0 | -| **`importance`** | Importance | The level of interruption for notifications posted to this channel. | 1.0.0 | -| **`visibility`** | Visibility | The visibility of notifications posted to this channel. This setting is for whether notifications posted to this channel appear on the lockscreen or not, and if so, whether they appear in a redacted form. | 1.0.0 | -| **`lights`** | boolean | Whether notifications posted to this channel should display notification lights, on devices that support it. | 1.0.0 | -| **`lightColor`** | string | The light color for notifications posted to this channel. Only supported if lights are enabled on this channel and the device supports it. Supported color formats are `#RRGGBB` and `#RRGGBBAA`. | 1.0.0 | -| **`vibration`** | boolean | Whether notifications posted to this channel should vibrate. | 1.0.0 | +| Prop | Type | Description | Default | Since | +| ----------------- | ------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------- | ----- | +| **`id`** | string | The channel identifier. | | 1.0.0 | +| **`name`** | string | The human-friendly name of this channel (presented to the user). | | 1.0.0 | +| **`description`** | string | The description of this channel (presented to the user). | | 1.0.0 | +| **`sound`** | string | The sound that should be played for notifications posted to this channel. Notification channels with an importance of at least `3` should have a sound. The file name of a sound file should be specified relative to the android app `res/raw` directory. | | 1.0.0 | +| **`importance`** | Importance | The level of interruption for notifications posted to this channel. | `3` | 1.0.0 | +| **`visibility`** | Visibility | The visibility of notifications posted to this channel. This setting is for whether notifications posted to this channel appear on the lockscreen or not, and if so, whether they appear in a redacted form. | | 1.0.0 | +| **`lights`** | boolean | Whether notifications posted to this channel should display notification lights, on devices that support it. | | 1.0.0 | +| **`lightColor`** | string | The light color for notifications posted to this channel. Only supported if lights are enabled on this channel and the device supports it. Supported color formats are `#RRGGBB` and `#RRGGBBAA`. | | 1.0.0 | +| **`vibration`** | boolean | Whether notifications posted to this channel should vibrate. | | 1.0.0 | #### ListChannelsResult @@ -504,6 +505,13 @@ Remove all native listeners for this plugin. | **`value`** | string | On iOS it contains the APNS token. On Android it contains the FCM token. | 1.0.0 | +#### RegistrationError + +| Prop | Type | Description | Since | +| ----------- | ------------------- | -------------------------------------------------- | ----- | +| **`error`** | string | Error message describing the registration failure. | 4.0.0 | + + #### ActionPerformed | Prop | Type | Description | Since | diff --git a/push-notifications/android/build.gradle b/push-notifications/android/build.gradle index 81ddb68c5..325d3d7d6 100644 --- a/push-notifications/android/build.gradle +++ b/push-notifications/android/build.gradle @@ -1,28 +1,40 @@ ext { - junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.1' - androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.2.0' - androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.1.2' - androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.3.0' - firebaseMessagingVersion = project.hasProperty('firebaseMessagingVersion') ? rootProject.ext.firebaseMessagingVersion : '21.0.1' + capacitorVersion = System.getenv('CAPACITOR_VERSION') + junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.2' + androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.4.2' + androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.1.3' + androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.4.0' + firebaseMessagingVersion = project.hasProperty('firebaseMessagingVersion') ? rootProject.ext.firebaseMessagingVersion : '23.0.5' } buildscript { repositories { google() mavenCentral() + maven { + url "https://plugins.gradle.org/m2/" + } } dependencies { - classpath 'com.android.tools.build:gradle:4.2.1' + classpath 'com.android.tools.build:gradle:7.2.1' + if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + classpath 'io.github.gradle-nexus:publish-plugin:1.1.0' + } } } apply plugin: 'com.android.library' +if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + apply plugin: 'io.github.gradle-nexus.publish-plugin' + apply from: file('../../scripts/android/publish-root.gradle') + apply from: file('../../scripts/android/publish-module.gradle') +} android { - compileSdkVersion project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 30 + compileSdkVersion project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 32 defaultConfig { - minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 21 - targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 30 + minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 22 + targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 32 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" @@ -37,21 +49,26 @@ android { abortOnError false } compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility JavaVersion.VERSION_11 + targetCompatibility JavaVersion.VERSION_11 } } repositories { google() mavenCentral() - jcenter() } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation project(':capacitor-android') + + if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + implementation "com.capacitorjs:core:$capacitorVersion" + } else { + implementation project(':capacitor-android') + } + implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion" implementation "com.google.firebase:firebase-messaging:$firebaseMessagingVersion" testImplementation "junit:junit:$junitVersion" diff --git a/push-notifications/android/gradle/wrapper/gradle-wrapper.jar b/push-notifications/android/gradle/wrapper/gradle-wrapper.jar index e708b1c02..41d9927a4 100644 Binary files a/push-notifications/android/gradle/wrapper/gradle-wrapper.jar and b/push-notifications/android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/push-notifications/android/gradle/wrapper/gradle-wrapper.properties b/push-notifications/android/gradle/wrapper/gradle-wrapper.properties index 3c4101c3e..92f06b50f 100644 --- a/push-notifications/android/gradle/wrapper/gradle-wrapper.properties +++ b/push-notifications/android/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/push-notifications/android/gradlew b/push-notifications/android/gradlew index 4f906e0c8..1b6c78733 100755 --- a/push-notifications/android/gradlew +++ b/push-notifications/android/gradlew @@ -1,7 +1,7 @@ -#!/usr/bin/env sh +#!/bin/sh # -# Copyright 2015 the original author or authors. +# Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,67 +17,101 @@ # ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` +APP_BASE_NAME=${0##*/} # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar @@ -87,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -98,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" + JAVACMD=java which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the @@ -106,80 +140,95 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=`expr $i + 1` + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" diff --git a/push-notifications/android/src/main/java/com/capacitorjs/plugins/pushnotifications/NotificationChannelManager.java b/push-notifications/android/src/main/java/com/capacitorjs/plugins/pushnotifications/NotificationChannelManager.java index f2c40ade9..60458a997 100644 --- a/push-notifications/android/src/main/java/com/capacitorjs/plugins/pushnotifications/NotificationChannelManager.java +++ b/push-notifications/android/src/main/java/com/capacitorjs/plugins/pushnotifications/NotificationChannelManager.java @@ -4,25 +4,29 @@ import android.app.NotificationManager; import android.content.ContentResolver; import android.content.Context; -import android.graphics.Color; import android.media.AudioAttributes; import android.net.Uri; +import android.os.Build; +import android.provider.Settings; import androidx.core.app.NotificationCompat; -import com.getcapacitor.JSArray; -import com.getcapacitor.JSObject; -import com.getcapacitor.Logger; -import com.getcapacitor.PluginCall; +import com.getcapacitor.*; import com.getcapacitor.util.WebColor; +import java.util.Arrays; import java.util.List; public class NotificationChannelManager { + public static final String FOREGROUND_NOTIFICATION_CHANNEL_ID = "PushDefaultForeground"; + private Context context; private NotificationManager notificationManager; + private PluginConfig config; - public NotificationChannelManager(Context context, NotificationManager manager) { + public NotificationChannelManager(Context context, NotificationManager manager, PluginConfig config) { this.context = context; this.notificationManager = manager; + this.config = config; + createForegroundNotificationChannel(); } private static String CHANNEL_ID = "id"; @@ -50,12 +54,8 @@ public void createChannel(PluginCall call) { call.reject("Channel missing name"); return; } - if (call.getInt(CHANNEL_IMPORTANCE) != null) { - channel.put(CHANNEL_IMPORTANCE, call.getInt(CHANNEL_IMPORTANCE)); - } else { - call.reject("Channel missing importance"); - return; - } + + channel.put(CHANNEL_IMPORTANCE, call.getInt(CHANNEL_IMPORTANCE, NotificationManager.IMPORTANCE_DEFAULT)); channel.put(CHANNEL_DESCRIPTION, call.getString(CHANNEL_DESCRIPTION, "")); channel.put(CHANNEL_VISIBILITY, call.getInt(CHANNEL_VISIBILITY, NotificationCompat.VISIBILITY_PUBLIC)); channel.put(CHANNEL_SOUND, call.getString(CHANNEL_SOUND, null)); @@ -140,4 +140,35 @@ public void listChannels(PluginCall call) { call.unavailable(); } } + + /** + * Create notification channel + */ + public void createForegroundNotificationChannel() { + // Create the NotificationChannel only if presentationOptions is defined + // Because the channel can't be changed after creation + String[] presentation = config.getArray("presentationOptions"); + if (presentation != null) { + // And only on API 26+ because the NotificationChannel class + // is new and not in the support library + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + CharSequence name = "Push Notifications Foreground"; + String description = "Push notifications in foreground"; + int importance = NotificationManager.IMPORTANCE_HIGH; + NotificationChannel channel = new NotificationChannel(FOREGROUND_NOTIFICATION_CHANNEL_ID, name, importance); + channel.setDescription(description); + if (Arrays.asList(presentation).contains("sound")) { + AudioAttributes audioAttributes = new AudioAttributes.Builder() + .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) + .setUsage(AudioAttributes.USAGE_ALARM) + .build(); + channel.setSound(Settings.System.DEFAULT_NOTIFICATION_URI, audioAttributes); + } + // Register the channel with the system; you can't change the importance + // or other notification behaviors after this + android.app.NotificationManager notificationManager = context.getSystemService(android.app.NotificationManager.class); + notificationManager.createNotificationChannel(channel); + } + } + } } diff --git a/push-notifications/android/src/main/java/com/capacitorjs/plugins/pushnotifications/PushNotificationsPlugin.java b/push-notifications/android/src/main/java/com/capacitorjs/plugins/pushnotifications/PushNotificationsPlugin.java index 019534454..b3c7824d3 100644 --- a/push-notifications/android/src/main/java/com/capacitorjs/plugins/pushnotifications/PushNotificationsPlugin.java +++ b/push-notifications/android/src/main/java/com/capacitorjs/plugins/pushnotifications/PushNotificationsPlugin.java @@ -4,26 +4,20 @@ import android.app.NotificationManager; import android.content.Context; import android.content.Intent; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.service.notification.StatusBarNotification; -import com.getcapacitor.Bridge; -import com.getcapacitor.JSArray; -import com.getcapacitor.JSObject; -import com.getcapacitor.Plugin; -import com.getcapacitor.PluginCall; -import com.getcapacitor.PluginHandle; -import com.getcapacitor.PluginMethod; +import androidx.core.app.NotificationCompat; +import com.getcapacitor.*; import com.getcapacitor.annotation.CapacitorPlugin; import com.getcapacitor.annotation.Permission; -import com.google.android.gms.tasks.OnFailureListener; -import com.google.android.gms.tasks.OnSuccessListener; -import com.google.firebase.iid.FirebaseInstanceId; -import com.google.firebase.iid.InstanceIdResult; import com.google.firebase.messaging.FirebaseMessaging; import com.google.firebase.messaging.RemoteMessage; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import org.json.JSONException; import org.json.JSONObject; @@ -50,7 +44,7 @@ public void load() { lastMessage = null; } - notificationChannelManager = new NotificationChannelManager(getActivity(), notificationManager); + notificationChannelManager = new NotificationChannelManager(getActivity(), notificationManager, getConfig()); } @Override @@ -80,26 +74,16 @@ protected void handleOnNewIntent(Intent data) { @PluginMethod public void register(PluginCall call) { FirebaseMessaging.getInstance().setAutoInitEnabled(true); - FirebaseInstanceId + FirebaseMessaging .getInstance() - .getInstanceId() - .addOnSuccessListener( - getActivity(), - new OnSuccessListener() { - @Override - public void onSuccess(InstanceIdResult instanceIdResult) { - sendToken(instanceIdResult.getToken()); - } - } - ); - FirebaseInstanceId - .getInstance() - .getInstanceId() - .addOnFailureListener( - new OnFailureListener() { - public void onFailure(Exception e) { - sendError(e.getLocalizedMessage()); + .getToken() + .addOnCompleteListener( + task -> { + if (!task.isSuccessful()) { + sendError(task.getException().getLocalizedMessage()); + return; } + sendToken(task.getResult()); } ); call.resolve(); @@ -115,6 +99,7 @@ public void getDeliveredNotifications(PluginCall call) { JSObject jsNotif = new JSObject(); jsNotif.put("id", notif.getId()); + jsNotif.put("tag", notif.getTag()); Notification notification = notif.getNotification(); if (notification != null) { @@ -145,13 +130,18 @@ public void getDeliveredNotifications(PluginCall call) { public void removeDeliveredNotifications(PluginCall call) { JSArray notifications = call.getArray("notifications"); - List ids = new ArrayList<>(); try { for (Object o : notifications.toList()) { if (o instanceof JSONObject) { JSObject notif = JSObject.fromJSONObject((JSONObject) o); + String tag = notif.getString("tag"); Integer id = notif.getInteger("id"); - ids.add(id); + + if (tag == null) { + notificationManager.cancel(id); + } else { + notificationManager.cancel(tag, id); + } } else { call.reject("Expected notifications to be a list of notification objects"); } @@ -160,10 +150,6 @@ public void removeDeliveredNotifications(PluginCall call) { call.reject(e.getMessage()); } - for (int id : ids) { - notificationManager.cancel(id); - } - call.resolve(); } @@ -229,8 +215,38 @@ public void fireNotification(RemoteMessage remoteMessage) { RemoteMessage.Notification notification = remoteMessage.getNotification(); if (notification != null) { - remoteMessageData.put("title", notification.getTitle()); - remoteMessageData.put("body", notification.getBody()); + String title = notification.getTitle(); + String body = notification.getBody(); + String[] presentation = getConfig().getArray("presentationOptions"); + if (presentation != null) { + if (Arrays.asList(presentation).contains("alert")) { + Bundle bundle = null; + try { + ApplicationInfo applicationInfo = getContext() + .getPackageManager() + .getApplicationInfo(getContext().getPackageName(), PackageManager.GET_META_DATA); + bundle = applicationInfo.metaData; + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + } + int pushIcon = android.R.drawable.ic_dialog_info; + + if (bundle != null && bundle.getInt("com.google.firebase.messaging.default_notification_icon") != 0) { + pushIcon = bundle.getInt("com.google.firebase.messaging.default_notification_icon"); + } + NotificationCompat.Builder builder = new NotificationCompat.Builder( + getContext(), + NotificationChannelManager.FOREGROUND_NOTIFICATION_CHANNEL_ID + ) + .setSmallIcon(pushIcon) + .setContentTitle(title) + .setContentText(body) + .setPriority(NotificationCompat.PRIORITY_DEFAULT); + notificationManager.notify(0, builder.build()); + } + } + remoteMessageData.put("title", title); + remoteMessageData.put("body", body); remoteMessageData.put("click_action", notification.getClickAction()); Uri link = notification.getLink(); diff --git a/push-notifications/ios/Plugin.xcodeproj/project.pbxproj b/push-notifications/ios/Plugin.xcodeproj/project.pbxproj index 9c5c5d458..e1ec92bc6 100644 --- a/push-notifications/ios/Plugin.xcodeproj/project.pbxproj +++ b/push-notifications/ios/Plugin.xcodeproj/project.pbxproj @@ -387,7 +387,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -448,7 +448,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; @@ -471,12 +471,13 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Plugin/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks $(FRAMEWORK_SEARCH_PATHS)\n$(FRAMEWORK_SEARCH_PATHS)\n$(FRAMEWORK_SEARCH_PATHS)"; ONLY_ACTIVE_ARCH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.getcapacitor.Plugin; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; + SUPPORTS_MACCATALYST = NO; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -496,12 +497,13 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Plugin/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks $(FRAMEWORK_SEARCH_PATHS)"; ONLY_ACTIVE_ARCH = NO; PRODUCT_BUNDLE_IDENTIFIER = com.getcapacitor.Plugin; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; + SUPPORTS_MACCATALYST = NO; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; diff --git a/push-notifications/ios/Plugin/PushNotificationsHandler.swift b/push-notifications/ios/Plugin/PushNotificationsHandler.swift index b33857660..f3972b68a 100644 --- a/push-notifications/ios/Plugin/PushNotificationsHandler.swift +++ b/push-notifications/ios/Plugin/PushNotificationsHandler.swift @@ -29,7 +29,7 @@ public class PushNotificationsHandler: NSObject, NotificationHandlerProtocol { } } - if let optionsArray = self.plugin?.getConfigValue("presentationOptions") as? [String] { + if let optionsArray = self.plugin?.getConfig().getArray("presentationOptions") as? [String] { var presentationOptions = UNNotificationPresentationOptions.init() optionsArray.forEach { option in diff --git a/push-notifications/ios/Plugin/PushNotificationsPlugin.m b/push-notifications/ios/Plugin/PushNotificationsPlugin.m index 01931ee91..883b2d243 100644 --- a/push-notifications/ios/Plugin/PushNotificationsPlugin.m +++ b/push-notifications/ios/Plugin/PushNotificationsPlugin.m @@ -9,7 +9,7 @@ CAP_PLUGIN_METHOD(requestPermissions, CAPPluginReturnPromise); CAP_PLUGIN_METHOD(getDeliveredNotifications, CAPPluginReturnPromise); CAP_PLUGIN_METHOD(removeAllDeliveredNotifications, CAPPluginReturnPromise); - CAP_PLUGIN_METHOD(removeAllListeners, CAPPluginReturnNone); + CAP_PLUGIN_METHOD(removeAllListeners, CAPPluginReturnPromise); CAP_PLUGIN_METHOD(removeDeliveredNotifications, CAPPluginReturnPromise); CAP_PLUGIN_METHOD(createChannel, CAPPluginReturnPromise); CAP_PLUGIN_METHOD(listChannels, CAPPluginReturnPromise); diff --git a/push-notifications/ios/Podfile b/push-notifications/ios/Podfile index 80322bf8a..d10106a86 100644 --- a/push-notifications/ios/Podfile +++ b/push-notifications/ios/Podfile @@ -1,4 +1,4 @@ -platform :ios, '12.0' +platform :ios, '13.0' def capacitor_pods # Comment the next line if you're not using Swift and don't want to use dynamic frameworks diff --git a/push-notifications/package.json b/push-notifications/package.json index 50851d185..f64a10cc4 100644 --- a/push-notifications/package.json +++ b/push-notifications/package.json @@ -1,6 +1,6 @@ { "name": "@capacitor/push-notifications", - "version": "1.0.9", + "version": "4.1.2", "description": "The Push Notifications API provides access to native push notifications.", "main": "dist/plugin.cjs.js", "module": "dist/esm/index.js", @@ -29,7 +29,7 @@ ], "scripts": { "verify": "npm run verify:ios && npm run verify:android && npm run verify:web", - "verify:ios": "cd ios && pod install && xcodebuild -workspace Plugin.xcworkspace -scheme Plugin && cd ..", + "verify:ios": "cd ios && pod install && xcodebuild -workspace Plugin.xcworkspace -scheme Plugin -destination generic/platform=iOS && cd ..", "verify:android": "cd android && ./gradlew clean build test && cd ..", "verify:web": "npm run build", "lint": "npm run eslint && npm run prettier -- --check && npm run swiftlint -- lint", @@ -45,11 +45,11 @@ "publish:cocoapod": "pod trunk push ./CapacitorPushNotifications.podspec --allow-warnings" }, "devDependencies": { - "@capacitor/android": "^3.0.0", - "@capacitor/cli": "^3.0.0", - "@capacitor/core": "^3.0.0", - "@capacitor/docgen": "0.0.18", - "@capacitor/ios": "^3.0.0", + "@capacitor/android": "^4.0.0", + "@capacitor/cli": "^4.0.0", + "@capacitor/core": "^4.0.0", + "@capacitor/docgen": "0.2.0", + "@capacitor/ios": "^4.0.0", "@ionic/eslint-config": "^0.3.0", "@ionic/prettier-config": "~1.0.1", "@ionic/swiftlint-config": "^1.1.2", @@ -62,7 +62,7 @@ "typescript": "~4.1.5" }, "peerDependencies": { - "@capacitor/core": "^3.0.0" + "@capacitor/core": "^4.0.0" }, "prettier": "@ionic/prettier-config", "swiftlint": "@ionic/swiftlint-config", diff --git a/push-notifications/src/definitions.ts b/push-notifications/src/definitions.ts index c46250361..08f4e2fbf 100644 --- a/push-notifications/src/definitions.ts +++ b/push-notifications/src/definitions.ts @@ -7,7 +7,7 @@ export type PresentationOption = 'badge' | 'sound' | 'alert'; declare module '@capacitor/cli' { export interface PluginsConfig { /** - * On iOS you can configure the way the push notifications are displayed when the app is in foreground. + * You can configure the way the push notifications are displayed when the app is in foreground. */ PushNotifications?: { /** @@ -18,7 +18,7 @@ declare module '@capacitor/cli' { * * An empty array can be provided if none of the options are desired. * - * Only available for iOS. + * badge is only available for iOS. * * @since 1.0.0 * @example ["badge", "sound", "alert"] @@ -79,7 +79,7 @@ export interface PushNotificationsPlugin { * * @since 1.0.0 */ - deleteChannel(channel: Channel): Promise; + deleteChannel(args: { id: string }): Promise; /** * List the available notification channels. @@ -109,7 +109,7 @@ export interface PushNotificationsPlugin { * * On iOS, the first time you use the function, it will prompt the user * for push notification permission and return granted or denied based - * on the user selection. On following calls it will currect status of + * on the user selection. On following calls it will get the current status of * the permission without prompting again. * * @since 1.0.0 @@ -137,7 +137,7 @@ export interface PushNotificationsPlugin { */ addListener( eventName: 'registrationError', - listenerFunc: (error: any) => void, + listenerFunc: (error: RegistrationError) => void, ): Promise & PluginListenerHandle; /** @@ -197,6 +197,15 @@ export interface PushNotificationSchema { */ id: string; + /** + * The notification tag. + * + * Only available on Android (from push notifications). + * + * @since 4.0.0 + */ + tag?: string; + /** * The number to display for the app icon badge. * @@ -292,6 +301,15 @@ export interface Token { value: string; } +export interface RegistrationError { + /** + * Error message describing the registration failure. + * + * @since 4.0.0 + */ + error: string; +} + export interface DeliveredNotifications { /** * List of notifications that are visible on the @@ -341,9 +359,10 @@ export interface Channel { /** * The level of interruption for notifications posted to this channel. * + * @default `3` * @since 1.0.0 */ - importance: Importance; + importance?: Importance; /** * The visibility of notifications posted to this channel. diff --git a/screen-reader/CHANGELOG.md b/screen-reader/CHANGELOG.md index 6f5ec8b07..a35b55181 100644 --- a/screen-reader/CHANGELOG.md +++ b/screen-reader/CHANGELOG.md @@ -3,6 +3,93 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [4.1.2](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/screen-reader@4.1.1...@capacitor/screen-reader@4.1.2) (2022-11-16) + +**Note:** Version bump only for package @capacitor/screen-reader + + + + + +## [4.1.1](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/screen-reader@4.1.0...@capacitor/screen-reader@4.1.1) (2022-10-21) + +**Note:** Version bump only for package @capacitor/screen-reader + + + + + +# [4.1.0](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/screen-reader@1.0.8...@capacitor/screen-reader@4.1.0) (2022-09-29) + + +### Bug Fixes + +* **screen-reader:** make speak use accessibility volume ([#1185](https://github.com/ionic-team/capacitor-plugins/issues/1185)) ([daa7b63](https://github.com/ionic-team/capacitor-plugins/commit/daa7b634797216123cf4eac1a04086b0c026cf90)) + + + + + +## [4.0.1](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0...4.0.1) (2022-07-28) + +**Note:** Version bump only for package @capacitor/screen-reader + + + + + +# [4.0.0](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0-beta.2...4.0.0) (2022-07-27) + +**Note:** Version bump only for package @capacitor/screen-reader + + + + + +# [4.0.0-beta.2](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0-beta.0...4.0.0-beta.2) (2022-07-08) + +**Note:** Version bump only for package @capacitor/screen-reader + + + + + +# 4.0.0-beta.0 (2022-06-27) + + +### Bug Fixes + +* add es2017 lib to tsconfig ([#180](https://github.com/ionic-team/capacitor-plugins/issues/180)) ([2c3776c](https://github.com/ionic-team/capacitor-plugins/commit/2c3776c38ca025c5ee965dec10ccf1cdb6c02e2f)) +* better ignore rules for npm distribution ([#32](https://github.com/ionic-team/capacitor-plugins/issues/32)) ([b8d55b9](https://github.com/ionic-team/capacitor-plugins/commit/b8d55b9233e4ad7b8a1cd41110b4e580fc2a059f)) +* correct addListeners links ([#655](https://github.com/ionic-team/capacitor-plugins/issues/655)) ([f9871e7](https://github.com/ionic-team/capacitor-plugins/commit/f9871e7bd53478addb21155e148829f550c0e457)) +* inline source code in esm map files ([#760](https://github.com/ionic-team/capacitor-plugins/issues/760)) ([a960489](https://github.com/ionic-team/capacitor-plugins/commit/a960489a19db0182b90d187a50deff9dfbe51038)) +* Make removeAllListeners return a promise ([#895](https://github.com/ionic-team/capacitor-plugins/issues/895)) ([e5c49d6](https://github.com/ionic-team/capacitor-plugins/commit/e5c49d64445dca70286334e6a0441d8021197b13)) +* remove postpublish scripts ([#656](https://github.com/ionic-team/capacitor-plugins/issues/656)) ([ed6ac49](https://github.com/ionic-team/capacitor-plugins/commit/ed6ac499ebf4a47525071ccbfc36c27503e11f60)) +* support deprecated types from Capacitor 2 ([#139](https://github.com/ionic-team/capacitor-plugins/issues/139)) ([2d7127a](https://github.com/ionic-team/capacitor-plugins/commit/2d7127a488e26f0287951921a6db47c49d817336)) +* use correct package in manifest files ([#22](https://github.com/ionic-team/capacitor-plugins/issues/22)) ([ab62987](https://github.com/ionic-team/capacitor-plugins/commit/ab629877e1951f944594f1b23e1bffefcbc783dd)) + + +### Features + +* add commonjs output format ([#179](https://github.com/ionic-team/capacitor-plugins/issues/179)) ([8e9e098](https://github.com/ionic-team/capacitor-plugins/commit/8e9e09862064b3f6771d7facbc4008e995d9b463)) +* Screen Reader plugin ([#1](https://github.com/ionic-team/capacitor-plugins/issues/1)) ([d0ab633](https://github.com/ionic-team/capacitor-plugins/commit/d0ab63335a3ba1d303dc11e0fc72767200e6390b)) +* set targetSDK default value to 31 ([#824](https://github.com/ionic-team/capacitor-plugins/issues/824)) ([3ee10de](https://github.com/ionic-team/capacitor-plugins/commit/3ee10de98067984c1a4e75295d001c5a895c47f4)) +* set targetSDK default value to 32 ([#970](https://github.com/ionic-team/capacitor-plugins/issues/970)) ([fa70d96](https://github.com/ionic-team/capacitor-plugins/commit/fa70d96f141af751aae53ceb5642c46b204f5958)) +* Upgrade gradle to 7.4 ([#826](https://github.com/ionic-team/capacitor-plugins/issues/826)) ([5db0906](https://github.com/ionic-team/capacitor-plugins/commit/5db0906f6264287c4f8e69dbaecf19d4d387824b)) +* Use java 11 ([#910](https://github.com/ionic-team/capacitor-plugins/issues/910)) ([5acb2a2](https://github.com/ionic-team/capacitor-plugins/commit/5acb2a288a413492b163e4e97da46a085d9e4be0)) + + + + + +## [1.0.8](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/screen-reader@1.0.7...@capacitor/screen-reader@1.0.8) (2022-03-03) + +**Note:** Version bump only for package @capacitor/screen-reader + + + + + ## [1.0.7](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/screen-reader@1.0.6...@capacitor/screen-reader@1.0.7) (2022-01-19) diff --git a/screen-reader/CapacitorScreenReader.podspec b/screen-reader/CapacitorScreenReader.podspec index 37e2cb0af..b70c3a1e3 100644 --- a/screen-reader/CapacitorScreenReader.podspec +++ b/screen-reader/CapacitorScreenReader.podspec @@ -11,7 +11,7 @@ Pod::Spec.new do |s| s.author = package['author'] s.source = { :git => 'https://github.com/ionic-team/capacitor-plugins.git', :tag => package['name'] + '@' + package['version'] } s.source_files = 'ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}', 'screen-reader/ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}' - s.ios.deployment_target = '12.0' + s.ios.deployment_target = '13.0' s.dependency 'Capacitor' s.swift_version = '5.1' end diff --git a/screen-reader/README.md b/screen-reader/README.md index 9e8a021eb..b0eeb009b 100644 --- a/screen-reader/README.md +++ b/screen-reader/README.md @@ -21,7 +21,7 @@ ScreenReader.addListener('screenReaderStateChange', ({ value }) => { const checkScreenReaderEnabled = async () => { const { value } = await ScreenReader.isEnabled(); - alert('Voice over enabled? ' + value); + console.log('Voice over enabled? ' + value); }; const sayHello = async () => { diff --git a/screen-reader/android/build.gradle b/screen-reader/android/build.gradle index 56ee0b28b..43252f49c 100644 --- a/screen-reader/android/build.gradle +++ b/screen-reader/android/build.gradle @@ -1,27 +1,39 @@ ext { - junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.1' - androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.2.0' - androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.1.2' - androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.3.0' + capacitorVersion = System.getenv('CAPACITOR_VERSION') + junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.2' + androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.4.2' + androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.1.3' + androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.4.0' } buildscript { repositories { google() mavenCentral() + maven { + url "https://plugins.gradle.org/m2/" + } } dependencies { - classpath 'com.android.tools.build:gradle:4.2.1' + classpath 'com.android.tools.build:gradle:7.2.1' + if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + classpath 'io.github.gradle-nexus:publish-plugin:1.1.0' + } } } apply plugin: 'com.android.library' +if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + apply plugin: 'io.github.gradle-nexus.publish-plugin' + apply from: file('../../scripts/android/publish-root.gradle') + apply from: file('../../scripts/android/publish-module.gradle') +} android { - compileSdkVersion project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 30 + compileSdkVersion project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 32 defaultConfig { - minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 21 - targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 30 + minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 22 + targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 32 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" @@ -36,21 +48,26 @@ android { abortOnError false } compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility JavaVersion.VERSION_11 + targetCompatibility JavaVersion.VERSION_11 } } repositories { google() mavenCentral() - jcenter() } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation project(':capacitor-android') + + if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + implementation "com.capacitorjs:core:$capacitorVersion" + } else { + implementation project(':capacitor-android') + } + implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion" testImplementation "junit:junit:$junitVersion" androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion" diff --git a/screen-reader/android/gradle/wrapper/gradle-wrapper.jar b/screen-reader/android/gradle/wrapper/gradle-wrapper.jar index e708b1c02..41d9927a4 100644 Binary files a/screen-reader/android/gradle/wrapper/gradle-wrapper.jar and b/screen-reader/android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/screen-reader/android/gradle/wrapper/gradle-wrapper.properties b/screen-reader/android/gradle/wrapper/gradle-wrapper.properties index 3c4101c3e..92f06b50f 100644 --- a/screen-reader/android/gradle/wrapper/gradle-wrapper.properties +++ b/screen-reader/android/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/screen-reader/android/gradlew b/screen-reader/android/gradlew index 4f906e0c8..1b6c78733 100755 --- a/screen-reader/android/gradlew +++ b/screen-reader/android/gradlew @@ -1,7 +1,7 @@ -#!/usr/bin/env sh +#!/bin/sh # -# Copyright 2015 the original author or authors. +# Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,67 +17,101 @@ # ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` +APP_BASE_NAME=${0##*/} # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar @@ -87,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -98,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" + JAVACMD=java which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the @@ -106,80 +140,95 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=`expr $i + 1` + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" diff --git a/screen-reader/android/src/main/java/com/capacitorjs/plugins/screenreader/ScreenReader.java b/screen-reader/android/src/main/java/com/capacitorjs/plugins/screenreader/ScreenReader.java index 692f872af..44685bf86 100644 --- a/screen-reader/android/src/main/java/com/capacitorjs/plugins/screenreader/ScreenReader.java +++ b/screen-reader/android/src/main/java/com/capacitorjs/plugins/screenreader/ScreenReader.java @@ -1,6 +1,7 @@ package com.capacitorjs.plugins.screenreader; import android.content.Context; +import android.media.AudioAttributes; import android.speech.tts.TextToSpeech; import android.view.accessibility.AccessibilityManager; import java.util.ArrayList; @@ -50,6 +51,10 @@ public void speak(final String text, final String languageTag) { new TextToSpeech( context, status -> { + AudioAttributes attributes = new AudioAttributes.Builder() + .setUsage(AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY) + .build(); + textToSpeech.setAudioAttributes(attributes); textToSpeech.setLanguage(locale); textToSpeech.speak(text, TextToSpeech.QUEUE_FLUSH, null, "capacitor-screen-reader" + System.currentTimeMillis()); } diff --git a/screen-reader/ios/Plugin.xcodeproj/project.pbxproj b/screen-reader/ios/Plugin.xcodeproj/project.pbxproj index 03ddad35b..e6fbaaabf 100644 --- a/screen-reader/ios/Plugin.xcodeproj/project.pbxproj +++ b/screen-reader/ios/Plugin.xcodeproj/project.pbxproj @@ -382,7 +382,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -442,7 +442,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; @@ -465,12 +465,13 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Plugin/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks $(FRAMEWORK_SEARCH_PATHS)\n$(FRAMEWORK_SEARCH_PATHS)\n$(FRAMEWORK_SEARCH_PATHS)"; ONLY_ACTIVE_ARCH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.getcapacitor.Plugin; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; + SUPPORTS_MACCATALYST = NO; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -490,12 +491,13 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Plugin/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks $(FRAMEWORK_SEARCH_PATHS)"; ONLY_ACTIVE_ARCH = NO; PRODUCT_BUNDLE_IDENTIFIER = com.getcapacitor.Plugin; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; + SUPPORTS_MACCATALYST = NO; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; diff --git a/screen-reader/ios/Plugin/ScreenReaderPlugin.m b/screen-reader/ios/Plugin/ScreenReaderPlugin.m index 86dec5bb2..6221414a9 100644 --- a/screen-reader/ios/Plugin/ScreenReaderPlugin.m +++ b/screen-reader/ios/Plugin/ScreenReaderPlugin.m @@ -6,5 +6,5 @@ CAP_PLUGIN(ScreenReaderPlugin, "ScreenReader", CAP_PLUGIN_METHOD(speak, CAPPluginReturnPromise); CAP_PLUGIN_METHOD(isEnabled, CAPPluginReturnPromise); - CAP_PLUGIN_METHOD(removeAllListeners, CAPPluginReturnNone); + CAP_PLUGIN_METHOD(removeAllListeners, CAPPluginReturnPromise); ) diff --git a/screen-reader/ios/Podfile b/screen-reader/ios/Podfile index 54a00c161..dee40960f 100644 --- a/screen-reader/ios/Podfile +++ b/screen-reader/ios/Podfile @@ -1,4 +1,4 @@ -platform :ios, '12.0' +platform :ios, '13.0' def capacitor_pods # Comment the next line if you're not using Swift and don't want to use dynamic frameworks diff --git a/screen-reader/package.json b/screen-reader/package.json index 62929ebe4..1cbba6ed6 100644 --- a/screen-reader/package.json +++ b/screen-reader/package.json @@ -1,6 +1,6 @@ { "name": "@capacitor/screen-reader", - "version": "1.0.7", + "version": "4.1.2", "description": "The Screen Reader API provides access to TalkBack/VoiceOver/etc. and provides simple text-to-speech capabilities for visual accessibility.", "main": "dist/plugin.cjs.js", "module": "dist/esm/index.js", @@ -29,7 +29,7 @@ ], "scripts": { "verify": "npm run verify:ios && npm run verify:android && npm run verify:web", - "verify:ios": "cd ios && pod install && xcodebuild -workspace Plugin.xcworkspace -scheme Plugin && cd ..", + "verify:ios": "cd ios && pod install && xcodebuild -workspace Plugin.xcworkspace -scheme Plugin -destination generic/platform=iOS && cd ..", "verify:android": "cd android && ./gradlew clean build test && cd ..", "verify:web": "npm run build", "lint": "npm run eslint && npm run prettier -- --check && npm run swiftlint -- lint", @@ -45,10 +45,10 @@ "publish:cocoapod": "pod trunk push ./CapacitorScreenReader.podspec --allow-warnings" }, "devDependencies": { - "@capacitor/android": "^3.0.0", - "@capacitor/core": "^3.0.0", - "@capacitor/docgen": "0.0.18", - "@capacitor/ios": "^3.0.0", + "@capacitor/android": "^4.0.0", + "@capacitor/core": "^4.0.0", + "@capacitor/docgen": "0.2.0", + "@capacitor/ios": "^4.0.0", "@ionic/eslint-config": "^0.3.0", "@ionic/prettier-config": "~1.0.1", "@ionic/swiftlint-config": "^1.1.2", @@ -61,7 +61,7 @@ "typescript": "~4.1.5" }, "peerDependencies": { - "@capacitor/core": "^3.0.0" + "@capacitor/core": "^4.0.0" }, "prettier": "@ionic/prettier-config", "swiftlint": "@ionic/swiftlint-config", diff --git a/scripts/.gitignore b/scripts/.gitignore new file mode 100644 index 000000000..41f712968 --- /dev/null +++ b/scripts/.gitignore @@ -0,0 +1,8 @@ +# Temp dir used for publish script log output +tmp + +# Local configuration file (sdk path, etc) for Android plugins publishing +local.properties + +# Gradle cache +.gradle/ \ No newline at end of file diff --git a/scripts/android/publish-module.gradle b/scripts/android/publish-module.gradle new file mode 100644 index 000000000..0d6a0c0ce --- /dev/null +++ b/scripts/android/publish-module.gradle @@ -0,0 +1,80 @@ +apply plugin: 'maven-publish' +apply plugin: 'signing' + +def LIB_VERSION = System.getenv('PLUGIN_VERSION') +def PLUGIN_NAME = System.getenv('PLUGIN_NAME') + +task androidSourcesJar(type: Jar) { + archiveClassifier.set('sources') + if (project.plugins.findPlugin("com.android.library")) { + from android.sourceSets.main.java.srcDirs + from android.sourceSets.main.kotlin.srcDirs + } else { + from sourceSets.main.java.srcDirs + from sourceSets.main.kotlin.srcDirs + } +} + +artifacts { + archives androidSourcesJar +} + +group = 'com.capacitorjs' +version = LIB_VERSION + +afterEvaluate { + publishing { + publications { + release(MavenPublication) { + // Coordinates + groupId 'com.capacitorjs' + artifactId PLUGIN_NAME + version LIB_VERSION + + // Two artifacts, the `aar` (or `jar`) and the sources + if (project.plugins.findPlugin("com.android.library")) { + from components.release + } else { + artifact("$buildDir/libs/${project.getName()}-${version}.jar") + } + + artifact androidSourcesJar + + // POM Data + pom { + name = PLUGIN_NAME + description = 'Capacitor Android ' + PLUGIN_NAME + ' plugin native library' + url = 'https://github.com/ionic-team/capacitor-plugins' + licenses { + license { + name = 'MIT' + url = 'https://github.com/ionic-team/capacitor-plugins/blob/main/' + PLUGIN_NAME + '/LICENSE' + } + } + developers { + developer { + name = 'Ionic' + email = 'hi@ionic.io' + } + } + + // Version Control Info + scm { + connection = 'scm:git:github.com:ionic-team/capacitor-plugins.git' + developerConnection = 'scm:git:ssh://github.com:ionic-team/capacitor-plugins.git' + url = 'https://github.com/ionic-team/capacitor-plugins/tree/main' + } + } + } + } + } +} + +signing { + useInMemoryPgpKeys( + rootProject.ext["signing.keyId"], + rootProject.ext["signing.key"], + rootProject.ext["signing.password"], + ) + sign publishing.publications +} \ No newline at end of file diff --git a/scripts/android/publish-root.gradle b/scripts/android/publish-root.gradle new file mode 100644 index 000000000..c8ef1d5c5 --- /dev/null +++ b/scripts/android/publish-root.gradle @@ -0,0 +1,43 @@ +// Create variables with empty default values +ext["signing.keyId"] = '' +ext["signing.key"] = '' +ext["signing.password"] = '' +ext["ossrhUsername"] = '' +ext["ossrhPassword"] = '' +ext["sonatypeStagingProfileId"] = '' + +File globalSecretPropsFile = file('../../scripts/android/local.properties') +File secretPropsFile = project.rootProject.file('local.properties') +if (globalSecretPropsFile.exists()) { + // Read global local.properties file first if it exists (scripts/android/local.properties) + Properties p = new Properties() + new FileInputStream(globalSecretPropsFile).withCloseable { is -> p.load(is) } + p.each { name, value -> ext[name] = value } +} else if (secretPropsFile.exists()) { + // Read plugin project specific local.properties file next if it exists + Properties p = new Properties() + new FileInputStream(secretPropsFile).withCloseable { is -> p.load(is) } + p.each { name, value -> ext[name] = value } +} else { + // Use system environment variables + ext["ossrhUsername"] = System.getenv('ANDROID_OSSRH_USERNAME') + ext["ossrhPassword"] = System.getenv('ANDROID_OSSRH_PASSWORD') + ext["sonatypeStagingProfileId"] = System.getenv('ANDROID_SONATYPE_STAGING_PROFILE_ID') + ext["signing.keyId"] = System.getenv('ANDROID_SIGNING_KEY_ID') + ext["signing.key"] = System.getenv('ANDROID_SIGNING_KEY') + ext["signing.password"] = System.getenv('ANDROID_SIGNING_PASSWORD') +} + +// Set up Sonatype repository +nexusPublishing { + repositories { + sonatype { + stagingProfileId = sonatypeStagingProfileId + username = ossrhUsername + password = ossrhPassword + nexusUrl.set(uri("https://s01.oss.sonatype.org/service/local/")) + snapshotRepositoryUrl.set(uri("https://s01.oss.sonatype.org/content/repositories/snapshots/")) + } + } + repositoryDescription = 'Capacitor Android ' + System.getenv('PLUGIN_NAME') + ' plugin v' + System.getenv('PLUGIN_VERSION') +} \ No newline at end of file diff --git a/scripts/publish-android.sh b/scripts/publish-android.sh new file mode 100644 index 000000000..d789cea55 --- /dev/null +++ b/scripts/publish-android.sh @@ -0,0 +1,141 @@ +#!/usr/bin/env bash + +# The default Capacitor version(s) the plugin should depend on. Latest published in a range will be pulled by the user +DEFAULT_CAPACITOR_VERSION="[4.0,5.0)" + +publish_plugin () { + PLUGIN_PATH=$1 + if [ -d "$PLUGIN_PATH" ]; then + # Android dir path + ANDROID_PATH=$PLUGIN_PATH/android + GRADLE_FILE=$ANDROID_PATH/build.gradle + + # Only try to publish if the directory contains a package.json and android package + if test -f "$PLUGIN_PATH/package.json" && test -d "$ANDROID_PATH" && test -f "$GRADLE_FILE"; then + PLUGIN_VERSION=$(grep '"version": ' "$PLUGIN_PATH"/package.json | awk '{print $2}' | tr -d '",') + PLUGIN_NAME=$(grep '"name": ' "$PLUGIN_PATH"/package.json | awk '{print $2}' | tr -d '",') + PLUGIN_NAME=${PLUGIN_NAME#@capacitor/} + LOG_OUTPUT=./tmp/$PLUGIN_NAME.txt + + # Get latest plugin info from MavenCentral + PLUGIN_PUBLISHED_URL="https://repo1.maven.org/maven2/com/capacitorjs/$PLUGIN_NAME/maven-metadata.xml" + PLUGIN_PUBLISHED_DATA=$(curl -s $PLUGIN_PUBLISHED_URL) + PLUGIN_PUBLISHED_VERSION="$(perl -ne 'print and last if s/.*(.*)<\/latest>.*/\1/;' <<< $PLUGIN_PUBLISHED_DATA)" + + if [[ $PLUGIN_VERSION == $PLUGIN_PUBLISHED_VERSION ]]; then + printf %"s\n\n" "Duplicate: a published plugin $PLUGIN_NAME exists for version $PLUGIN_VERSION, skipping..." + else + # Make log dir if doesnt exist + mkdir -p ./tmp + + printf %"s\n" "Attempting to build and publish plugin $PLUGIN_NAME for version $PLUGIN_VERSION to production..." + + # Export ENV variables used by Gradle for the plugin + export PLUGIN_NAME + export PLUGIN_VERSION + export CAPACITOR_VERSION + export CAP_PLUGIN_PUBLISH=true + + # Build and publish + "$ANDROID_PATH"/gradlew clean build publishReleasePublicationToSonatypeRepository closeAndReleaseSonatypeStagingRepository --max-workers 1 -b "$ANDROID_PATH"/build.gradle -Pandroid.useAndroidX=true -Pandroid.enableJetifier=true > $LOG_OUTPUT 2>&1 + + if grep --quiet "BUILD SUCCESSFUL" $LOG_OUTPUT; then + printf %"s\n\n" "Success: $PLUGIN_NAME published to MavenCentral." + else + printf %"s\n\n" "Error publishing $PLUGIN_NAME, check $LOG_OUTPUT for more info! Manual publication review may be necessary at the Sonatype Repository Manager https://s01.oss.sonatype.org/" + cat $LOG_OUTPUT + exit 1 + fi + fi + else + printf %"s\n\n" "$PLUGIN_PATH does not appear to be a plugin (has no package.json file or Android package), skipping..." + fi + fi +} + +# Plugins base location +DIR=.. + +# Get latest com.capacitorjs:core XML version info +CAPACITOR_PUBLISHED_URL="https://repo1.maven.org/maven2/com/capacitorjs/core/maven-metadata.xml" +CAPACITOR_PUBLISHED_DATA=$(curl -s $CAPACITOR_PUBLISHED_URL) +CAPACITOR_PUBLISHED_VERSION="$(perl -ne 'print and last if s/.*(.*)<\/latest>.*/\1/;' <<< $CAPACITOR_PUBLISHED_DATA)" + +printf %"s\n" "The latest published Android library version of Capacitor Core is $CAPACITOR_PUBLISHED_VERSION in MavenCentral." + +# Check if github actions passing in a custom native Capacitor dependency version +if [[ $GITHUB_CAPACITOR_VERSION ]]; then + CAPACITOR_VERSION=$GITHUB_CAPACITOR_VERSION +else + CAPACITOR_VERSION=$DEFAULT_CAPACITOR_VERSION +fi + +printf %"s\n" "Publishing plugin(s) with dependency on Capacitor version $CAPACITOR_VERSION" + +# Check if github actions passing in a custom list of plugins +if [[ $GITHUB_PLUGINS ]]; then + for var in ${GITHUB_PLUGINS[@]}; do + PLUGIN_DIR="$DIR"/$var + publish_plugin $PLUGIN_DIR + done +else + # If run without .sh args, process all plugins, else run over the plugins provided as args + if [[ "$#" -eq "0" ]]; then + # Run publish task for all plugins + for f in "$DIR"/*; do + publish_plugin $f + done + else + # Run publish task for plugins provided as arguments + for var in "$@"; do + PLUGIN_DIR="$DIR"/$var + publish_plugin $PLUGIN_DIR + done + fi +fi + +# ----------------------------------------------- +# old below - for reference only + +# # Get the latest version of Capacitor +# CAPACITOR_PACKAGE_JSON="https://raw.githubusercontent.com/ionic-team/capacitor/main/android/package.json" +# CAPACITOR_VERSION=$(curl -s $CAPACITOR_PACKAGE_JSON | awk -F\" '/"version":/ {print $4}') + +# # Don't continue if there was a problem getting the latest version of Capacitor +# if [[ $CAPACITOR_VERSION ]]; then +# printf %"s\n\n" "Attempting to publish new plugins with dependency on Capacitor Version $CAPACITOR_VERSION" +# else +# printf %"s\n\n" "Error resolving latest Capacitor version from $CAPACITOR_PACKAGE_JSON" +# exit 1 +# fi + +# # Check if we need to publish a new native version of the Capacitor Android library +# if [[ "$CAPACITOR_VERSION" != "$CAPACITOR_PUBLISHED_VERSION" ]]; then +# printf %"s\n" "Publish Capacitor Core first! The latest published Android library version $CAPACITOR_PUBLISHED_VERSION in MavenCentral is outdated. There is an unpublished version $CAPACITOR_VERSION in ionic-team/capacitor." +# exit 1 +# else +# # Capacitor version in MavenCentral is up to date, continue publishing the native Capacitor Plugins +# printf %"s\n\n" "Latest native Capacitor Android library is version $CAPACITOR_PUBLISHED_VERSION and is up to date, continuing with plugin publishing..." + +# # Check if github actions passing in a custom list of plugins +# if [[ $GITHUB_PLUGINS ]]; then +# for var in ${GITHUB_PLUGINS[@]}; do +# PLUGIN_DIR="$DIR"/$var +# publish_plugin $PLUGIN_DIR +# done +# else +# # If run without .sh args, process all plugins, else run over the plugins provided as args +# if [[ "$#" -eq "0" ]]; then +# # Run publish task for all plugins +# for f in "$DIR"/*; do +# publish_plugin $f +# done +# else +# # Run publish task for plugins provided as arguments +# for var in "$@"; do +# PLUGIN_DIR="$DIR"/$var +# publish_plugin $PLUGIN_DIR +# done +# fi +# fi +# fi \ No newline at end of file diff --git a/share/CHANGELOG.md b/share/CHANGELOG.md index 42347be84..86d7fc008 100644 --- a/share/CHANGELOG.md +++ b/share/CHANGELOG.md @@ -3,6 +3,120 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.1.0](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/share@1.1.2...@capacitor/share@4.1.0) (2022-11-16) + + +### Features + +* **share:** Support for sharing multiple files ([#1267](https://github.com/ionic-team/capacitor-plugins/issues/1267)) ([b342061](https://github.com/ionic-team/capacitor-plugins/commit/b342061b41e26761f3d47b5dad06bd2e4f151216)) + + + +## 4.0.1 (2022-07-28) + + + +# 4.0.0 (2022-07-27) + + +### Bug Fixes + +* **share:** Prevent crash on no shareable files ([#1088](https://github.com/ionic-team/capacitor-plugins/issues/1088)) ([dc67e7b](https://github.com/ionic-team/capacitor-plugins/commit/dc67e7b96daa99e2d020b76005e37d93b610bbf2)) + + + +# 4.0.0-beta.2 (2022-07-08) + + + +# 4.0.0-beta.0 (2022-06-27) + + +### Bug Fixes + +* **share:** avoid crash when targeting SDK 31 ([#913](https://github.com/ionic-team/capacitor-plugins/issues/913)) ([275da5f](https://github.com/ionic-team/capacitor-plugins/commit/275da5fc23cf0ef173276d9027f8c5ffdb8a5432)) + + +### Features + +* set targetSDK default value to 31 ([#824](https://github.com/ionic-team/capacitor-plugins/issues/824)) ([3ee10de](https://github.com/ionic-team/capacitor-plugins/commit/3ee10de98067984c1a4e75295d001c5a895c47f4)) +* set targetSDK default value to 32 ([#970](https://github.com/ionic-team/capacitor-plugins/issues/970)) ([fa70d96](https://github.com/ionic-team/capacitor-plugins/commit/fa70d96f141af751aae53ceb5642c46b204f5958)) +* Upgrade gradle to 7.4 ([#826](https://github.com/ionic-team/capacitor-plugins/issues/826)) ([5db0906](https://github.com/ionic-team/capacitor-plugins/commit/5db0906f6264287c4f8e69dbaecf19d4d387824b)) +* Use java 11 ([#910](https://github.com/ionic-team/capacitor-plugins/issues/910)) ([5acb2a2](https://github.com/ionic-team/capacitor-plugins/commit/5acb2a288a413492b163e4e97da46a085d9e4be0)) + + + + + +## [4.0.1](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0...4.0.1) (2022-07-28) + +**Note:** Version bump only for package @capacitor/share + + + + + +# [4.0.0](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0-beta.2...4.0.0) (2022-07-27) + + +### Bug Fixes + +* **share:** Prevent crash on no shareable files ([#1088](https://github.com/ionic-team/capacitor-plugins/issues/1088)) ([dc67e7b](https://github.com/ionic-team/capacitor-plugins/commit/dc67e7b96daa99e2d020b76005e37d93b610bbf2)) + + + + + +# [4.0.0-beta.2](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0-beta.0...4.0.0-beta.2) (2022-07-08) + +**Note:** Version bump only for package @capacitor/share + + + + + +# 4.0.0-beta.0 (2022-06-27) + + +### Bug Fixes + +* **share:** avoid crash when targeting SDK 31 ([#913](https://github.com/ionic-team/capacitor-plugins/issues/913)) ([275da5f](https://github.com/ionic-team/capacitor-plugins/commit/275da5fc23cf0ef173276d9027f8c5ffdb8a5432)) +* add es2017 lib to tsconfig ([#180](https://github.com/ionic-team/capacitor-plugins/issues/180)) ([2c3776c](https://github.com/ionic-team/capacitor-plugins/commit/2c3776c38ca025c5ee965dec10ccf1cdb6c02e2f)) +* correct addListeners links ([#655](https://github.com/ionic-team/capacitor-plugins/issues/655)) ([f9871e7](https://github.com/ionic-team/capacitor-plugins/commit/f9871e7bd53478addb21155e148829f550c0e457)) +* inline source code in esm map files ([#760](https://github.com/ionic-team/capacitor-plugins/issues/760)) ([a960489](https://github.com/ionic-team/capacitor-plugins/commit/a960489a19db0182b90d187a50deff9dfbe51038)) +* remove postpublish scripts ([#656](https://github.com/ionic-team/capacitor-plugins/issues/656)) ([ed6ac49](https://github.com/ionic-team/capacitor-plugins/commit/ed6ac499ebf4a47525071ccbfc36c27503e11f60)) +* **share:** Avoid SecurityError on Android 10 file share ([#63](https://github.com/ionic-team/capacitor-plugins/issues/63)) ([b6a8191](https://github.com/ionic-team/capacitor-plugins/commit/b6a819115c84fe533a97bad9f8784499c492ddcd)) +* **share:** Prevent share if sharing in progress ([#489](https://github.com/ionic-team/capacitor-plugins/issues/489)) ([3479783](https://github.com/ionic-team/capacitor-plugins/commit/34797837363588f4511403e39017bf6b656685cb)) +* **share:** set type to */* if no mine type can be found ([#324](https://github.com/ionic-team/capacitor-plugins/issues/324)) ([40d4baa](https://github.com/ionic-team/capacitor-plugins/commit/40d4baa8b89e55b094ee568daecf8c63a53fc7cb)) +* support deprecated types from Capacitor 2 ([#139](https://github.com/ionic-team/capacitor-plugins/issues/139)) ([2d7127a](https://github.com/ionic-team/capacitor-plugins/commit/2d7127a488e26f0287951921a6db47c49d817336)) + + +### Features + +* add commonjs output format ([#179](https://github.com/ionic-team/capacitor-plugins/issues/179)) ([8e9e098](https://github.com/ionic-team/capacitor-plugins/commit/8e9e09862064b3f6771d7facbc4008e995d9b463)) +* set targetSDK default value to 31 ([#824](https://github.com/ionic-team/capacitor-plugins/issues/824)) ([3ee10de](https://github.com/ionic-team/capacitor-plugins/commit/3ee10de98067984c1a4e75295d001c5a895c47f4)) +* set targetSDK default value to 32 ([#970](https://github.com/ionic-team/capacitor-plugins/issues/970)) ([fa70d96](https://github.com/ionic-team/capacitor-plugins/commit/fa70d96f141af751aae53ceb5642c46b204f5958)) +* Share plugin ([#39](https://github.com/ionic-team/capacitor-plugins/issues/39)) ([9076c8e](https://github.com/ionic-team/capacitor-plugins/commit/9076c8e6b83b80514d23c809035fd7579b2e607a)) +* Upgrade gradle to 7.4 ([#826](https://github.com/ionic-team/capacitor-plugins/issues/826)) ([5db0906](https://github.com/ionic-team/capacitor-plugins/commit/5db0906f6264287c4f8e69dbaecf19d4d387824b)) +* Use java 11 ([#910](https://github.com/ionic-team/capacitor-plugins/issues/910)) ([5acb2a2](https://github.com/ionic-team/capacitor-plugins/commit/5acb2a288a413492b163e4e97da46a085d9e4be0)) +* **android:** implements Activity Result API changes for permissions and activity results ([#222](https://github.com/ionic-team/capacitor-plugins/issues/222)) ([f671b9f](https://github.com/ionic-team/capacitor-plugins/commit/f671b9f4b472806ef43db6dcf302d4503cf1828c)) +* **share:** Add canShare method to check availability ([#748](https://github.com/ionic-team/capacitor-plugins/issues/748)) ([3883d82](https://github.com/ionic-team/capacitor-plugins/commit/3883d82952a4453797b86c562af27f9b05e82a18)) + + + + + +## [1.1.2](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/share@1.1.1...@capacitor/share@1.1.2) (2022-03-03) + + +### Bug Fixes + +* **share:** correct whatsapp file sharing ([#816](https://github.com/ionic-team/capacitor-plugins/issues/816)) ([18b10c4](https://github.com/ionic-team/capacitor-plugins/commit/18b10c493e26a6b62031c3bfb57e1ffbbf926c41)) + + + + + ## [1.1.1](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/share@1.1.0...@capacitor/share@1.1.1) (2022-01-19) diff --git a/share/CapacitorShare.podspec b/share/CapacitorShare.podspec index 592f92178..53543d6dd 100644 --- a/share/CapacitorShare.podspec +++ b/share/CapacitorShare.podspec @@ -11,7 +11,7 @@ Pod::Spec.new do |s| s.author = package['author'] s.source = { :git => 'https://github.com/ionic-team/capacitor-plugins.git', :tag => package['name'] + '@' + package['version'] } s.source_files = 'ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}', 'share/ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}' - s.ios.deployment_target = '12.0' + s.ios.deployment_target = '13.0' s.dependency 'Capacitor' s.swift_version = '5.1' end diff --git a/share/README.md b/share/README.md index 06fb7ae11..e57930f2c 100644 --- a/share/README.md +++ b/share/README.md @@ -11,6 +11,9 @@ API](https://web.dev/web-share/)), though web support is currently spotty. npm install @capacitor/share npx cap sync ``` +## Android + +By default, Capacitor apps only allow to share files from caches folder. To make other Android folders shareable, they have to be added in `android/app/src/main/res/xml/file_paths.xml` file. Check the Specifying Available Files section in [FileProvider docs](https://developer.android.com/reference/androidx/core/content/FileProvider) for the available locations. ## Example @@ -93,11 +96,12 @@ Show a Share modal for sharing content with other apps #### ShareOptions -| Prop | Type | Description | Since | -| ----------------- | ------------------- | -------------------------------------------------------------------------- | ----- | -| **`title`** | string | Set a title for any message. This will be the subject if sharing to email | 1.0.0 | -| **`text`** | string | Set some text to share | 1.0.0 | -| **`url`** | string | Set a URL to share, can be http, https or file:// URL | 1.0.0 | -| **`dialogTitle`** | string | Set a title for the share modal. This option is only supported on Android. | 1.0.0 | +| Prop | Type | Description | Since | +| ----------------- | --------------------- | ----------------------------------------------------------------------------------- | ----- | +| **`title`** | string | Set a title for any message. This will be the subject if sharing to email | 1.0.0 | +| **`text`** | string | Set some text to share | 1.0.0 | +| **`url`** | string | Set a URL to share, can be http, https or file:// URL | 1.0.0 | +| **`files`** | string[] | Array of file:// URLs of the files to be shared. Only supported on iOS and Android. | 4.1.0 | +| **`dialogTitle`** | string | Set a title for the share modal. This option is only supported on Android. | 1.0.0 | diff --git a/share/android/build.gradle b/share/android/build.gradle index 4f5769141..502908223 100644 --- a/share/android/build.gradle +++ b/share/android/build.gradle @@ -1,28 +1,40 @@ ext { - junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.1' - androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.2.0' - androidxCoreVersion = project.hasProperty('androidxCoreVersion') ? rootProject.ext.androidxCoreVersion : '1.3.2' - androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.1.2' - androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.3.0' + capacitorVersion = System.getenv('CAPACITOR_VERSION') + junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.2' + androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.4.2' + androidxCoreVersion = project.hasProperty('androidxCoreVersion') ? rootProject.ext.androidxCoreVersion : '1.8.0' + androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.1.3' + androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.4.0' } buildscript { repositories { google() mavenCentral() + maven { + url "https://plugins.gradle.org/m2/" + } } dependencies { - classpath 'com.android.tools.build:gradle:4.2.1' + classpath 'com.android.tools.build:gradle:7.2.1' + if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + classpath 'io.github.gradle-nexus:publish-plugin:1.1.0' + } } } apply plugin: 'com.android.library' +if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + apply plugin: 'io.github.gradle-nexus.publish-plugin' + apply from: file('../../scripts/android/publish-root.gradle') + apply from: file('../../scripts/android/publish-module.gradle') +} android { - compileSdkVersion project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 30 + compileSdkVersion project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 32 defaultConfig { - minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 21 - targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 30 + minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 22 + targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 32 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" @@ -37,21 +49,26 @@ android { abortOnError false } compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility JavaVersion.VERSION_11 + targetCompatibility JavaVersion.VERSION_11 } } repositories { google() mavenCentral() - jcenter() } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation project(':capacitor-android') + + if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + implementation "com.capacitorjs:core:$capacitorVersion" + } else { + implementation project(':capacitor-android') + } + implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion" implementation "androidx.core:core:$androidxCoreVersion" testImplementation "junit:junit:$junitVersion" diff --git a/share/android/gradle/wrapper/gradle-wrapper.jar b/share/android/gradle/wrapper/gradle-wrapper.jar index e708b1c02..41d9927a4 100644 Binary files a/share/android/gradle/wrapper/gradle-wrapper.jar and b/share/android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/share/android/gradle/wrapper/gradle-wrapper.properties b/share/android/gradle/wrapper/gradle-wrapper.properties index 3c4101c3e..92f06b50f 100644 --- a/share/android/gradle/wrapper/gradle-wrapper.properties +++ b/share/android/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/share/android/gradlew b/share/android/gradlew index 4f906e0c8..1b6c78733 100755 --- a/share/android/gradlew +++ b/share/android/gradlew @@ -1,7 +1,7 @@ -#!/usr/bin/env sh +#!/bin/sh # -# Copyright 2015 the original author or authors. +# Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,67 +17,101 @@ # ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` +APP_BASE_NAME=${0##*/} # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar @@ -87,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -98,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" + JAVACMD=java which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the @@ -106,80 +140,95 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=`expr $i + 1` + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" diff --git a/share/android/src/main/java/com/capacitorjs/plugins/share/SharePlugin.java b/share/android/src/main/java/com/capacitorjs/plugins/share/SharePlugin.java index edef5ff2d..19b3009e5 100644 --- a/share/android/src/main/java/com/capacitorjs/plugins/share/SharePlugin.java +++ b/share/android/src/main/java/com/capacitorjs/plugins/share/SharePlugin.java @@ -8,6 +8,7 @@ import android.webkit.MimeTypeMap; import androidx.activity.result.ActivityResult; import androidx.core.content.FileProvider; +import com.getcapacitor.JSArray; import com.getcapacitor.JSObject; import com.getcapacitor.Plugin; import com.getcapacitor.PluginCall; @@ -15,6 +16,9 @@ import com.getcapacitor.annotation.ActivityCallback; import com.getcapacitor.annotation.CapacitorPlugin; import java.io.File; +import java.util.ArrayList; +import java.util.List; +import org.json.JSONException; @CapacitorPlugin(name = "Share") public class SharePlugin extends Plugin { @@ -26,16 +30,14 @@ public class SharePlugin extends Plugin { @Override public void load() { - if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) { - broadcastReceiver = - new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - chosenComponent = intent.getParcelableExtra(Intent.EXTRA_CHOSEN_COMPONENT); - } - }; - getActivity().registerReceiver(broadcastReceiver, new IntentFilter(Intent.EXTRA_CHOSEN_COMPONENT)); - } + broadcastReceiver = + new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + chosenComponent = intent.getParcelableExtra(Intent.EXTRA_CHOSEN_COMPONENT); + } + }; + getActivity().registerReceiver(broadcastReceiver, new IntentFilter(Intent.EXTRA_CHOSEN_COMPONENT)); } @ActivityCallback @@ -63,10 +65,11 @@ public void share(PluginCall call) { String title = call.getString("title", ""); String text = call.getString("text"); String url = call.getString("url"); + JSArray files = call.getArray("files"); String dialogTitle = call.getString("dialogTitle", "Share"); - if (text == null && url == null) { - call.reject("Must provide a URL or Message"); + if (text == null && url == null && (files == null || files.length() == 0)) { + call.reject("Must provide a URL or Message or files"); return; } @@ -75,7 +78,7 @@ public void share(PluginCall call) { return; } - Intent intent = new Intent(Intent.ACTION_SEND); + Intent intent = new Intent(files != null && files.length() > 1 ? Intent.ACTION_SEND_MULTIPLE : Intent.ACTION_SEND); if (text != null) { // If they supplied both fields, concat them @@ -88,41 +91,27 @@ public void share(PluginCall call) { intent.putExtra(Intent.EXTRA_TEXT, url); intent.setTypeAndNormalize("text/plain"); } else if (url != null && isFileUrl(url)) { - String type = getMimeType(url); - if (type == null) { - type = "*/*"; - } - intent.setType(type); - Uri fileUrl = FileProvider.getUriForFile( - getActivity(), - getContext().getPackageName() + ".fileprovider", - new File(Uri.parse(url).getPath()) - ); - intent.putExtra(Intent.EXTRA_STREAM, fileUrl); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { - intent.setData(fileUrl); - } - intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + JSArray filesArray = new JSArray(); + filesArray.put(url); + shareFiles(filesArray, intent, call); } if (title != null) { intent.putExtra(Intent.EXTRA_SUBJECT, title); } - Intent chooser = null; - if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) { - // requestCode parameter is not used. Providing 0 - PendingIntent pi = PendingIntent.getBroadcast( - getContext(), - 0, - new Intent(Intent.EXTRA_CHOSEN_COMPONENT), - PendingIntent.FLAG_UPDATE_CURRENT - ); - chooser = Intent.createChooser(intent, dialogTitle, pi.getIntentSender()); - chosenComponent = null; - } else { - chooser = Intent.createChooser(intent, dialogTitle); + if (files != null && files.length() != 0) { + shareFiles(files, intent, call); + } + int flags = PendingIntent.FLAG_UPDATE_CURRENT; + if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + flags = flags | PendingIntent.FLAG_MUTABLE; } + + // requestCode parameter is not used. Providing 0 + PendingIntent pi = PendingIntent.getBroadcast(getContext(), 0, new Intent(Intent.EXTRA_CHOSEN_COMPONENT), flags); + Intent chooser = Intent.createChooser(intent, dialogTitle, pi.getIntentSender()); + chosenComponent = null; chooser.addCategory(Intent.CATEGORY_DEFAULT); stopped = false; isPresenting = true; @@ -132,6 +121,46 @@ public void share(PluginCall call) { } } + private void shareFiles(JSArray files, Intent intent, PluginCall call) { + List filesList; + ArrayList fileUris = new ArrayList<>(); + try { + filesList = files.toList(); + for (int i = 0; i < filesList.size(); i++) { + String file = (String) filesList.get(i); + if (isFileUrl(file)) { + String type = getMimeType(file); + if (type == null || filesList.size() > 1) { + type = "*/*"; + } + intent.setType(type); + + Uri fileUrl = FileProvider.getUriForFile( + getActivity(), + getContext().getPackageName() + ".fileprovider", + new File(Uri.parse(file).getPath()) + ); + fileUris.add(fileUrl); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && filesList.size() == 1) { + intent.setDataAndType(fileUrl, type); + intent.putExtra(Intent.EXTRA_STREAM, fileUrl); + } + } else { + call.reject("only file urls are supported"); + return; + } + } + if (fileUris.size() > 1) { + intent.putExtra(Intent.EXTRA_STREAM, fileUris); + } + intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + } catch (Exception ex) { + call.reject(ex.getLocalizedMessage()); + return; + } + } + @Override protected void handleOnDestroy() { if (broadcastReceiver != null) { diff --git a/share/ios/Plugin.xcodeproj/project.pbxproj b/share/ios/Plugin.xcodeproj/project.pbxproj index 3c6daeb3b..6da13a4fd 100644 --- a/share/ios/Plugin.xcodeproj/project.pbxproj +++ b/share/ios/Plugin.xcodeproj/project.pbxproj @@ -382,7 +382,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -442,7 +442,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; @@ -465,12 +465,13 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Plugin/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks $(FRAMEWORK_SEARCH_PATHS)\n$(FRAMEWORK_SEARCH_PATHS)\n$(FRAMEWORK_SEARCH_PATHS)"; ONLY_ACTIVE_ARCH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.getcapacitor.Plugin; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; + SUPPORTS_MACCATALYST = NO; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -490,12 +491,13 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Plugin/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks $(FRAMEWORK_SEARCH_PATHS)"; ONLY_ACTIVE_ARCH = NO; PRODUCT_BUNDLE_IDENTIFIER = com.getcapacitor.Plugin; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; + SUPPORTS_MACCATALYST = NO; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; diff --git a/share/ios/Plugin/SharePlugin.swift b/share/ios/Plugin/SharePlugin.swift index ff9950ab9..4ce8446dd 100644 --- a/share/ios/Plugin/SharePlugin.swift +++ b/share/ios/Plugin/SharePlugin.swift @@ -23,8 +23,16 @@ public class SharePlugin: CAPPlugin { let title = call.getString("title") + if let files = call.getArray("files") { + files.forEach { file in + if let url = file as? String, let fileUrl = URL(string: url) { + items.append(fileUrl) + } + } + } + if items.count == 0 { - call.reject("Must provide at least url or text") + call.reject("Must provide at least url, text or files") return } diff --git a/share/ios/Podfile b/share/ios/Podfile index 54a00c161..dee40960f 100644 --- a/share/ios/Podfile +++ b/share/ios/Podfile @@ -1,4 +1,4 @@ -platform :ios, '12.0' +platform :ios, '13.0' def capacitor_pods # Comment the next line if you're not using Swift and don't want to use dynamic frameworks diff --git a/share/package.json b/share/package.json index 5c8f53ac3..9113b1f31 100644 --- a/share/package.json +++ b/share/package.json @@ -1,6 +1,6 @@ { "name": "@capacitor/share", - "version": "1.1.1", + "version": "4.1.0", "description": "The Share API provides methods for sharing content in any sharing-enabled apps the user may have installed.", "main": "dist/plugin.cjs.js", "module": "dist/esm/index.js", @@ -29,7 +29,7 @@ ], "scripts": { "verify": "npm run verify:ios && npm run verify:android && npm run verify:web", - "verify:ios": "cd ios && pod install && xcodebuild -workspace Plugin.xcworkspace -scheme Plugin && cd ..", + "verify:ios": "cd ios && pod install && xcodebuild -workspace Plugin.xcworkspace -scheme Plugin -destination generic/platform=iOS && cd ..", "verify:android": "cd android && ./gradlew clean build test && cd ..", "verify:web": "npm run build", "lint": "npm run eslint && npm run prettier -- --check && npm run swiftlint -- lint", @@ -45,10 +45,10 @@ "publish:cocoapod": "pod trunk push ./CapacitorShare.podspec --allow-warnings" }, "devDependencies": { - "@capacitor/android": "^3.0.0", - "@capacitor/core": "^3.0.0", - "@capacitor/docgen": "0.0.18", - "@capacitor/ios": "^3.0.0", + "@capacitor/android": "^4.0.0", + "@capacitor/core": "^4.0.0", + "@capacitor/docgen": "0.2.0", + "@capacitor/ios": "^4.0.0", "@ionic/eslint-config": "^0.3.0", "@ionic/prettier-config": "~1.0.1", "@ionic/swiftlint-config": "^1.1.2", @@ -61,7 +61,7 @@ "typescript": "~4.1.5" }, "peerDependencies": { - "@capacitor/core": "^3.0.0" + "@capacitor/core": "^4.0.0" }, "prettier": "@ionic/prettier-config", "swiftlint": "@ionic/swiftlint-config", diff --git a/share/src/definitions.ts b/share/src/definitions.ts index d616d06b9..48779e43a 100644 --- a/share/src/definitions.ts +++ b/share/src/definitions.ts @@ -21,6 +21,14 @@ export interface ShareOptions { */ url?: string; + /** + * Array of file:// URLs of the files to be shared. + * Only supported on iOS and Android. + * + * @since 4.1.0 + */ + files?: string[]; + /** * Set a title for the share modal. * This option is only supported on Android. diff --git a/splash-screen/CHANGELOG.md b/splash-screen/CHANGELOG.md index 22026d56e..2c29a853c 100644 --- a/splash-screen/CHANGELOG.md +++ b/splash-screen/CHANGELOG.md @@ -3,6 +3,104 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [4.1.2](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/splash-screen@4.1.1...@capacitor/splash-screen@4.1.2) (2022-11-16) + + +### Bug Fixes + +* **splash-screen:** Remove extension from storyboard name ([#1281](https://github.com/ionic-team/capacitor-plugins/issues/1281)) ([86ecc4f](https://github.com/ionic-team/capacitor-plugins/commit/86ecc4f0c45799b2a5a02700c18a3d5f0de00615)) + + + + + +## [4.1.1](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/splash-screen@4.1.0...@capacitor/splash-screen@4.1.1) (2022-10-21) + +**Note:** Version bump only for package @capacitor/splash-screen + + + + + +# [4.1.0](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/splash-screen@1.2.2...@capacitor/splash-screen@4.1.0) (2022-09-29) + + + + + +## [4.0.1](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0...4.0.1) (2022-07-28) + +**Note:** Version bump only for package @capacitor/splash-screen + + + + + +# [4.0.0](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0-beta.2...4.0.0) (2022-07-27) + + +### Features + +* **splash-screen:** Use Android 12 Splash Screen API ([#1011](https://github.com/ionic-team/capacitor-plugins/issues/1011)) ([79185ad](https://github.com/ionic-team/capacitor-plugins/commit/79185adf76bc4ff4bae1be5ec5b5881cfbe748b1)) + + + + + +# [4.0.0-beta.2](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0-beta.0...4.0.0-beta.2) (2022-07-08) + +**Note:** Version bump only for package @capacitor/splash-screen + + + + + +# 4.0.0-beta.0 (2022-06-27) + + +### Bug Fixes + +* **splash-screen:** avoid conditional downcast warning ([#776](https://github.com/ionic-team/capacitor-plugins/issues/776)) ([87ed912](https://github.com/ionic-team/capacitor-plugins/commit/87ed9128f43f0be498601f0ba89cadeba7a339b4)) +* **splash-screen:** pick first window when there is no key window ([#730](https://github.com/ionic-team/capacitor-plugins/issues/730)) ([0e335ad](https://github.com/ionic-team/capacitor-plugins/commit/0e335ad386da8ceadfdfaa3be982840547fc41b6)) +* **splash-screen:** Use Locale.ROOT on toLowerCase ([#813](https://github.com/ionic-team/capacitor-plugins/issues/813)) ([ecc55e1](https://github.com/ionic-team/capacitor-plugins/commit/ecc55e172acfe066977a4aac5018a55beef64f53)) +* add es2017 lib to tsconfig ([#180](https://github.com/ionic-team/capacitor-plugins/issues/180)) ([2c3776c](https://github.com/ionic-team/capacitor-plugins/commit/2c3776c38ca025c5ee965dec10ccf1cdb6c02e2f)) +* correct addListeners links ([#655](https://github.com/ionic-team/capacitor-plugins/issues/655)) ([f9871e7](https://github.com/ionic-team/capacitor-plugins/commit/f9871e7bd53478addb21155e148829f550c0e457)) +* export all TS definitions ([6cd2996](https://github.com/ionic-team/capacitor-plugins/commit/6cd299660fdeb27382ec7f45f0b3a55224cd0ad1)) +* inline source code in esm map files ([#760](https://github.com/ionic-team/capacitor-plugins/issues/760)) ([a960489](https://github.com/ionic-team/capacitor-plugins/commit/a960489a19db0182b90d187a50deff9dfbe51038)) +* remove postpublish scripts ([#656](https://github.com/ionic-team/capacitor-plugins/issues/656)) ([ed6ac49](https://github.com/ionic-team/capacitor-plugins/commit/ed6ac499ebf4a47525071ccbfc36c27503e11f60)) +* **splash-screen:** launchAutoHide not working on iOS ([#319](https://github.com/ionic-team/capacitor-plugins/issues/319)) ([2a83fcb](https://github.com/ionic-team/capacitor-plugins/commit/2a83fcb536cdfc5b601f363212353201de40ca5b)) +* **splash-screen:** Use configured storyboard instead of hardcoded value ([#548](https://github.com/ionic-team/capacitor-plugins/issues/548)) ([67dd67f](https://github.com/ionic-team/capacitor-plugins/commit/67dd67fc443ea5494e8482fd4346c5275a42841b)) +* support deprecated types from Capacitor 2 ([#139](https://github.com/ionic-team/capacitor-plugins/issues/139)) ([2d7127a](https://github.com/ionic-team/capacitor-plugins/commit/2d7127a488e26f0287951921a6db47c49d817336)) + + +### Features + +* add commonjs output format ([#179](https://github.com/ionic-team/capacitor-plugins/issues/179)) ([8e9e098](https://github.com/ionic-team/capacitor-plugins/commit/8e9e09862064b3f6771d7facbc4008e995d9b463)) +* set targetSDK default value to 31 ([#824](https://github.com/ionic-team/capacitor-plugins/issues/824)) ([3ee10de](https://github.com/ionic-team/capacitor-plugins/commit/3ee10de98067984c1a4e75295d001c5a895c47f4)) +* set targetSDK default value to 32 ([#970](https://github.com/ionic-team/capacitor-plugins/issues/970)) ([fa70d96](https://github.com/ionic-team/capacitor-plugins/commit/fa70d96f141af751aae53ceb5642c46b204f5958)) +* SplashScreen plugin ([#149](https://github.com/ionic-team/capacitor-plugins/issues/149)) ([c5f44be](https://github.com/ionic-team/capacitor-plugins/commit/c5f44bee46d06bd9a2623cd907862633ee5331eb)) +* Upgrade gradle to 7.4 ([#826](https://github.com/ionic-team/capacitor-plugins/issues/826)) ([5db0906](https://github.com/ionic-team/capacitor-plugins/commit/5db0906f6264287c4f8e69dbaecf19d4d387824b)) +* Use java 11 ([#910](https://github.com/ionic-team/capacitor-plugins/issues/910)) ([5acb2a2](https://github.com/ionic-team/capacitor-plugins/commit/5acb2a288a413492b163e4e97da46a085d9e4be0)) +* **splash-screen:** add useDialog and layoutName options for Android ([#519](https://github.com/ionic-team/capacitor-plugins/issues/519)) ([f48733f](https://github.com/ionic-team/capacitor-plugins/commit/f48733fd42a49d718a70c2fd36d28355a64b7a88)) +* **splash-screen:** Make splash work in apps that use scenes ([#631](https://github.com/ionic-team/capacitor-plugins/issues/631)) ([cf0d214](https://github.com/ionic-team/capacitor-plugins/commit/cf0d2143c225336984a6bc8fa7ef814a18b02bd1)) +* **splash-screen:** Use Launch Storyboard for splash ([#516](https://github.com/ionic-team/capacitor-plugins/issues/516)) ([0292dab](https://github.com/ionic-team/capacitor-plugins/commit/0292dab65ac9c0f81e632eaf711b13b051f4da92)) + + + + + +## [1.2.2](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/splash-screen@1.2.1...@capacitor/splash-screen@1.2.2) (2022-02-10) + + +### Bug Fixes + +* **splash-screen:** avoid conditional downcast warning ([#776](https://github.com/ionic-team/capacitor-plugins/issues/776)) ([87ed912](https://github.com/ionic-team/capacitor-plugins/commit/87ed9128f43f0be498601f0ba89cadeba7a339b4)) +* **splash-screen:** Use Locale.ROOT on toLowerCase ([#813](https://github.com/ionic-team/capacitor-plugins/issues/813)) ([ecc55e1](https://github.com/ionic-team/capacitor-plugins/commit/ecc55e172acfe066977a4aac5018a55beef64f53)) + + + + + ## [1.2.1](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/splash-screen@1.2.0...@capacitor/splash-screen@1.2.1) (2022-01-19) diff --git a/splash-screen/CapacitorSplashScreen.podspec b/splash-screen/CapacitorSplashScreen.podspec index 3c7cc22b9..a86dda7ff 100644 --- a/splash-screen/CapacitorSplashScreen.podspec +++ b/splash-screen/CapacitorSplashScreen.podspec @@ -11,7 +11,7 @@ Pod::Spec.new do |s| s.author = package['author'] s.source = { :git => 'https://github.com/ionic-team/capacitor-plugins.git', :tag => package['name'] + '@' + package['version'] } s.source_files = 'ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}', 'splash-screen/ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}' - s.ios.deployment_target = '12.0' + s.ios.deployment_target = '13.0' s.dependency 'Capacitor' s.swift_version = '5.1' end diff --git a/splash-screen/README.md b/splash-screen/README.md index eb6ede7b8..375e857ea 100644 --- a/splash-screen/README.md +++ b/splash-screen/README.md @@ -19,13 +19,13 @@ await SplashScreen.hide(); // Show the splash for an indefinite amount of time: await SplashScreen.show({ - autoHide: false + autoHide: false, }); // Show the splash for two seconds and then automatically hide it: await SplashScreen.show({ showDuration: 2000, - autoHide: true + autoHide: true, }); ``` @@ -37,7 +37,6 @@ If you want to be sure the splash screen never disappears before your app is rea If, instead, you want to show the splash screen for a fixed amount of time, set `launchShowDuration` in your [Capacitor configuration file](https://capacitorjs.com/docs/config). - ## Background Color In certain conditions, especially if the splash screen does not fully cover the device screen, it might happen that the app screen is visible around the corners (due to transparency). Instead of showing a transparent color, you can set a `backgroundColor` to cover those areas. @@ -51,6 +50,7 @@ If you want to show a spinner on top of the splash screen, set `showSpinner` to You can customize the appearance of the spinner with the following configuration. For Android, `androidSpinnerStyle` has the following options: + - `horizontal` - `small` - `large` (default) @@ -59,6 +59,7 @@ For Android, `androidSpinnerStyle` has the following options: - `largeInverse` For iOS, `iosSpinnerStyle` has the following options: + - `large` (default) - `small` @@ -71,21 +72,21 @@ To set the color of the spinner use `spinnerColor`, values are either `#RRGGBB` These config values are available: -| Prop | Type | Description | Default | Since | -| ------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------- | ----- | -| **`launchShowDuration`** | number | How long to show the launch splash screen when autoHide is enabled (in ms) | 500 | 1.0.0 | -| **`launchAutoHide`** | boolean | Whether to auto hide the splash after launchShowDuration. | true | 1.0.0 | -| **`backgroundColor`** | string | Color of the background of the Splash Screen in hex format, #RRGGBB or #RRGGBBAA. Doesn't work if `useDialog` is true. | | 1.0.0 | -| **`androidSplashResourceName`** | string | Name of the resource to be used as Splash Screen. Only available on Android. | splash | 1.0.0 | -| **`androidScaleType`** | 'CENTER' \| 'CENTER_CROP' \| 'CENTER_INSIDE' \| 'FIT_CENTER' \| 'FIT_END' \| 'FIT_START' \| 'FIT_XY' \| 'MATRIX' | The [ImageView.ScaleType](https://developer.android.com/reference/android/widget/ImageView.ScaleType) used to scale the Splash Screen image. Doesn't work if `useDialog` is true. Only available on Android. | FIT_XY | 1.0.0 | -| **`showSpinner`** | boolean | Show a loading spinner on the Splash Screen. Doesn't work if `useDialog` is true. | | 1.0.0 | -| **`androidSpinnerStyle`** | 'horizontal' \| 'small' \| 'large' \| 'inverse' \| 'smallInverse' \| 'largeInverse' | Style of the Android spinner. Doesn't work if `useDialog` is true. | large | 1.0.0 | -| **`iosSpinnerStyle`** | 'small' \| 'large' | Style of the iOS spinner. Doesn't work if `useDialog` is true. Only available on iOS. | large | 1.0.0 | -| **`spinnerColor`** | string | Color of the spinner in hex format, #RRGGBB or #RRGGBBAA. Doesn't work if `useDialog` is true. | | 1.0.0 | -| **`splashFullScreen`** | boolean | Hide the status bar on the Splash Screen. Only available on Android. | | 1.0.0 | -| **`splashImmersive`** | boolean | Hide the status bar and the software navigation buttons on the Splash Screen. Only available on Android. | | 1.0.0 | -| **`layoutName`** | string | If `useDialog` is set to true, configure the Dialog layout. If `useDialog` is not set or false, use a layout instead of the ImageView. Only available on Android. | | 1.1.0 | -| **`useDialog`** | boolean | Use a Dialog instead of an ImageView. If `layoutName` is not configured, it will use a layout that uses the splash image as background. Only available on Android. | | 1.1.0 | +| Prop | Type | Description | Default | Since | +| ------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------- | ----- | +| **`launchShowDuration`** | number | How long to show the launch splash screen when autoHide is enabled (in ms) | 500 | 1.0.0 | +| **`launchAutoHide`** | boolean | Whether to auto hide the splash after launchShowDuration. | true | 1.0.0 | +| **`backgroundColor`** | string | Color of the background of the Splash Screen in hex format, #RRGGBB or #RRGGBBAA. Doesn't work if `useDialog` is true or on launch when using the Android 12 API. | | 1.0.0 | +| **`androidSplashResourceName`** | string | Name of the resource to be used as Splash Screen. Doesn't work on launch when using the Android 12 API. Only available on Android. | splash | 1.0.0 | +| **`androidScaleType`** | 'CENTER' \| 'CENTER_CROP' \| 'CENTER_INSIDE' \| 'FIT_CENTER' \| 'FIT_END' \| 'FIT_START' \| 'FIT_XY' \| 'MATRIX' | The [ImageView.ScaleType](https://developer.android.com/reference/android/widget/ImageView.ScaleType) used to scale the Splash Screen image. Doesn't work if `useDialog` is true or on launch when using the Android 12 API. Only available on Android. | FIT_XY | 1.0.0 | +| **`showSpinner`** | boolean | Show a loading spinner on the Splash Screen. Doesn't work if `useDialog` is true or on launch when using the Android 12 API. | | 1.0.0 | +| **`androidSpinnerStyle`** | 'horizontal' \| 'small' \| 'large' \| 'inverse' \| 'smallInverse' \| 'largeInverse' | Style of the Android spinner. Doesn't work if `useDialog` is true or on launch when using the Android 12 API. | large | 1.0.0 | +| **`iosSpinnerStyle`** | 'small' \| 'large' | Style of the iOS spinner. Doesn't work if `useDialog` is true. Only available on iOS. | large | 1.0.0 | +| **`spinnerColor`** | string | Color of the spinner in hex format, #RRGGBB or #RRGGBBAA. Doesn't work if `useDialog` is true or on launch when using the Android 12 API. | | 1.0.0 | +| **`splashFullScreen`** | boolean | Hide the status bar on the Splash Screen. Doesn't work on launch when using the Android 12 API. Only available on Android. | | 1.0.0 | +| **`splashImmersive`** | boolean | Hide the status bar and the software navigation buttons on the Splash Screen. Doesn't work on launch when using the Android 12 API. Only available on Android. | | 1.0.0 | +| **`layoutName`** | string | If `useDialog` is set to true, configure the Dialog layout. If `useDialog` is not set or false, use a layout instead of the ImageView. Doesn't work on launch when using the Android 12 API. Only available on Android. | | 1.1.0 | +| **`useDialog`** | boolean | Use a Dialog instead of an ImageView. If `layoutName` is not configured, it will use a layout that uses the splash image as background. Doesn't work on launch when using the Android 12 API. Only available on Android. | | 1.1.0 | ### Examples @@ -155,6 +156,36 @@ To use splash screen images named something other than `splash.png`, set `androi ``` +### Android 12 Splash Screen API + +_**This only affects the launch splash screen and is not used when utilizing the programmatic `show()` method.**_ + +To enable the new recommended **[Android 12 Splash Screen API](https://developer.android.com/guide/topics/ui/splash-screen)** in SDK Versions 30 or below: + +_This is enabled by default and required for SDK version 31+._ + +- Add `$coreSplashScreenVersion` to the `variables.gradle` file. + _See Variables Section for more information_ + +- Add `implementation "androidx.core:core-splashscreen:$coreSplashScreenVersion"` in the dependencies section of `/android/app/build.gradle`. + +- In `android/app/src/main/res/values/styles.xml`, edit the theme `parent` attribute on the Applications's MainActivity Theme to `Theme.SplashScreen` and add desired options to the theme. + +```xml + +``` + +**NOTE**: Some issues may exist on SDK >= 31 when using the new API for the splash screen, which pertain to the splash screen only showing when launched from the launcher icon. +**[Google Issue Tracker](https://issuetracker.google.com/issues/205021357)** + +## Variables + +This plugin will use the following project variables (defined in your app's `variables.gradle` file): + +`$coreSplashScreenVersion` version of `androidx.core:core-splashscreen:$coreSplashScreenVersion` (default: `1.0.0-rc01`) + ## Example Guides [Adding Your Own Icons and Splash Screen Images ›](https://www.joshmorony.com/adding-icons-splash-screens-launch-images-to-capacitor-projects/) diff --git a/splash-screen/android/build.gradle b/splash-screen/android/build.gradle index 56ee0b28b..a1b1024f0 100644 --- a/splash-screen/android/build.gradle +++ b/splash-screen/android/build.gradle @@ -1,27 +1,40 @@ ext { - junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.1' - androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.2.0' - androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.1.2' - androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.3.0' + capacitorVersion = System.getenv('CAPACITOR_VERSION') + junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.2' + androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.4.2' + androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.1.3' + androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.4.0' + coreSplashScreenVersion = project.hasProperty('coreSplashScreenVersion') ? rootProject.ext.coreSplashScreenVersion : '1.0.0-rc01' } buildscript { repositories { google() mavenCentral() + maven { + url "https://plugins.gradle.org/m2/" + } } dependencies { - classpath 'com.android.tools.build:gradle:4.2.1' + classpath 'com.android.tools.build:gradle:7.2.1' + if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + classpath 'io.github.gradle-nexus:publish-plugin:1.1.0' + } } } apply plugin: 'com.android.library' +if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + apply plugin: 'io.github.gradle-nexus.publish-plugin' + apply from: file('../../scripts/android/publish-root.gradle') + apply from: file('../../scripts/android/publish-module.gradle') +} android { - compileSdkVersion project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 30 + compileSdkVersion project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 32 defaultConfig { - minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 21 - targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 30 + minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 22 + targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 32 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" @@ -36,23 +49,29 @@ android { abortOnError false } compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility JavaVersion.VERSION_11 + targetCompatibility JavaVersion.VERSION_11 } } repositories { google() mavenCentral() - jcenter() } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation project(':capacitor-android') + + if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + implementation "com.capacitorjs:core:$capacitorVersion" + } else { + implementation project(':capacitor-android') + } + implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion" testImplementation "junit:junit:$junitVersion" androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion" androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion" + implementation "androidx.core:core-splashscreen:$coreSplashScreenVersion" } diff --git a/splash-screen/android/gradle/wrapper/gradle-wrapper.jar b/splash-screen/android/gradle/wrapper/gradle-wrapper.jar index e708b1c02..41d9927a4 100644 Binary files a/splash-screen/android/gradle/wrapper/gradle-wrapper.jar and b/splash-screen/android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/splash-screen/android/gradle/wrapper/gradle-wrapper.properties b/splash-screen/android/gradle/wrapper/gradle-wrapper.properties index 3c4101c3e..92f06b50f 100644 --- a/splash-screen/android/gradle/wrapper/gradle-wrapper.properties +++ b/splash-screen/android/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/splash-screen/android/gradlew b/splash-screen/android/gradlew index 4f906e0c8..1b6c78733 100755 --- a/splash-screen/android/gradlew +++ b/splash-screen/android/gradlew @@ -1,7 +1,7 @@ -#!/usr/bin/env sh +#!/bin/sh # -# Copyright 2015 the original author or authors. +# Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,67 +17,101 @@ # ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` +APP_BASE_NAME=${0##*/} # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar @@ -87,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -98,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" + JAVACMD=java which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the @@ -106,80 +140,95 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=`expr $i + 1` + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" diff --git a/splash-screen/android/src/main/java/com/capacitorjs/plugins/splashscreen/SplashScreen.java b/splash-screen/android/src/main/java/com/capacitorjs/plugins/splashscreen/SplashScreen.java index 6ef6fac08..342a27a58 100644 --- a/splash-screen/android/src/main/java/com/capacitorjs/plugins/splashscreen/SplashScreen.java +++ b/splash-screen/android/src/main/java/com/capacitorjs/plugins/splashscreen/SplashScreen.java @@ -1,6 +1,8 @@ package com.capacitorjs.plugins.splashscreen; import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ObjectAnimator; import android.app.Activity; import android.app.Dialog; import android.content.Context; @@ -10,14 +12,25 @@ import android.graphics.drawable.Animatable; import android.graphics.drawable.Drawable; import android.graphics.drawable.LayerDrawable; +import android.os.Build; import android.os.Handler; -import android.view.*; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewTreeObserver; +import android.view.ViewTreeObserver.OnPreDrawListener; +import android.view.Window; +import android.view.WindowInsetsController; +import android.view.WindowManager; import android.view.animation.LinearInterpolator; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ProgressBar; import androidx.appcompat.app.AppCompatActivity; +import androidx.core.view.WindowCompat; +import androidx.core.view.WindowInsetsCompat; import com.getcapacitor.Logger; /** @@ -32,7 +45,9 @@ public class SplashScreen { private boolean isVisible = false; private boolean isHiding = false; private Context context; + private View content; private SplashScreenConfig config; + private OnPreDrawListener onPreDrawListener; SplashScreen(Context context, SplashScreenConfig config) { this.context = context; @@ -51,6 +66,17 @@ public void showOnLaunch(final AppCompatActivity activity) { SplashScreenSettings settings = new SplashScreenSettings(); settings.setShowDuration(config.getLaunchShowDuration()); settings.setAutoHide(config.isLaunchAutoHide()); + + // Method can fail if styles are incorrectly set... + // If it fails, log error & fallback to old method + try { + showWithAndroid12API(activity, settings); + return; + } catch (Exception e) { + Logger.warn("Android 12 Splash API failed... using previous method."); + this.onPreDrawListener = null; + } + settings.setFadeInDuration(config.getLaunchFadeInDuration()); if (config.isUsingDialog()) { showDialog(activity, settings, null, true); @@ -59,6 +85,82 @@ public void showOnLaunch(final AppCompatActivity activity) { } } + /** + * Show the Splash Screen using the Android 12 API (31+) + * Uses Compat Library for backwards compatibility + * + * @param activity + * @param settings Settings used to show the Splash Screen + */ + private void showWithAndroid12API(final AppCompatActivity activity, final SplashScreenSettings settings) { + if (activity == null || activity.isFinishing()) return; + + activity.runOnUiThread( + () -> { + androidx.core.splashscreen.SplashScreen windowSplashScreen = androidx.core.splashscreen.SplashScreen.installSplashScreen( + activity + ); + windowSplashScreen.setKeepOnScreenCondition(() -> isVisible || isHiding); + + // Set Fade Out Animation + windowSplashScreen.setOnExitAnimationListener( + windowSplashScreenView -> { + final ObjectAnimator fadeAnimator = ObjectAnimator.ofFloat(windowSplashScreenView.getView(), View.ALPHA, 1f, 0f); + fadeAnimator.setInterpolator(new LinearInterpolator()); + fadeAnimator.setDuration(settings.getFadeOutDuration()); + + fadeAnimator.addListener( + new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + isHiding = false; + windowSplashScreenView.remove(); + } + } + ); + + fadeAnimator.start(); + + isHiding = true; + isVisible = false; + } + ); + + // Set Pre Draw Listener & Delay Drawing Until Duration Elapses + content = activity.findViewById(android.R.id.content); + + this.onPreDrawListener = + new ViewTreeObserver.OnPreDrawListener() { + @Override + public boolean onPreDraw() { + // Start Timer On First Run + if (!isVisible && !isHiding) { + isVisible = true; + + new Handler(context.getMainLooper()) + .postDelayed( + () -> { + // Splash screen is done... start drawing content. + if (settings.isAutoHide()) { + isVisible = false; + onPreDrawListener = null; + content.getViewTreeObserver().removeOnPreDrawListener(this); + } + }, + settings.getShowDuration() + ); + } + + // Not ready to dismiss splash screen + return false; + } + }; + + content.getViewTreeObserver().addOnPreDrawListener(this.onPreDrawListener); + } + ); + } + /** * Show the Splash Screen * @@ -125,7 +227,7 @@ private void showDialog( isVisible = true; if (settings.isAutoHide()) { - new Handler() + new Handler(context.getMainLooper()) .postDelayed( () -> { hideDialog(activity, isLaunchSplash); @@ -215,7 +317,11 @@ private void buildViews() { // Stops flickers dead in their tracks // https://stackoverflow.com/a/21847579/32140 ImageView imageView = (ImageView) splashImage; - imageView.setDrawingCacheEnabled(true); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { + imageView.setLayerType(View.LAYER_TYPE_SOFTWARE, null); + } else { + legacyStopFlickers(imageView); + } imageView.setScaleType(config.getScaleType()); imageView.setImageDrawable(splash); } @@ -223,19 +329,6 @@ private void buildViews() { splashImage.setFitsSystemWindows(true); - if (config.isImmersive()) { - final int flags = - View.SYSTEM_UI_FLAG_LAYOUT_STABLE | - View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | - View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | - View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | - View.SYSTEM_UI_FLAG_FULLSCREEN | - View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; - splashImage.setSystemUiVisibility(flags); - } else if (config.isFullScreen()) { - splashImage.setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN); - } - if (config.getBackgroundColor() != null) { splashImage.setBackgroundColor(config.getBackgroundColor()); } @@ -265,6 +358,11 @@ private void buildViews() { } } + @SuppressWarnings("deprecation") + private void legacyStopFlickers(ImageView imageView) { + imageView.setDrawingCacheEnabled(true); + } + private Drawable getSplashDrawable() { int splashId = context.getResources().getIdentifier(config.getResourceName(), "drawable", context.getPackageName()); try { @@ -301,7 +399,7 @@ public void onAnimationEnd(Animator animator) { isVisible = true; if (settings.isAutoHide()) { - new Handler() + new Handler(context.getMainLooper()) .postDelayed( () -> { hide(settings.getFadeOutDuration(), isLaunchSplash); @@ -348,6 +446,35 @@ public void onAnimationStart(Animator animator) {} return; } + if (config.isImmersive()) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + activity.runOnUiThread( + () -> { + Window window = activity.getWindow(); + WindowCompat.setDecorFitsSystemWindows(window, false); + WindowInsetsController controller = splashImage.getWindowInsetsController(); + controller.hide(WindowInsetsCompat.Type.systemBars()); + controller.setSystemBarsBehavior(WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE); + } + ); + } else { + legacyImmersive(); + } + } else if (config.isFullScreen()) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + activity.runOnUiThread( + () -> { + Window window = activity.getWindow(); + WindowCompat.setDecorFitsSystemWindows(window, false); + WindowInsetsController controller = splashImage.getWindowInsetsController(); + controller.hide(WindowInsetsCompat.Type.statusBars()); + } + ); + } else { + legacyFullscreen(); + } + } + splashImage.setAlpha(0f); splashImage @@ -389,6 +516,23 @@ public void onAnimationStart(Animator animator) {} ); } + @SuppressWarnings("deprecation") + private void legacyImmersive() { + final int flags = + View.SYSTEM_UI_FLAG_LAYOUT_STABLE | + View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | + View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | + View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | + View.SYSTEM_UI_FLAG_FULLSCREEN | + View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; + splashImage.setSystemUiVisibility(flags); + } + + @SuppressWarnings("deprecation") + private void legacyFullscreen() { + splashImage.setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN); + } + private void hide(final int fadeOutDuration, boolean isLaunchSplash) { // Warn the user if the splash was hidden automatically, which means they could be experiencing an app // that feels slower than it actually is. @@ -400,7 +544,21 @@ private void hide(final int fadeOutDuration, boolean isLaunchSplash) { ); } - if (isHiding || splashImage == null || splashImage.getParent() == null) { + if (isHiding) { + return; + } + + // Hide with Android 12 API + if (null != this.onPreDrawListener) { + this.isVisible = false; + if (null != content) { + content.getViewTreeObserver().removeOnPreDrawListener(this.onPreDrawListener); + } + this.onPreDrawListener = null; + return; + } + + if (splashImage == null || splashImage.getParent() == null) { return; } @@ -462,6 +620,16 @@ private void hideDialog(final AppCompatActivity activity, boolean isLaunchSplash return; } + // Hide with Android 12 API + if (null != this.onPreDrawListener) { + this.isVisible = false; + if (null != content) { + content.getViewTreeObserver().removeOnPreDrawListener(this.onPreDrawListener); + } + this.onPreDrawListener = null; + return; + } + isHiding = true; activity.runOnUiThread( @@ -471,6 +639,7 @@ private void hideDialog(final AppCompatActivity activity, boolean isLaunchSplash dialog.dismiss(); } dialog = null; + isHiding = false; isVisible = false; } } @@ -492,6 +661,11 @@ private void tearDown(boolean removeSpinner) { windowManager.removeView(splashImage); } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && config.isFullScreen() || config.isImmersive()) { + // Exit fullscreen mode + Window window = ((Activity) context).getWindow(); + WindowCompat.setDecorFitsSystemWindows(window, true); + } isHiding = false; isVisible = false; } diff --git a/splash-screen/android/src/main/java/com/capacitorjs/plugins/splashscreen/SplashScreenPlugin.java b/splash-screen/android/src/main/java/com/capacitorjs/plugins/splashscreen/SplashScreenPlugin.java index d4e06258e..72cd636df 100644 --- a/splash-screen/android/src/main/java/com/capacitorjs/plugins/splashscreen/SplashScreenPlugin.java +++ b/splash-screen/android/src/main/java/com/capacitorjs/plugins/splashscreen/SplashScreenPlugin.java @@ -7,6 +7,7 @@ import com.getcapacitor.PluginMethod; import com.getcapacitor.annotation.CapacitorPlugin; import com.getcapacitor.util.WebColor; +import java.util.Locale; @CapacitorPlugin(name = "SplashScreen") public class SplashScreenPlugin extends Plugin { @@ -103,7 +104,7 @@ private SplashScreenConfig getSplashScreenConfig() { if (spinnerStyle != null) { int spinnerBarStyle = android.R.attr.progressBarStyleLarge; - switch (spinnerStyle.toLowerCase()) { + switch (spinnerStyle.toLowerCase(Locale.ROOT)) { case "horizontal": spinnerBarStyle = android.R.attr.progressBarStyleHorizontal; break; diff --git a/splash-screen/ios/Plugin.xcodeproj/project.pbxproj b/splash-screen/ios/Plugin.xcodeproj/project.pbxproj index 9b6b3bd9c..01ea34e26 100644 --- a/splash-screen/ios/Plugin.xcodeproj/project.pbxproj +++ b/splash-screen/ios/Plugin.xcodeproj/project.pbxproj @@ -394,7 +394,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -454,7 +454,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; @@ -477,12 +477,13 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Plugin/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks $(FRAMEWORK_SEARCH_PATHS)\n$(FRAMEWORK_SEARCH_PATHS)\n$(FRAMEWORK_SEARCH_PATHS)"; ONLY_ACTIVE_ARCH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.getcapacitor.Plugin; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; + SUPPORTS_MACCATALYST = NO; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -502,12 +503,13 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Plugin/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks $(FRAMEWORK_SEARCH_PATHS)"; ONLY_ACTIVE_ARCH = NO; PRODUCT_BUNDLE_IDENTIFIER = com.getcapacitor.Plugin; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; + SUPPORTS_MACCATALYST = NO; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; diff --git a/splash-screen/ios/Plugin/SplashScreen.swift b/splash-screen/ios/Plugin/SplashScreen.swift index 615326039..4a00ed628 100644 --- a/splash-screen/ios/Plugin/SplashScreen.swift +++ b/splash-screen/ios/Plugin/SplashScreen.swift @@ -89,7 +89,7 @@ import Capacitor private func buildViews() { let storyboardName = Bundle.main.infoDictionary?["UILaunchStoryboardName"] as? String ?? "LaunchScreen" - if let vc = UIStoryboard(name: storyboardName, bundle: nil).instantiateInitialViewController() { + if let vc = UIStoryboard(name: storyboardName.replacingOccurrences(of: ".storyboard", with: ""), bundle: nil).instantiateInitialViewController() { viewController = vc } @@ -117,9 +117,9 @@ import Capacitor // Update the bounds for the splash image. This will also be called when // the parent view observers fire private func updateSplashImageBounds() { - var window: UIWindow? = UIApplication.shared.delegate?.window as? UIWindow + var window: UIWindow? = UIApplication.shared.delegate?.window ?? nil - if #available(iOS 13, *), window == nil { + if window == nil { let scene: UIWindowScene? = UIApplication.shared.connectedScenes.first as? UIWindowScene window = scene?.windows.filter({$0.isKeyWindow}).first if window == nil { diff --git a/splash-screen/ios/Plugin/SplashScreenPlugin.swift b/splash-screen/ios/Plugin/SplashScreenPlugin.swift index 1fee828e9..8c0e31a69 100644 --- a/splash-screen/ios/Plugin/SplashScreenPlugin.swift +++ b/splash-screen/ios/Plugin/SplashScreenPlugin.swift @@ -58,30 +58,24 @@ public class SplashScreenPlugin: CAPPlugin { private func splashScreenConfig() -> SplashScreenConfig { var config = SplashScreenConfig() - if let backgroundColor = getConfigValue("backgroundColor") as? String { + if let backgroundColor = getConfig().getString("backgroundColor") { config.backgroundColor = UIColor.capacitor.color(fromHex: backgroundColor) } - if let spinnerStyle = getConfigValue("iosSpinnerStyle") as? String { + if let spinnerStyle = getConfig().getString("iosSpinnerStyle") { switch spinnerStyle.lowercased() { case "small": - config.spinnerStyle = .white + config.spinnerStyle = .medium default: - config.spinnerStyle = .whiteLarge + config.spinnerStyle = .large } } - if let spinnerColor = getConfigValue("spinnerColor") as? String { + if let spinnerColor = getConfig().getString("spinnerColor") { config.spinnerColor = UIColor.capacitor.color(fromHex: spinnerColor) } - if let showSpinner = getConfigValue("showSpinner") as? Bool { - config.showSpinner = showSpinner - } + config.showSpinner = getConfig().getBoolean("showSpinner", config.showSpinner) - if let launchShowDuration = getConfigValue("launchShowDuration") as? Int { - config.launchShowDuration = launchShowDuration - } - if let launchAutoHide = getConfigValue("launchAutoHide") as? Bool { - config.launchAutoHide = launchAutoHide - } + config.launchShowDuration = getConfig().getInt("launchShowDuration", config.launchShowDuration) + config.launchAutoHide = getConfig().getBoolean("launchAutoHide", config.launchAutoHide) return config } diff --git a/splash-screen/ios/Podfile b/splash-screen/ios/Podfile index 54a00c161..dee40960f 100644 --- a/splash-screen/ios/Podfile +++ b/splash-screen/ios/Podfile @@ -1,4 +1,4 @@ -platform :ios, '12.0' +platform :ios, '13.0' def capacitor_pods # Comment the next line if you're not using Swift and don't want to use dynamic frameworks diff --git a/splash-screen/package.json b/splash-screen/package.json index bde9e15f2..07aaf0180 100644 --- a/splash-screen/package.json +++ b/splash-screen/package.json @@ -1,6 +1,6 @@ { "name": "@capacitor/splash-screen", - "version": "1.2.1", + "version": "4.1.2", "description": "The Splash Screen API provides methods for showing or hiding a Splash image.", "main": "dist/plugin.cjs.js", "module": "dist/esm/index.js", @@ -29,7 +29,7 @@ ], "scripts": { "verify": "npm run verify:ios && npm run verify:android && npm run verify:web", - "verify:ios": "cd ios && pod install && xcodebuild -workspace Plugin.xcworkspace -scheme Plugin && cd ..", + "verify:ios": "cd ios && pod install && xcodebuild -workspace Plugin.xcworkspace -scheme Plugin -destination generic/platform=iOS && cd ..", "verify:android": "cd android && ./gradlew clean build test && cd ..", "verify:web": "npm run build", "lint": "npm run eslint && npm run prettier -- --check && npm run swiftlint -- lint", @@ -45,11 +45,11 @@ "publish:cocoapod": "pod trunk push ./CapacitorSplashScreen.podspec --allow-warnings" }, "devDependencies": { - "@capacitor/android": "^3.0.0", - "@capacitor/cli": "^3.0.0", - "@capacitor/core": "^3.0.0", - "@capacitor/docgen": "0.0.18", - "@capacitor/ios": "^3.0.0", + "@capacitor/android": "^4.0.0", + "@capacitor/cli": "^4.0.0", + "@capacitor/core": "^4.0.0", + "@capacitor/docgen": "0.2.0", + "@capacitor/ios": "^4.0.0", "@ionic/eslint-config": "^0.3.0", "@ionic/prettier-config": "~1.0.1", "@ionic/swiftlint-config": "^1.1.2", @@ -62,7 +62,7 @@ "typescript": "~4.1.5" }, "peerDependencies": { - "@capacitor/core": "^3.0.0" + "@capacitor/core": "^4.0.0" }, "prettier": "@ionic/prettier-config", "swiftlint": "@ionic/swiftlint-config", diff --git a/splash-screen/src/definitions.ts b/splash-screen/src/definitions.ts index 3a5913759..b3b539344 100644 --- a/splash-screen/src/definitions.ts +++ b/splash-screen/src/definitions.ts @@ -26,7 +26,7 @@ declare module '@capacitor/cli' { /** * Color of the background of the Splash Screen in hex format, #RRGGBB or #RRGGBBAA. - * Doesn't work if `useDialog` is true. + * Doesn't work if `useDialog` is true or on launch when using the Android 12 API. * * @since 1.0.0 * @example "#ffffffff" @@ -36,6 +36,8 @@ declare module '@capacitor/cli' { /** * Name of the resource to be used as Splash Screen. * + * Doesn't work on launch when using the Android 12 API. + * * Only available on Android. * * @since 1.0.0 @@ -47,7 +49,7 @@ declare module '@capacitor/cli' { /** * The [ImageView.ScaleType](https://developer.android.com/reference/android/widget/ImageView.ScaleType) used to scale * the Splash Screen image. - * Doesn't work if `useDialog` is true. + * Doesn't work if `useDialog` is true or on launch when using the Android 12 API. * * Only available on Android. * @@ -67,7 +69,7 @@ declare module '@capacitor/cli' { /** * Show a loading spinner on the Splash Screen. - * Doesn't work if `useDialog` is true. + * Doesn't work if `useDialog` is true or on launch when using the Android 12 API. * * @since 1.0.0 * @example true @@ -76,7 +78,7 @@ declare module '@capacitor/cli' { /** * Style of the Android spinner. - * Doesn't work if `useDialog` is true. + * Doesn't work if `useDialog` is true or on launch when using the Android 12 API. * * @since 1.0.0 * @default large @@ -104,7 +106,7 @@ declare module '@capacitor/cli' { /** * Color of the spinner in hex format, #RRGGBB or #RRGGBBAA. - * Doesn't work if `useDialog` is true. + * Doesn't work if `useDialog` is true or on launch when using the Android 12 API. * * @since 1.0.0 * @example "#999999" @@ -114,6 +116,8 @@ declare module '@capacitor/cli' { /** * Hide the status bar on the Splash Screen. * + * Doesn't work on launch when using the Android 12 API. + * * Only available on Android. * * @since 1.0.0 @@ -124,6 +128,8 @@ declare module '@capacitor/cli' { /** * Hide the status bar and the software navigation buttons on the Splash Screen. * + * Doesn't work on launch when using the Android 12 API. + * * Only available on Android. * * @since 1.0.0 @@ -135,6 +141,8 @@ declare module '@capacitor/cli' { * If `useDialog` is set to true, configure the Dialog layout. * If `useDialog` is not set or false, use a layout instead of the ImageView. * + * Doesn't work on launch when using the Android 12 API. + * * Only available on Android. * * @since 1.1.0 @@ -147,6 +155,8 @@ declare module '@capacitor/cli' { * If `layoutName` is not configured, it will use * a layout that uses the splash image as background. * + * Doesn't work on launch when using the Android 12 API. + * * Only available on Android. * * @since 1.1.0 diff --git a/status-bar/CHANGELOG.md b/status-bar/CHANGELOG.md index d613b121e..2186b49d3 100644 --- a/status-bar/CHANGELOG.md +++ b/status-bar/CHANGELOG.md @@ -3,6 +3,107 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.1.0](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/status-bar@1.0.8...@capacitor/status-bar@4.1.0) (2022-11-16) + + + +## 4.0.1 (2022-07-28) + + + +# 4.0.0 (2022-07-27) + + +### Bug Fixes + +* **status-bar:** not working on older devices ([#1078](https://github.com/ionic-team/capacitor-plugins/issues/1078)) ([4e34977](https://github.com/ionic-team/capacitor-plugins/commit/4e349772d3d8f8e30ce52c1831a1dc9a9f9fd408)) + + + +# 4.0.0-beta.2 (2022-07-08) + + + +# 4.0.0-beta.0 (2022-06-27) + + +### Features + +* set targetSDK default value to 31 ([#824](https://github.com/ionic-team/capacitor-plugins/issues/824)) ([3ee10de](https://github.com/ionic-team/capacitor-plugins/commit/3ee10de98067984c1a4e75295d001c5a895c47f4)) +* set targetSDK default value to 32 ([#970](https://github.com/ionic-team/capacitor-plugins/issues/970)) ([fa70d96](https://github.com/ionic-team/capacitor-plugins/commit/fa70d96f141af751aae53ceb5642c46b204f5958)) +* Upgrade gradle to 7.4 ([#826](https://github.com/ionic-team/capacitor-plugins/issues/826)) ([5db0906](https://github.com/ionic-team/capacitor-plugins/commit/5db0906f6264287c4f8e69dbaecf19d4d387824b)) +* Use java 11 ([#910](https://github.com/ionic-team/capacitor-plugins/issues/910)) ([5acb2a2](https://github.com/ionic-team/capacitor-plugins/commit/5acb2a288a413492b163e4e97da46a085d9e4be0)) + + + + + +## [4.0.1](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0...4.0.1) (2022-07-28) + +**Note:** Version bump only for package @capacitor/status-bar + + + + + +# [4.0.0](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0-beta.2...4.0.0) (2022-07-27) + + +### Bug Fixes + +* **status-bar:** not working on older devices ([#1078](https://github.com/ionic-team/capacitor-plugins/issues/1078)) ([4e34977](https://github.com/ionic-team/capacitor-plugins/commit/4e349772d3d8f8e30ce52c1831a1dc9a9f9fd408)) + + + + + +# [4.0.0-beta.2](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0-beta.0...4.0.0-beta.2) (2022-07-08) + +**Note:** Version bump only for package @capacitor/status-bar + + + + + +# 4.0.0-beta.0 (2022-06-27) + + +### Bug Fixes + +* **status-bar:** Use Locale.ROOT on toUpperCase ([#814](https://github.com/ionic-team/capacitor-plugins/issues/814)) ([bf804ce](https://github.com/ionic-team/capacitor-plugins/commit/bf804ceaa5b7ee94ddeff052511db7c6ee49b4e6)) +* add es2017 lib to tsconfig ([#180](https://github.com/ionic-team/capacitor-plugins/issues/180)) ([2c3776c](https://github.com/ionic-team/capacitor-plugins/commit/2c3776c38ca025c5ee965dec10ccf1cdb6c02e2f)) +* correct addListeners links ([#655](https://github.com/ionic-team/capacitor-plugins/issues/655)) ([f9871e7](https://github.com/ionic-team/capacitor-plugins/commit/f9871e7bd53478addb21155e148829f550c0e457)) +* inline source code in esm map files ([#760](https://github.com/ionic-team/capacitor-plugins/issues/760)) ([a960489](https://github.com/ionic-team/capacitor-plugins/commit/a960489a19db0182b90d187a50deff9dfbe51038)) +* Migrate plugins from Color.parseColor() to WebColor.parseColor() ([#140](https://github.com/ionic-team/capacitor-plugins/issues/140)) ([26625cf](https://github.com/ionic-team/capacitor-plugins/commit/26625cfefe45b8d1f17ce27efbc8b04f23e99d93)) +* remove postpublish scripts ([#656](https://github.com/ionic-team/capacitor-plugins/issues/656)) ([ed6ac49](https://github.com/ionic-team/capacitor-plugins/commit/ed6ac499ebf4a47525071ccbfc36c27503e11f60)) +* support deprecated types from Capacitor 2 ([#139](https://github.com/ionic-team/capacitor-plugins/issues/139)) ([2d7127a](https://github.com/ionic-team/capacitor-plugins/commit/2d7127a488e26f0287951921a6db47c49d817336)) +* **status-bar:** remove deprecate warnings ([#120](https://github.com/ionic-team/capacitor-plugins/issues/120)) ([5dcfb25](https://github.com/ionic-team/capacitor-plugins/commit/5dcfb25b7307e631873fc66523ffccd206e07875)) + + +### Features + +* add commonjs output format ([#179](https://github.com/ionic-team/capacitor-plugins/issues/179)) ([8e9e098](https://github.com/ionic-team/capacitor-plugins/commit/8e9e09862064b3f6771d7facbc4008e995d9b463)) +* set targetSDK default value to 31 ([#824](https://github.com/ionic-team/capacitor-plugins/issues/824)) ([3ee10de](https://github.com/ionic-team/capacitor-plugins/commit/3ee10de98067984c1a4e75295d001c5a895c47f4)) +* set targetSDK default value to 32 ([#970](https://github.com/ionic-team/capacitor-plugins/issues/970)) ([fa70d96](https://github.com/ionic-team/capacitor-plugins/commit/fa70d96f141af751aae53ceb5642c46b204f5958)) +* Status Bar plugin ([#58](https://github.com/ionic-team/capacitor-plugins/issues/58)) ([9a04a5d](https://github.com/ionic-team/capacitor-plugins/commit/9a04a5daa16a283383afba58acde1d11d81378ec)) +* Upgrade gradle to 7.4 ([#826](https://github.com/ionic-team/capacitor-plugins/issues/826)) ([5db0906](https://github.com/ionic-team/capacitor-plugins/commit/5db0906f6264287c4f8e69dbaecf19d4d387824b)) +* Use java 11 ([#910](https://github.com/ionic-team/capacitor-plugins/issues/910)) ([5acb2a2](https://github.com/ionic-team/capacitor-plugins/commit/5acb2a288a413492b163e4e97da46a085d9e4be0)) + + + + + +## [1.0.8](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/status-bar@1.0.7...@capacitor/status-bar@1.0.8) (2022-02-10) + + +### Bug Fixes + +* **status-bar:** Use Locale.ROOT on toUpperCase ([#814](https://github.com/ionic-team/capacitor-plugins/issues/814)) ([bf804ce](https://github.com/ionic-team/capacitor-plugins/commit/bf804ceaa5b7ee94ddeff052511db7c6ee49b4e6)) + + + + + ## [1.0.7](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/status-bar@1.0.6...@capacitor/status-bar@1.0.7) (2022-01-19) diff --git a/status-bar/CapacitorStatusBar.podspec b/status-bar/CapacitorStatusBar.podspec index af923b0ff..cc74bae37 100644 --- a/status-bar/CapacitorStatusBar.podspec +++ b/status-bar/CapacitorStatusBar.podspec @@ -11,7 +11,7 @@ Pod::Spec.new do |s| s.author = package['author'] s.source = { :git => 'https://github.com/ionic-team/capacitor-plugins.git', :tag => package['name'] + '@' + package['version'] } s.source_files = 'ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}', 'status-bar/ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}' - s.ios.deployment_target = '12.0' + s.ios.deployment_target = '13.0' s.dependency 'Capacitor' s.swift_version = '5.1' end diff --git a/status-bar/README.md b/status-bar/README.md index 92c2a7a4b..7a6d6ed20 100644 --- a/status-bar/README.md +++ b/status-bar/README.md @@ -222,11 +222,11 @@ This method is only supported on Android. #### Style -| Members | Value | Description | Since | -| ------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----- | -| **`Dark`** | 'DARK' | Light text for dark backgrounds. | 1.0.0 | -| **`Light`** | 'LIGHT' | Dark text for light backgrounds. | 1.0.0 | -| **`Default`** | 'DEFAULT' | On iOS 13 and newer the style is based on the device appearance. If the device is using Dark mode, the statusbar text will be light. If the device is using Light mode, the statusbar text will be dark. On iOS 12 and older the statusbar text will be dark. On Android the default will be the one the app was launched with. | 1.0.0 | +| Members | Value | Description | Since | +| ------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----- | +| **`Dark`** | 'DARK' | Light text for dark backgrounds. | 1.0.0 | +| **`Light`** | 'LIGHT' | Dark text for light backgrounds. | 1.0.0 | +| **`Default`** | 'DEFAULT' | The style is based on the device appearance. If the device is using Dark mode, the statusbar text will be light. If the device is using Light mode, the statusbar text will be dark. On Android the default will be the one the app was launched with. | 1.0.0 | #### Animation diff --git a/status-bar/android/build.gradle b/status-bar/android/build.gradle index 56ee0b28b..61fd3be31 100644 --- a/status-bar/android/build.gradle +++ b/status-bar/android/build.gradle @@ -1,27 +1,40 @@ ext { - junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.1' - androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.2.0' - androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.1.2' - androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.3.0' + capacitorVersion = System.getenv('CAPACITOR_VERSION') + junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.2' + androidxCoreVersion = project.hasProperty('androidxCoreVersion') ? rootProject.ext.androidxCoreVersion : '1.8.0' + androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.4.2' + androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.1.3' + androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.4.0' } buildscript { repositories { google() mavenCentral() + maven { + url "https://plugins.gradle.org/m2/" + } } dependencies { - classpath 'com.android.tools.build:gradle:4.2.1' + classpath 'com.android.tools.build:gradle:7.2.1' + if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + classpath 'io.github.gradle-nexus:publish-plugin:1.1.0' + } } } apply plugin: 'com.android.library' +if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + apply plugin: 'io.github.gradle-nexus.publish-plugin' + apply from: file('../../scripts/android/publish-root.gradle') + apply from: file('../../scripts/android/publish-module.gradle') +} android { - compileSdkVersion project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 30 + compileSdkVersion project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 32 defaultConfig { - minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 21 - targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 30 + minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 22 + targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 32 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" @@ -36,21 +49,27 @@ android { abortOnError false } compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility JavaVersion.VERSION_11 + targetCompatibility JavaVersion.VERSION_11 } } repositories { google() mavenCentral() - jcenter() } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation project(':capacitor-android') + + if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + implementation "com.capacitorjs:core:$capacitorVersion" + } else { + implementation project(':capacitor-android') + } + + implementation "androidx.core:core:$androidxCoreVersion" implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion" testImplementation "junit:junit:$junitVersion" androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion" diff --git a/status-bar/android/gradle/wrapper/gradle-wrapper.jar b/status-bar/android/gradle/wrapper/gradle-wrapper.jar index e708b1c02..41d9927a4 100644 Binary files a/status-bar/android/gradle/wrapper/gradle-wrapper.jar and b/status-bar/android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/status-bar/android/gradle/wrapper/gradle-wrapper.properties b/status-bar/android/gradle/wrapper/gradle-wrapper.properties index 3c4101c3e..92f06b50f 100644 --- a/status-bar/android/gradle/wrapper/gradle-wrapper.properties +++ b/status-bar/android/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/status-bar/android/gradlew b/status-bar/android/gradlew index 4f906e0c8..1b6c78733 100755 --- a/status-bar/android/gradlew +++ b/status-bar/android/gradlew @@ -1,7 +1,7 @@ -#!/usr/bin/env sh +#!/bin/sh # -# Copyright 2015 the original author or authors. +# Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,67 +17,101 @@ # ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` +APP_BASE_NAME=${0##*/} # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar @@ -87,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -98,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" + JAVACMD=java which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the @@ -106,80 +140,95 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=`expr $i + 1` + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" diff --git a/status-bar/android/src/main/java/com/capacitorjs/plugins/statusbar/StatusBar.java b/status-bar/android/src/main/java/com/capacitorjs/plugins/statusbar/StatusBar.java index 30e583496..01d354a29 100644 --- a/status-bar/android/src/main/java/com/capacitorjs/plugins/statusbar/StatusBar.java +++ b/status-bar/android/src/main/java/com/capacitorjs/plugins/statusbar/StatusBar.java @@ -5,17 +5,21 @@ import android.view.Window; import android.view.WindowManager; import androidx.appcompat.app.AppCompatActivity; +import androidx.core.view.ViewCompat; +import androidx.core.view.WindowCompat; +import androidx.core.view.WindowInsetsCompat; +import androidx.core.view.WindowInsetsControllerCompat; public class StatusBar { - private int currentStatusbarColor; - private AppCompatActivity activity; - private String defaultStyle; + private int currentStatusBarColor; + private final AppCompatActivity activity; + private final String defaultStyle; public StatusBar(AppCompatActivity activity) { // save initial color of the status bar this.activity = activity; - this.currentStatusbarColor = activity.getWindow().getStatusBarColor(); + this.currentStatusBarColor = activity.getWindow().getStatusBarColor(); this.defaultStyle = getStyle(); } @@ -23,83 +27,81 @@ public void setStyle(String style) { Window window = activity.getWindow(); View decorView = window.getDecorView(); - int visibilityFlags = decorView.getSystemUiVisibility(); if (style.equals("DEFAULT")) { style = this.defaultStyle; } - if (style.equals("DARK")) { - decorView.setSystemUiVisibility(visibilityFlags & ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); - } else { - decorView.setSystemUiVisibility(visibilityFlags | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); - } + + WindowInsetsControllerCompat windowInsetsControllerCompat = WindowCompat.getInsetsController(window, decorView); + windowInsetsControllerCompat.setAppearanceLightStatusBars(!style.equals("DARK")); } + @SuppressWarnings("deprecation") public void setBackgroundColor(int color) { Window window = activity.getWindow(); window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); window.setStatusBarColor(color); // update the local color field as well - currentStatusbarColor = color; + currentStatusBarColor = color; } public void hide() { View decorView = activity.getWindow().getDecorView(); - int uiOptions = decorView.getSystemUiVisibility(); - uiOptions = uiOptions | View.SYSTEM_UI_FLAG_FULLSCREEN; - uiOptions = uiOptions & ~View.SYSTEM_UI_FLAG_VISIBLE; - decorView.setSystemUiVisibility(uiOptions); + WindowInsetsControllerCompat windowInsetsControllerCompat = WindowCompat.getInsetsController(activity.getWindow(), decorView); + windowInsetsControllerCompat.hide(WindowInsetsCompat.Type.statusBars()); } public void show() { View decorView = activity.getWindow().getDecorView(); - int uiOptions = decorView.getSystemUiVisibility(); - uiOptions = uiOptions | View.SYSTEM_UI_FLAG_VISIBLE; - uiOptions = uiOptions & ~View.SYSTEM_UI_FLAG_FULLSCREEN; - decorView.setSystemUiVisibility(uiOptions); + WindowInsetsControllerCompat windowInsetsControllerCompat = WindowCompat.getInsetsController(activity.getWindow(), decorView); + windowInsetsControllerCompat.show(WindowInsetsCompat.Type.statusBars()); } + @SuppressWarnings("deprecation") public void setOverlaysWebView(Boolean overlays) { + View decorView = activity.getWindow().getDecorView(); + int uiOptions = decorView.getSystemUiVisibility(); if (overlays) { - // Sets the layout to a fullscreen one that does not hide the actual status bar, so the webview is displayed behind it. - View decorView = activity.getWindow().getDecorView(); - int uiOptions = decorView.getSystemUiVisibility(); + // Sets the layout to a fullscreen one that does not hide the actual status bar, so the WebView is displayed behind it. uiOptions = uiOptions | View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; decorView.setSystemUiVisibility(uiOptions); - currentStatusbarColor = activity.getWindow().getStatusBarColor(); + currentStatusBarColor = activity.getWindow().getStatusBarColor(); activity.getWindow().setStatusBarColor(Color.TRANSPARENT); } else { - // Sets the layout to a normal one that displays the webview below the status bar. - View decorView = activity.getWindow().getDecorView(); - int uiOptions = decorView.getSystemUiVisibility(); + // Sets the layout to a normal one that displays the WebView below the status bar. uiOptions = uiOptions & ~View.SYSTEM_UI_FLAG_LAYOUT_STABLE & ~View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; decorView.setSystemUiVisibility(uiOptions); // recover the previous color of the status bar - activity.getWindow().setStatusBarColor(currentStatusbarColor); + activity.getWindow().setStatusBarColor(currentStatusBarColor); } } + @SuppressWarnings("deprecation") + private boolean getIsOverlaid() { + return ( + (activity.getWindow().getDecorView().getSystemUiVisibility() & View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) == + View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + ); + } + public StatusBarInfo getInfo() { Window window = activity.getWindow(); - View decorView = window.getDecorView(); + WindowInsetsCompat windowInsetsCompat = ViewCompat.getRootWindowInsets(window.getDecorView()); + boolean isVisible = windowInsetsCompat != null && windowInsetsCompat.isVisible(WindowInsetsCompat.Type.statusBars()); StatusBarInfo info = new StatusBarInfo(); info.setStyle(getStyle()); - info.setOverlays( - (decorView.getSystemUiVisibility() & View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) == View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN - ); - info.setVisible((decorView.getSystemUiVisibility() & View.SYSTEM_UI_FLAG_FULLSCREEN) != View.SYSTEM_UI_FLAG_FULLSCREEN); + info.setOverlays(getIsOverlaid()); + info.setVisible(isVisible); info.setColor(String.format("#%06X", (0xFFFFFF & window.getStatusBarColor()))); - return info; } private String getStyle() { View decorView = activity.getWindow().getDecorView(); - String style; - if ((decorView.getSystemUiVisibility() & View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR) == View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR) { + String style = "DARK"; + WindowInsetsControllerCompat windowInsetsControllerCompat = WindowCompat.getInsetsController(activity.getWindow(), decorView); + if (windowInsetsControllerCompat.isAppearanceLightStatusBars()) { style = "LIGHT"; - } else { - style = "DARK"; } return style; } diff --git a/status-bar/android/src/main/java/com/capacitorjs/plugins/statusbar/StatusBarPlugin.java b/status-bar/android/src/main/java/com/capacitorjs/plugins/statusbar/StatusBarPlugin.java index becddb039..a66492014 100644 --- a/status-bar/android/src/main/java/com/capacitorjs/plugins/statusbar/StatusBarPlugin.java +++ b/status-bar/android/src/main/java/com/capacitorjs/plugins/statusbar/StatusBarPlugin.java @@ -6,6 +6,7 @@ import com.getcapacitor.PluginMethod; import com.getcapacitor.annotation.CapacitorPlugin; import com.getcapacitor.util.WebColor; +import java.util.Locale; @CapacitorPlugin(name = "StatusBar") public class StatusBarPlugin extends Plugin { @@ -46,7 +47,7 @@ public void setBackgroundColor(final PluginCall call) { .executeOnMainThread( () -> { try { - final int parsedColor = WebColor.parseColor(color.toUpperCase()); + final int parsedColor = WebColor.parseColor(color.toUpperCase(Locale.ROOT)); implementation.setBackgroundColor(parsedColor); call.resolve(); } catch (IllegalArgumentException ex) { diff --git a/status-bar/ios/Plugin.xcodeproj/project.pbxproj b/status-bar/ios/Plugin.xcodeproj/project.pbxproj index bf328b0f4..25141e761 100644 --- a/status-bar/ios/Plugin.xcodeproj/project.pbxproj +++ b/status-bar/ios/Plugin.xcodeproj/project.pbxproj @@ -382,7 +382,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -442,7 +442,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; @@ -465,12 +465,13 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Plugin/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks $(FRAMEWORK_SEARCH_PATHS)\n$(FRAMEWORK_SEARCH_PATHS)\n$(FRAMEWORK_SEARCH_PATHS)"; ONLY_ACTIVE_ARCH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.getcapacitor.Plugin; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; + SUPPORTS_MACCATALYST = NO; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -490,12 +491,13 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Plugin/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks $(FRAMEWORK_SEARCH_PATHS)"; ONLY_ACTIVE_ARCH = NO; PRODUCT_BUNDLE_IDENTIFIER = com.getcapacitor.Plugin; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; + SUPPORTS_MACCATALYST = NO; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; diff --git a/status-bar/ios/Plugin/StatusBarPlugin.swift b/status-bar/ios/Plugin/StatusBarPlugin.swift index 64d2b8d73..8839e401b 100644 --- a/status-bar/ios/Plugin/StatusBarPlugin.swift +++ b/status-bar/ios/Plugin/StatusBarPlugin.swift @@ -28,11 +28,7 @@ public class StatusBarPlugin: CAPPlugin { if style == "DARK" { bridge?.statusBarStyle = .lightContent } else if style == "LIGHT" { - if #available(iOS 13.0, *) { - bridge?.statusBarStyle = .darkContent - } else { - bridge?.statusBarStyle = .default - } + bridge?.statusBarStyle = .darkContent } else if style == "DEFAULT" { bridge?.statusBarStyle = .default } @@ -74,25 +70,17 @@ public class StatusBarPlugin: CAPPlugin { return } let style: String - if #available(iOS 13.0, *) { - switch bridge.statusBarStyle { - case .default: - if bridge.userInterfaceStyle == UIUserInterfaceStyle.dark { - style = "DARK" - } else { - style = "LIGHT" - } - case .lightContent: - style = "DARK" - default: - style = "LIGHT" - } - } else { - if bridge.statusBarStyle == .lightContent { + switch bridge.statusBarStyle { + case .default: + if bridge.userInterfaceStyle == UIUserInterfaceStyle.dark { style = "DARK" } else { style = "LIGHT" } + case .lightContent: + style = "DARK" + default: + style = "LIGHT" } call.resolve([ diff --git a/status-bar/ios/Podfile b/status-bar/ios/Podfile index 54a00c161..dee40960f 100644 --- a/status-bar/ios/Podfile +++ b/status-bar/ios/Podfile @@ -1,4 +1,4 @@ -platform :ios, '12.0' +platform :ios, '13.0' def capacitor_pods # Comment the next line if you're not using Swift and don't want to use dynamic frameworks diff --git a/status-bar/package.json b/status-bar/package.json index 8b9e5f504..a813e0d38 100644 --- a/status-bar/package.json +++ b/status-bar/package.json @@ -1,6 +1,6 @@ { "name": "@capacitor/status-bar", - "version": "1.0.7", + "version": "4.1.0", "description": "The StatusBar API Provides methods for configuring the style of the Status Bar, along with showing or hiding it.", "main": "dist/plugin.cjs.js", "module": "dist/esm/index.js", @@ -29,7 +29,7 @@ ], "scripts": { "verify": "npm run verify:ios && npm run verify:android && npm run verify:web", - "verify:ios": "cd ios && pod install && xcodebuild -workspace Plugin.xcworkspace -scheme Plugin && cd ..", + "verify:ios": "cd ios && pod install && xcodebuild -workspace Plugin.xcworkspace -scheme Plugin -destination generic/platform=iOS && cd ..", "verify:android": "cd android && ./gradlew clean build test && cd ..", "verify:web": "npm run build", "lint": "npm run eslint && npm run prettier -- --check && npm run swiftlint -- lint", @@ -45,10 +45,10 @@ "publish:cocoapod": "pod trunk push ./CapacitorStatusBar.podspec --allow-warnings" }, "devDependencies": { - "@capacitor/android": "^3.0.0", - "@capacitor/core": "^3.0.0", - "@capacitor/docgen": "0.0.18", - "@capacitor/ios": "^3.0.0", + "@capacitor/android": "^4.0.0", + "@capacitor/core": "^4.0.0", + "@capacitor/docgen": "0.2.0", + "@capacitor/ios": "^4.0.0", "@ionic/eslint-config": "^0.3.0", "@ionic/prettier-config": "~1.0.1", "@ionic/swiftlint-config": "^1.1.2", @@ -61,7 +61,7 @@ "typescript": "~4.1.5" }, "peerDependencies": { - "@capacitor/core": "^3.0.0" + "@capacitor/core": "^4.0.0" }, "prettier": "@ionic/prettier-config", "swiftlint": "@ionic/swiftlint-config", diff --git a/status-bar/src/definitions.ts b/status-bar/src/definitions.ts index 4305b48f2..1d1c43187 100644 --- a/status-bar/src/definitions.ts +++ b/status-bar/src/definitions.ts @@ -23,10 +23,9 @@ export enum Style { Light = 'LIGHT', /** - * On iOS 13 and newer the style is based on the device appearance. + * The style is based on the device appearance. * If the device is using Dark mode, the statusbar text will be light. * If the device is using Light mode, the statusbar text will be dark. - * On iOS 12 and older the statusbar text will be dark. * On Android the default will be the one the app was launched with. * * @since 1.0.0 diff --git a/storage/android/src/main/java/com/capacitorjs/plugins/storage/StorageConfiguration.java b/storage/android/src/main/java/com/capacitorjs/plugins/storage/StorageConfiguration.java deleted file mode 100644 index 8362c8807..000000000 --- a/storage/android/src/main/java/com/capacitorjs/plugins/storage/StorageConfiguration.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.capacitorjs.plugins.storage; - -public class StorageConfiguration implements Cloneable { - - static final StorageConfiguration DEFAULTS; - - static { - DEFAULTS = new StorageConfiguration(); - DEFAULTS.group = "CapacitorStorage"; - } - - String group; - - @Override - public StorageConfiguration clone() throws CloneNotSupportedException { - return (StorageConfiguration) super.clone(); - } -} diff --git a/storage/src/index.ts b/storage/src/index.ts deleted file mode 100644 index 7b571ba3b..000000000 --- a/storage/src/index.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { registerPlugin } from '@capacitor/core'; - -import type { StoragePlugin } from './definitions'; - -const Storage = registerPlugin('Storage', { - web: () => import('./web').then(m => new m.StorageWeb()), -}); - -export * from './definitions'; -export { Storage }; diff --git a/text-zoom/CHANGELOG.md b/text-zoom/CHANGELOG.md index 1fdebb0dd..91b8e6a23 100644 --- a/text-zoom/CHANGELOG.md +++ b/text-zoom/CHANGELOG.md @@ -3,6 +3,88 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.1.0](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/text-zoom@1.0.8...@capacitor/text-zoom@4.1.0) (2022-11-16) + + + +## 4.0.1 (2022-07-28) + + + +# 4.0.0 (2022-07-27) + + + +# 4.0.0-beta.2 (2022-07-08) + + + +# 4.0.0-beta.0 (2022-06-27) + + +### Features + +* set targetSDK default value to 31 ([#824](https://github.com/ionic-team/capacitor-plugins/issues/824)) ([3ee10de](https://github.com/ionic-team/capacitor-plugins/commit/3ee10de98067984c1a4e75295d001c5a895c47f4)) +* set targetSDK default value to 32 ([#970](https://github.com/ionic-team/capacitor-plugins/issues/970)) ([fa70d96](https://github.com/ionic-team/capacitor-plugins/commit/fa70d96f141af751aae53ceb5642c46b204f5958)) +* Upgrade gradle to 7.4 ([#826](https://github.com/ionic-team/capacitor-plugins/issues/826)) ([5db0906](https://github.com/ionic-team/capacitor-plugins/commit/5db0906f6264287c4f8e69dbaecf19d4d387824b)) +* Use java 11 ([#910](https://github.com/ionic-team/capacitor-plugins/issues/910)) ([5acb2a2](https://github.com/ionic-team/capacitor-plugins/commit/5acb2a288a413492b163e4e97da46a085d9e4be0)) + + + + + +## [4.0.1](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0...4.0.1) (2022-07-28) + +**Note:** Version bump only for package @capacitor/text-zoom + + + + + +# [4.0.0](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0-beta.2...4.0.0) (2022-07-27) + +**Note:** Version bump only for package @capacitor/text-zoom + + + + + +# [4.0.0-beta.2](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0-beta.0...4.0.0-beta.2) (2022-07-08) + +**Note:** Version bump only for package @capacitor/text-zoom + + + + + +# 4.0.0-beta.0 (2022-06-27) + + +### Bug Fixes + +* inline source code in esm map files ([#760](https://github.com/ionic-team/capacitor-plugins/issues/760)) ([a960489](https://github.com/ionic-team/capacitor-plugins/commit/a960489a19db0182b90d187a50deff9dfbe51038)) +* **text-zoom:** Lazy load iOS implementation ([#735](https://github.com/ionic-team/capacitor-plugins/issues/735)) ([5039a74](https://github.com/ionic-team/capacitor-plugins/commit/5039a747efa2bc36674c70bdd9dae4439165ab4d)) +* add es2017 lib to tsconfig ([#180](https://github.com/ionic-team/capacitor-plugins/issues/180)) ([2c3776c](https://github.com/ionic-team/capacitor-plugins/commit/2c3776c38ca025c5ee965dec10ccf1cdb6c02e2f)) +* better ignore rules for npm distribution ([#32](https://github.com/ionic-team/capacitor-plugins/issues/32)) ([b8d55b9](https://github.com/ionic-team/capacitor-plugins/commit/b8d55b9233e4ad7b8a1cd41110b4e580fc2a059f)) +* correct addListeners links ([#655](https://github.com/ionic-team/capacitor-plugins/issues/655)) ([f9871e7](https://github.com/ionic-team/capacitor-plugins/commit/f9871e7bd53478addb21155e148829f550c0e457)) +* remove postpublish scripts ([#656](https://github.com/ionic-team/capacitor-plugins/issues/656)) ([ed6ac49](https://github.com/ionic-team/capacitor-plugins/commit/ed6ac499ebf4a47525071ccbfc36c27503e11f60)) +* support deprecated types from Capacitor 2 ([#139](https://github.com/ionic-team/capacitor-plugins/issues/139)) ([2d7127a](https://github.com/ionic-team/capacitor-plugins/commit/2d7127a488e26f0287951921a6db47c49d817336)) +* use correct package in manifest files ([#22](https://github.com/ionic-team/capacitor-plugins/issues/22)) ([ab62987](https://github.com/ionic-team/capacitor-plugins/commit/ab629877e1951f944594f1b23e1bffefcbc783dd)) + + +### Features + +* add commonjs output format ([#179](https://github.com/ionic-team/capacitor-plugins/issues/179)) ([8e9e098](https://github.com/ionic-team/capacitor-plugins/commit/8e9e09862064b3f6771d7facbc4008e995d9b463)) +* set targetSDK default value to 31 ([#824](https://github.com/ionic-team/capacitor-plugins/issues/824)) ([3ee10de](https://github.com/ionic-team/capacitor-plugins/commit/3ee10de98067984c1a4e75295d001c5a895c47f4)) +* set targetSDK default value to 32 ([#970](https://github.com/ionic-team/capacitor-plugins/issues/970)) ([fa70d96](https://github.com/ionic-team/capacitor-plugins/commit/fa70d96f141af751aae53ceb5642c46b204f5958)) +* Text Zoom plugin ([#9](https://github.com/ionic-team/capacitor-plugins/issues/9)) ([cc18d0f](https://github.com/ionic-team/capacitor-plugins/commit/cc18d0fb1b6f4509d95a4114c92255d8d7873311)) +* Upgrade gradle to 7.4 ([#826](https://github.com/ionic-team/capacitor-plugins/issues/826)) ([5db0906](https://github.com/ionic-team/capacitor-plugins/commit/5db0906f6264287c4f8e69dbaecf19d4d387824b)) +* Use java 11 ([#910](https://github.com/ionic-team/capacitor-plugins/issues/910)) ([5acb2a2](https://github.com/ionic-team/capacitor-plugins/commit/5acb2a288a413492b163e4e97da46a085d9e4be0)) + + + + + ## [1.0.8](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/text-zoom@1.0.7...@capacitor/text-zoom@1.0.8) (2022-01-19) diff --git a/text-zoom/CapacitorTextZoom.podspec b/text-zoom/CapacitorTextZoom.podspec index 219d7e53c..306d82054 100644 --- a/text-zoom/CapacitorTextZoom.podspec +++ b/text-zoom/CapacitorTextZoom.podspec @@ -11,7 +11,7 @@ Pod::Spec.new do |s| s.author = package['author'] s.source = { :git => 'https://github.com/ionic-team/capacitor-plugins.git', :tag => package['name'] + '@' + package['version'] } s.source_files = 'ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}', 'text-zoom/ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}' - s.ios.deployment_target = '12.0' + s.ios.deployment_target = '13.0' s.dependency 'Capacitor' s.swift_version = '5.1' end diff --git a/text-zoom/README.md b/text-zoom/README.md index 6b5cef094..cfba1875f 100644 --- a/text-zoom/README.md +++ b/text-zoom/README.md @@ -2,6 +2,16 @@ The Text Zoom API provides the ability to change Web View text size for visual accessibility. +**Note:** text-zoom plugin won't work on iPads unless `preferredContentMode` configuration is set to `mobile` in your [Capacitor configuration file](https://capacitorjs.com/docs/config). + +```json +{ + "ios": { + "preferredContentMode": "mobile" + } +} +``` + ## Install ```bash diff --git a/text-zoom/android/build.gradle b/text-zoom/android/build.gradle index 56ee0b28b..43252f49c 100644 --- a/text-zoom/android/build.gradle +++ b/text-zoom/android/build.gradle @@ -1,27 +1,39 @@ ext { - junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.1' - androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.2.0' - androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.1.2' - androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.3.0' + capacitorVersion = System.getenv('CAPACITOR_VERSION') + junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.2' + androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.4.2' + androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.1.3' + androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.4.0' } buildscript { repositories { google() mavenCentral() + maven { + url "https://plugins.gradle.org/m2/" + } } dependencies { - classpath 'com.android.tools.build:gradle:4.2.1' + classpath 'com.android.tools.build:gradle:7.2.1' + if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + classpath 'io.github.gradle-nexus:publish-plugin:1.1.0' + } } } apply plugin: 'com.android.library' +if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + apply plugin: 'io.github.gradle-nexus.publish-plugin' + apply from: file('../../scripts/android/publish-root.gradle') + apply from: file('../../scripts/android/publish-module.gradle') +} android { - compileSdkVersion project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 30 + compileSdkVersion project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 32 defaultConfig { - minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 21 - targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 30 + minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 22 + targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 32 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" @@ -36,21 +48,26 @@ android { abortOnError false } compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility JavaVersion.VERSION_11 + targetCompatibility JavaVersion.VERSION_11 } } repositories { google() mavenCentral() - jcenter() } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation project(':capacitor-android') + + if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + implementation "com.capacitorjs:core:$capacitorVersion" + } else { + implementation project(':capacitor-android') + } + implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion" testImplementation "junit:junit:$junitVersion" androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion" diff --git a/text-zoom/android/gradle/wrapper/gradle-wrapper.jar b/text-zoom/android/gradle/wrapper/gradle-wrapper.jar index e708b1c02..41d9927a4 100644 Binary files a/text-zoom/android/gradle/wrapper/gradle-wrapper.jar and b/text-zoom/android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/text-zoom/android/gradle/wrapper/gradle-wrapper.properties b/text-zoom/android/gradle/wrapper/gradle-wrapper.properties index 3c4101c3e..92f06b50f 100644 --- a/text-zoom/android/gradle/wrapper/gradle-wrapper.properties +++ b/text-zoom/android/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/text-zoom/android/gradlew b/text-zoom/android/gradlew index 4f906e0c8..1b6c78733 100755 --- a/text-zoom/android/gradlew +++ b/text-zoom/android/gradlew @@ -1,7 +1,7 @@ -#!/usr/bin/env sh +#!/bin/sh # -# Copyright 2015 the original author or authors. +# Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,67 +17,101 @@ # ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` +APP_BASE_NAME=${0##*/} # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar @@ -87,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -98,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" + JAVACMD=java which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the @@ -106,80 +140,95 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=`expr $i + 1` + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" diff --git a/text-zoom/ios/Plugin.xcodeproj/project.pbxproj b/text-zoom/ios/Plugin.xcodeproj/project.pbxproj index 8ac3338c6..27b259ab1 100644 --- a/text-zoom/ios/Plugin.xcodeproj/project.pbxproj +++ b/text-zoom/ios/Plugin.xcodeproj/project.pbxproj @@ -386,7 +386,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -446,7 +446,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; @@ -469,12 +469,13 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Plugin/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks $(FRAMEWORK_SEARCH_PATHS)\n$(FRAMEWORK_SEARCH_PATHS)\n$(FRAMEWORK_SEARCH_PATHS)"; ONLY_ACTIVE_ARCH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.getcapacitor.Plugin; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; + SUPPORTS_MACCATALYST = NO; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -494,12 +495,13 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Plugin/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks $(FRAMEWORK_SEARCH_PATHS)"; ONLY_ACTIVE_ARCH = NO; PRODUCT_BUNDLE_IDENTIFIER = com.getcapacitor.Plugin; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; + SUPPORTS_MACCATALYST = NO; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; diff --git a/text-zoom/ios/Podfile b/text-zoom/ios/Podfile index 54a00c161..dee40960f 100644 --- a/text-zoom/ios/Podfile +++ b/text-zoom/ios/Podfile @@ -1,4 +1,4 @@ -platform :ios, '12.0' +platform :ios, '13.0' def capacitor_pods # Comment the next line if you're not using Swift and don't want to use dynamic frameworks diff --git a/text-zoom/package.json b/text-zoom/package.json index 9e4504d27..e7afc7d88 100644 --- a/text-zoom/package.json +++ b/text-zoom/package.json @@ -1,6 +1,6 @@ { "name": "@capacitor/text-zoom", - "version": "1.0.8", + "version": "4.1.0", "description": "The Text Zoom API provides the ability to change Web View text size for visual accessibility.", "main": "dist/plugin.cjs.js", "module": "dist/esm/index.js", @@ -29,7 +29,7 @@ ], "scripts": { "verify": "npm run verify:ios && npm run verify:android && npm run verify:web", - "verify:ios": "cd ios && pod install && xcodebuild -workspace Plugin.xcworkspace -scheme Plugin && cd ..", + "verify:ios": "cd ios && pod install && xcodebuild -workspace Plugin.xcworkspace -scheme Plugin -destination generic/platform=iOS && cd ..", "verify:android": "cd android && ./gradlew clean build test && cd ..", "verify:web": "npm run build", "lint": "npm run eslint && npm run prettier -- --check && npm run swiftlint -- lint", @@ -45,10 +45,10 @@ "publish:cocoapod": "pod trunk push ./CapacitorTextZoom.podspec --allow-warnings" }, "devDependencies": { - "@capacitor/android": "^3.0.0", - "@capacitor/core": "^3.0.0", - "@capacitor/docgen": "0.0.18", - "@capacitor/ios": "^3.0.0", + "@capacitor/android": "^4.0.0", + "@capacitor/core": "^4.0.0", + "@capacitor/docgen": "0.2.0", + "@capacitor/ios": "^4.0.0", "@ionic/eslint-config": "^0.3.0", "@ionic/prettier-config": "~1.0.1", "@ionic/swiftlint-config": "^1.1.2", @@ -61,7 +61,7 @@ "typescript": "~4.1.5" }, "peerDependencies": { - "@capacitor/core": "^3.0.0" + "@capacitor/core": "^4.0.0" }, "prettier": "@ionic/prettier-config", "swiftlint": "@ionic/swiftlint-config", diff --git a/toast/CHANGELOG.md b/toast/CHANGELOG.md index 38bfd3b66..dbc3d9cad 100644 --- a/toast/CHANGELOG.md +++ b/toast/CHANGELOG.md @@ -3,6 +3,93 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.1.0](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/toast@1.0.8...@capacitor/toast@4.1.0) (2022-11-16) + + + +## 4.0.1 (2022-07-28) + + + +# 4.0.0 (2022-07-27) + + + +# 4.0.0-beta.2 (2022-07-08) + + + +# 4.0.0-beta.0 (2022-06-27) + + +### Features + +* set targetSDK default value to 31 ([#824](https://github.com/ionic-team/capacitor-plugins/issues/824)) ([3ee10de](https://github.com/ionic-team/capacitor-plugins/commit/3ee10de98067984c1a4e75295d001c5a895c47f4)) +* set targetSDK default value to 32 ([#970](https://github.com/ionic-team/capacitor-plugins/issues/970)) ([fa70d96](https://github.com/ionic-team/capacitor-plugins/commit/fa70d96f141af751aae53ceb5642c46b204f5958)) +* Upgrade gradle to 7.4 ([#826](https://github.com/ionic-team/capacitor-plugins/issues/826)) ([5db0906](https://github.com/ionic-team/capacitor-plugins/commit/5db0906f6264287c4f8e69dbaecf19d4d387824b)) +* Use java 11 ([#910](https://github.com/ionic-team/capacitor-plugins/issues/910)) ([5acb2a2](https://github.com/ionic-team/capacitor-plugins/commit/5acb2a288a413492b163e4e97da46a085d9e4be0)) + + + + + +## [4.0.1](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0...4.0.1) (2022-07-28) + +**Note:** Version bump only for package @capacitor/toast + + + + + +# [4.0.0](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0-beta.2...4.0.0) (2022-07-27) + +**Note:** Version bump only for package @capacitor/toast + + + + + +# [4.0.0-beta.2](https://github.com/ionic-team/capacitor-plugins/compare/4.0.0-beta.0...4.0.0-beta.2) (2022-07-08) + +**Note:** Version bump only for package @capacitor/toast + + + + + +# 4.0.0-beta.0 (2022-06-27) + + +### Bug Fixes + +* add es2017 lib to tsconfig ([#180](https://github.com/ionic-team/capacitor-plugins/issues/180)) ([2c3776c](https://github.com/ionic-team/capacitor-plugins/commit/2c3776c38ca025c5ee965dec10ccf1cdb6c02e2f)) +* correct addListeners links ([#655](https://github.com/ionic-team/capacitor-plugins/issues/655)) ([f9871e7](https://github.com/ionic-team/capacitor-plugins/commit/f9871e7bd53478addb21155e148829f550c0e457)) +* inline source code in esm map files ([#760](https://github.com/ionic-team/capacitor-plugins/issues/760)) ([a960489](https://github.com/ionic-team/capacitor-plugins/commit/a960489a19db0182b90d187a50deff9dfbe51038)) +* remove postpublish scripts ([#656](https://github.com/ionic-team/capacitor-plugins/issues/656)) ([ed6ac49](https://github.com/ionic-team/capacitor-plugins/commit/ed6ac499ebf4a47525071ccbfc36c27503e11f60)) +* support deprecated types from Capacitor 2 ([#139](https://github.com/ionic-team/capacitor-plugins/issues/139)) ([2d7127a](https://github.com/ionic-team/capacitor-plugins/commit/2d7127a488e26f0287951921a6db47c49d817336)) + + +### Features + +* add commonjs output format ([#179](https://github.com/ionic-team/capacitor-plugins/issues/179)) ([8e9e098](https://github.com/ionic-team/capacitor-plugins/commit/8e9e09862064b3f6771d7facbc4008e995d9b463)) +* set targetSDK default value to 31 ([#824](https://github.com/ionic-team/capacitor-plugins/issues/824)) ([3ee10de](https://github.com/ionic-team/capacitor-plugins/commit/3ee10de98067984c1a4e75295d001c5a895c47f4)) +* set targetSDK default value to 32 ([#970](https://github.com/ionic-team/capacitor-plugins/issues/970)) ([fa70d96](https://github.com/ionic-team/capacitor-plugins/commit/fa70d96f141af751aae53ceb5642c46b204f5958)) +* Toast plugin ([#52](https://github.com/ionic-team/capacitor-plugins/issues/52)) ([b52dc47](https://github.com/ionic-team/capacitor-plugins/commit/b52dc471291bcf6ad54ed1ffde6ecf3327ecd747)) +* Upgrade gradle to 7.4 ([#826](https://github.com/ionic-team/capacitor-plugins/issues/826)) ([5db0906](https://github.com/ionic-team/capacitor-plugins/commit/5db0906f6264287c4f8e69dbaecf19d4d387824b)) +* Use java 11 ([#910](https://github.com/ionic-team/capacitor-plugins/issues/910)) ([5acb2a2](https://github.com/ionic-team/capacitor-plugins/commit/5acb2a288a413492b163e4e97da46a085d9e4be0)) + + + + + +## [1.0.8](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/toast@1.0.7...@capacitor/toast@1.0.8) (2022-02-10) + +**Note:** Version bump only for package @capacitor/toast + + + + + ## [1.0.7](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/toast@1.0.6...@capacitor/toast@1.0.7) (2022-01-19) diff --git a/toast/CapacitorToast.podspec b/toast/CapacitorToast.podspec index 8802cf9f2..b4c023d5c 100644 --- a/toast/CapacitorToast.podspec +++ b/toast/CapacitorToast.podspec @@ -11,7 +11,7 @@ Pod::Spec.new do |s| s.author = package['author'] s.source = { :git => 'https://github.com/ionic-team/capacitor-plugins.git', :tag => package['name'] + '@' + package['version'] } s.source_files = 'ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}', 'toast/ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}' - s.ios.deployment_target = '12.0' + s.ios.deployment_target = '13.0' s.dependency 'Capacitor' s.swift_version = '5.1' end diff --git a/toast/README.md b/toast/README.md index 0c9d411c5..4a0053dd0 100644 --- a/toast/README.md +++ b/toast/README.md @@ -9,6 +9,10 @@ npm install @capacitor/toast npx cap sync ``` +## PWA Notes + +[PWA Elements](https://capacitorjs.com/docs/web/pwa-elements) are required for the Toast plugin to work. + ## Example ```typescript @@ -55,10 +59,10 @@ Shows a Toast on the screen #### ShowOptions -| Prop | Type | Description | Default | Since | -| -------------- | ------------------------------------------ | ----------------------------------------------------------------- | --------------------- | ----- | -| **`text`** | string | Text to display on the Toast | | 1.0.0 | -| **`duration`** | 'short' \| 'long' | Duration of the Toast, either 'short' (2000ms) or 'long' (3500ms) | 'short' | 1.0.0 | -| **`position`** | 'top' \| 'center' \| 'bottom' | Postion of the Toast | 'bottom' | 1.0.0 | +| Prop | Type | Description | Default | Since | +| -------------- | ------------------------------------------ | ---------------------------------------------------------------------------------- | --------------------- | ----- | +| **`text`** | string | Text to display on the Toast | | 1.0.0 | +| **`duration`** | 'short' \| 'long' | Duration of the Toast, either 'short' (2000ms) or 'long' (3500ms) | 'short' | 1.0.0 | +| **`position`** | 'top' \| 'center' \| 'bottom' | Position of the Toast. On Android 12 and newer all toasts are shown at the bottom. | 'bottom' | 1.0.0 | diff --git a/toast/android/build.gradle b/toast/android/build.gradle index 56ee0b28b..43252f49c 100644 --- a/toast/android/build.gradle +++ b/toast/android/build.gradle @@ -1,27 +1,39 @@ ext { - junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.1' - androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.2.0' - androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.1.2' - androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.3.0' + capacitorVersion = System.getenv('CAPACITOR_VERSION') + junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.2' + androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.4.2' + androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.1.3' + androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.4.0' } buildscript { repositories { google() mavenCentral() + maven { + url "https://plugins.gradle.org/m2/" + } } dependencies { - classpath 'com.android.tools.build:gradle:4.2.1' + classpath 'com.android.tools.build:gradle:7.2.1' + if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + classpath 'io.github.gradle-nexus:publish-plugin:1.1.0' + } } } apply plugin: 'com.android.library' +if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + apply plugin: 'io.github.gradle-nexus.publish-plugin' + apply from: file('../../scripts/android/publish-root.gradle') + apply from: file('../../scripts/android/publish-module.gradle') +} android { - compileSdkVersion project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 30 + compileSdkVersion project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 32 defaultConfig { - minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 21 - targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 30 + minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 22 + targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 32 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" @@ -36,21 +48,26 @@ android { abortOnError false } compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility JavaVersion.VERSION_11 + targetCompatibility JavaVersion.VERSION_11 } } repositories { google() mavenCentral() - jcenter() } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation project(':capacitor-android') + + if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") { + implementation "com.capacitorjs:core:$capacitorVersion" + } else { + implementation project(':capacitor-android') + } + implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion" testImplementation "junit:junit:$junitVersion" androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion" diff --git a/toast/android/gradle/wrapper/gradle-wrapper.jar b/toast/android/gradle/wrapper/gradle-wrapper.jar index e708b1c02..41d9927a4 100644 Binary files a/toast/android/gradle/wrapper/gradle-wrapper.jar and b/toast/android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/toast/android/gradle/wrapper/gradle-wrapper.properties b/toast/android/gradle/wrapper/gradle-wrapper.properties index 3c4101c3e..92f06b50f 100644 --- a/toast/android/gradle/wrapper/gradle-wrapper.properties +++ b/toast/android/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/toast/android/gradlew b/toast/android/gradlew index 4f906e0c8..1b6c78733 100755 --- a/toast/android/gradlew +++ b/toast/android/gradlew @@ -1,7 +1,7 @@ -#!/usr/bin/env sh +#!/bin/sh # -# Copyright 2015 the original author or authors. +# Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,67 +17,101 @@ # ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` +APP_BASE_NAME=${0##*/} # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar @@ -87,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -98,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" + JAVACMD=java which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the @@ -106,80 +140,95 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=`expr $i + 1` + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" diff --git a/toast/ios/Plugin.xcodeproj/project.pbxproj b/toast/ios/Plugin.xcodeproj/project.pbxproj index f7dcc2265..b5e8554e4 100644 --- a/toast/ios/Plugin.xcodeproj/project.pbxproj +++ b/toast/ios/Plugin.xcodeproj/project.pbxproj @@ -390,7 +390,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -450,7 +450,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; @@ -473,12 +473,13 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Plugin/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks $(FRAMEWORK_SEARCH_PATHS)\n$(FRAMEWORK_SEARCH_PATHS)\n$(FRAMEWORK_SEARCH_PATHS)"; ONLY_ACTIVE_ARCH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.getcapacitor.Plugin; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; + SUPPORTS_MACCATALYST = NO; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -498,12 +499,13 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Plugin/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks $(FRAMEWORK_SEARCH_PATHS)"; ONLY_ACTIVE_ARCH = NO; PRODUCT_BUNDLE_IDENTIFIER = com.getcapacitor.Plugin; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; + SUPPORTS_MACCATALYST = NO; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; diff --git a/toast/ios/Podfile b/toast/ios/Podfile index 54a00c161..dee40960f 100644 --- a/toast/ios/Podfile +++ b/toast/ios/Podfile @@ -1,4 +1,4 @@ -platform :ios, '12.0' +platform :ios, '13.0' def capacitor_pods # Comment the next line if you're not using Swift and don't want to use dynamic frameworks diff --git a/toast/package.json b/toast/package.json index fa0241570..f4cb48f18 100644 --- a/toast/package.json +++ b/toast/package.json @@ -1,6 +1,6 @@ { "name": "@capacitor/toast", - "version": "1.0.7", + "version": "4.1.0", "description": "The Toast API provides a notification pop up for displaying important information to a user. Just like real toast!", "main": "dist/plugin.cjs.js", "module": "dist/esm/index.js", @@ -29,7 +29,7 @@ ], "scripts": { "verify": "npm run verify:ios && npm run verify:android && npm run verify:web", - "verify:ios": "cd ios && pod install && xcodebuild -workspace Plugin.xcworkspace -scheme Plugin && cd ..", + "verify:ios": "cd ios && pod install && xcodebuild -workspace Plugin.xcworkspace -scheme Plugin -destination generic/platform=iOS && cd ..", "verify:android": "cd android && ./gradlew clean build test && cd ..", "verify:web": "npm run build", "lint": "npm run eslint && npm run prettier -- --check && npm run swiftlint -- lint", @@ -45,10 +45,10 @@ "publish:cocoapod": "pod trunk push ./CapacitorToast.podspec --allow-warnings" }, "devDependencies": { - "@capacitor/android": "^3.0.0", - "@capacitor/core": "^3.0.0", - "@capacitor/docgen": "0.0.18", - "@capacitor/ios": "^3.0.0", + "@capacitor/android": "^4.0.0", + "@capacitor/core": "^4.0.0", + "@capacitor/docgen": "0.2.0", + "@capacitor/ios": "^4.0.0", "@ionic/eslint-config": "^0.3.0", "@ionic/prettier-config": "~1.0.1", "@ionic/swiftlint-config": "^1.1.2", @@ -61,7 +61,7 @@ "typescript": "~4.1.5" }, "peerDependencies": { - "@capacitor/core": "^3.0.0" + "@capacitor/core": "^4.0.0" }, "prettier": "@ionic/prettier-config", "swiftlint": "@ionic/swiftlint-config", diff --git a/toast/src/definitions.ts b/toast/src/definitions.ts index c30808774..bd9d3ebec 100644 --- a/toast/src/definitions.ts +++ b/toast/src/definitions.ts @@ -24,7 +24,9 @@ export interface ShowOptions { duration?: 'short' | 'long'; /** - * Postion of the Toast + * Position of the Toast. + * + * On Android 12 and newer all toasts are shown at the bottom. * * @default 'bottom' * @since 1.0.0