├── .eslintignore
├── .github
├── CODEOWNERS
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
├── PULL_REQUEST_TEMPLATE.md
└── workflows
│ ├── ci.yml
│ ├── lock.yml
│ ├── needs-reply-remove.yml
│ ├── needs-reply.yml
│ └── needs-triage.yml
├── .gitignore
├── .npmrc
├── .prettierignore
├── CHANGELOG.md
├── CONTRIBUTING.md
├── CapacitorCommunitySpeechRecognition.podspec
├── LICENSE
├── README.md
├── android
├── .npmignore
├── build.gradle
├── gradle.properties
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── proguard-rules.pro
├── settings.gradle
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── getcapacitor
│ │ └── android
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── getcapacitor
│ │ │ └── community
│ │ │ └── speechrecognition
│ │ │ ├── Constants.java
│ │ │ ├── Receiver.java
│ │ │ └── SpeechRecognition.java
│ └── res
│ │ ├── layout
│ │ └── bridge_layout_main.xml
│ │ └── values
│ │ ├── colors.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── com
│ └── getcapacitor
│ └── ExampleUnitTest.java
├── ios
├── Plugin.xcodeproj
│ └── project.pbxproj
├── Plugin.xcworkspace
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
├── Plugin
│ ├── Info.plist
│ ├── Plugin.h
│ ├── Plugin.m
│ └── Plugin.swift
├── PluginTests
│ ├── Info.plist
│ └── PluginTests.swift
└── Podfile
├── package-lock.json
├── package.json
├── rollup.config.mjs
├── src
├── definitions.ts
├── index.ts
└── web.ts
└── tsconfig.json
/.eslintignore:
--------------------------------------------------------------------------------
1 | build
2 | dist
3 |
--------------------------------------------------------------------------------
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners
2 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: "bug: "
5 | labels: ""
6 | assignees: ""
7 | ---
8 |
9 | **Plugin version:**
10 |
11 |
12 |
13 |
14 | **Platform(s):**
15 |
16 |
17 |
18 |
19 | **Current behavior:**
20 |
21 |
22 |
23 |
24 | **Expected behavior:**
25 |
26 |
27 |
28 |
29 | **Steps to reproduce:**
30 |
31 |
32 |
33 |
34 | **Related code:**
35 |
36 |
37 | ```
38 | insert short code snippets here
39 | ```
40 |
41 | **Other information:**
42 |
43 |
44 |
45 |
46 | **Capacitor doctor:**
47 |
48 |
49 | ```
50 | insert the output from `npx cap doctor` here
51 | ```
52 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: "feat: "
5 | labels: ""
6 | assignees: ""
7 | ---
8 |
9 | **Is your feature request related to a problem? Please describe:**
10 |
11 |
12 |
13 |
14 | **Describe the solution you'd like:**
15 |
16 |
17 |
18 |
19 | **Describe alternatives you've considered:**
20 |
21 |
22 |
23 |
24 | **Additional context:**
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | ## Pull request checklist
2 |
3 | Please check if your PR fulfills the following requirements:
4 |
5 | - [ ] The changes have been tested successfully.
6 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on:
4 | push:
5 | branches:
6 | - master
7 | paths-ignore:
8 | - "**.md"
9 | - ".vscode/**"
10 | pull_request:
11 | paths-ignore:
12 | - "**.md"
13 | - ".vscode/**"
14 | workflow_dispatch:
15 |
16 | env:
17 | NODE_VERSION: 18
18 | JAVA_VERSION: 21
19 |
20 | jobs:
21 | build:
22 | name: Build
23 | runs-on: macos-14
24 | steps:
25 | - name: Checkout
26 | uses: actions/checkout@v4
27 | - name: Set up Node.js ${{ env.NODE_VERSION }}
28 | uses: actions/setup-node@v4
29 | with:
30 | node-version: ${{ env.NODE_VERSION }}
31 | - name: Set up Java ${{ env.JAVA_VERSION }}
32 | uses: actions/setup-java@v4
33 | with:
34 | distribution: 'zulu'
35 | java-version: ${{ env.JAVA_VERSION }}
36 | - name: Install dependencies
37 | run: npm ci
38 | - name: Build iOS
39 | run: npm run verify:ios
40 | - name: Build Android
41 | run: npm run verify:android
42 | - name: Build Web
43 | run: npm run verify:web
44 | - name: Upload artifacts
45 | uses: actions/upload-artifact@v4
46 | with:
47 | name: dist
48 | path: dist
49 | lint:
50 | name: Lint
51 | runs-on: macos-latest
52 | steps:
53 | - name: Checkout
54 | uses: actions/checkout@v4
55 | - name: Set up Node.js ${{ env.NODE_VERSION }}
56 | uses: actions/setup-node@v4
57 | with:
58 | node-version: ${{ env.NODE_VERSION }}
59 | - name: Install dependencies
60 | run: npm ci
61 | - name: Run Lint script
62 | run: npm run lint
63 |
--------------------------------------------------------------------------------
/.github/workflows/lock.yml:
--------------------------------------------------------------------------------
1 | name: Lock old issues and pull requests that are closed
2 |
3 | on:
4 | schedule:
5 | - cron: '0 18 * * *'
6 | workflow_dispatch:
7 |
8 | permissions:
9 | issues: write
10 | pull-requests: write
11 |
12 | concurrency:
13 | group: lock
14 |
15 | jobs:
16 | action:
17 | runs-on: ubuntu-latest
18 | steps:
19 | - uses: dessant/lock-threads@v3
20 | with:
21 | issue-inactive-days: '56'
22 |
--------------------------------------------------------------------------------
/.github/workflows/needs-reply-remove.yml:
--------------------------------------------------------------------------------
1 | name: Remove needs-reply label
2 |
3 | on:
4 | issue_comment:
5 | types:
6 | - created
7 |
8 | jobs:
9 | needs-reply:
10 | runs-on: ubuntu-latest
11 | steps:
12 | - name: Remove needs-reply label
13 | run: |
14 | curl --request DELETE \
15 | --url 'https://api.github.com/repos/${{ github.repository }}/issues/${{ github.event.issue.number }}/labels/needs%3A%20reply' \
16 | --header 'Authorization: token ${{ secrets.GITHUB_TOKEN }}'
17 |
--------------------------------------------------------------------------------
/.github/workflows/needs-reply.yml:
--------------------------------------------------------------------------------
1 | name: Close old issues that need reply
2 |
3 | on:
4 | schedule:
5 | - cron: '0 0 * * *'
6 | workflow_dispatch:
7 |
8 | jobs:
9 | needs-reply:
10 | runs-on: ubuntu-latest
11 | steps:
12 | - name: Close old issues that need reply
13 | uses: dwieeb/needs-reply@v2
14 | with:
15 | repo-token: ${{ secrets.GITHUB_TOKEN }}
16 | issue-label: 'needs: reply'
17 |
--------------------------------------------------------------------------------
/.github/workflows/needs-triage.yml:
--------------------------------------------------------------------------------
1 | name: Add needs-triage label
2 |
3 | on:
4 | issues:
5 | types:
6 | - opened
7 |
8 | jobs:
9 | needs-triage:
10 | runs-on: ubuntu-latest
11 | steps:
12 | - name: Add needs-triage label
13 | if: join(github.event.issue.labels) == ''
14 | run: |
15 | curl --request POST \
16 | --url 'https://api.github.com/repos/${{ github.repository }}/issues/${{ github.event.issue.number }}/labels' \
17 | --header 'Authorization: token ${{ secrets.GITHUB_TOKEN }}' \
18 | --header 'Content-Type: application/json' \
19 | --header 'Accept: application/vnd.github.v3+json' \
20 | --data-raw '{ "labels": ["needs: triage"] }'
21 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # node files
2 | dist
3 | node_modules
4 |
5 | # iOS files
6 | Pods
7 | Podfile.lock
8 | Build
9 | xcuserdata
10 |
11 | # macOS files
12 | .DS_Store
13 |
14 |
15 |
16 | # Based on Android gitignore template: https://github.com/github/gitignore/blob/HEAD/Android.gitignore
17 |
18 | # Built application files
19 | *.apk
20 | *.ap_
21 |
22 | # Files for the ART/Dalvik VM
23 | *.dex
24 |
25 | # Java class files
26 | *.class
27 |
28 | # Generated files
29 | bin
30 | gen
31 | out
32 |
33 | # Gradle files
34 | .gradle
35 | build
36 |
37 | # Local configuration file (sdk path, etc)
38 | local.properties
39 |
40 | # Proguard folder generated by Eclipse
41 | proguard
42 |
43 | # Log Files
44 | *.log
45 |
46 | # Android Studio Navigation editor temp files
47 | .navigation
48 |
49 | # Android Studio captures folder
50 | captures
51 |
52 | # IntelliJ
53 | *.iml
54 | .idea
55 |
56 | # Keystore files
57 | # Uncomment the following line if you do not want to check your keystore files in.
58 | #*.jks
59 |
60 | # External native build folder generated in Android Studio 2.2 and later
61 | .externalNativeBuild
62 |
63 | # VSCode
64 | .vscode/settings.json
65 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | save-exact=true
2 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | build
2 | dist
3 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4 |
5 | ### [7.0.1](https://github.com/capacitor-community/speech-recognition/compare/v7.0.0...v7.0.1) (2025-06-09)
6 |
7 |
8 | ### Bug Fixes
9 |
10 | * gracefully handle AVAudioSession conflict when mic is busy ([#116](https://github.com/capacitor-community/speech-recognition/issues/116)) ([36cc033](https://github.com/capacitor-community/speech-recognition/commit/36cc0333c69ab676eb057f81cec2e9be22398cc9))
11 |
12 | ## [7.0.0](https://github.com/capacitor-community/speech-recognition/compare/v6.0.1...v7.0.0) (2025-03-25)
13 |
14 |
15 | ### ⚠ BREAKING CHANGES
16 |
17 | * This plugin now only supports Capacitor 7.
18 |
19 | ### Features
20 |
21 | * update to Capacitor 7 ([#114](https://github.com/capacitor-community/speech-recognition/issues/114)) ([bb13bee](https://github.com/capacitor-community/speech-recognition/commit/bb13beec20410b6d3b2e4192cf9fa14cc55c3360))
22 |
23 | ### [6.0.1](https://github.com/capacitor-community/speech-recognition/compare/v6.0.0...v6.0.1) (2024-06-28)
24 |
25 |
26 | ### Bug Fixes
27 |
28 | * **ios:** proper isListening return ([#103](https://github.com/capacitor-community/speech-recognition/issues/103)) ([daf40a7](https://github.com/capacitor-community/speech-recognition/commit/daf40a73fda9b1caa5e84df41bf15ff687617742))
29 |
30 | ## [6.0.0](https://github.com/capacitor-community/speech-recognition/compare/v5.1.0...v6.0.0) (2024-06-07)
31 |
32 |
33 | ### ⚠ BREAKING CHANGES
34 |
35 | * Remove deprecated permission methods (#94)
36 | * Update to Capacitor 6 (#86)
37 | * use correct name on rollup (#93)
38 |
39 | ### Features
40 |
41 | * Remove deprecated permission methods ([#94](https://github.com/capacitor-community/speech-recognition/issues/94)) ([77d89b8](https://github.com/capacitor-community/speech-recognition/commit/77d89b86117a9e1adc88abfafc8c9327ea5fef8d))
42 | * Update to Capacitor 6 ([#86](https://github.com/capacitor-community/speech-recognition/issues/86)) ([8e2f62b](https://github.com/capacitor-community/speech-recognition/commit/8e2f62b5ed37fdb8acf33c31b4e7157d03a47739))
43 |
44 |
45 | ### Bug Fixes
46 |
47 | * correct since for isListening and listeningState ([#92](https://github.com/capacitor-community/speech-recognition/issues/92)) ([8b9445c](https://github.com/capacitor-community/speech-recognition/commit/8b9445caf09093422d761c6b3f91ed330d273047))
48 | * **ios:** add missing listeningState stopped cases ([#95](https://github.com/capacitor-community/speech-recognition/issues/95)) ([19f98d1](https://github.com/capacitor-community/speech-recognition/commit/19f98d13b6a9454373a7d1af57e83f49fa823174))
49 | * use correct name on rollup ([#93](https://github.com/capacitor-community/speech-recognition/issues/93)) ([d8fefbc](https://github.com/capacitor-community/speech-recognition/commit/d8fefbc13594c7949e3bc687355c7308d9f90d8d))
50 |
51 | ## [5.1.0](https://github.com/capacitor-community/speech-recognition/compare/v5.0.0...v5.1.0) (2024-03-27)
52 |
53 |
54 | ### Features
55 |
56 | * add `isListening` method and `listeningState` listener ([#83](https://github.com/capacitor-community/speech-recognition/issues/83)) ([5a9b532](https://github.com/capacitor-community/speech-recognition/commit/5a9b532f316df7585b94e65bff77b642df5eb32e))
57 |
58 | # Changelog
59 |
60 | All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
61 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | This guide provides instructions for contributing to this Capacitor plugin.
4 |
5 | ## Developing
6 |
7 | ### Local Setup
8 |
9 | 1. Fork and clone the repo.
10 | 2. Install the dependencies.
11 |
12 | ```shell
13 | npm install
14 | ```
15 |
16 | 3. Install SwiftLint if you're on macOS.
17 |
18 | ```shell
19 | brew install swiftlint
20 | ```
21 |
22 | ### Scripts
23 |
24 | #### `npm run build`
25 |
26 | Build the plugin web assets and generate plugin API documentation using [`@capacitor/docgen`](https://github.com/ionic-team/capacitor-docgen).
27 |
28 | It will compile the TypeScript code from `src/` into ESM JavaScript in `dist/esm/`. These files are used in apps with bundlers when your plugin is imported.
29 |
30 | Then, Rollup will bundle the code into a single file at `dist/plugin.js`. This file is used in apps without bundlers by including it as a script in `index.html`.
31 |
32 | #### `npm run verify`
33 |
34 | Build and validate the web and native projects.
35 |
36 | This is useful to run in CI to verify that the plugin builds for all platforms.
37 |
38 | #### `npm run lint` / `npm run fmt`
39 |
40 | Check formatting and code quality, autoformat/autofix if possible.
41 |
42 | This template is integrated with ESLint, Prettier, and SwiftLint. Using these tools is completely optional, but the [Capacitor Community](https://github.com/capacitor-community/) strives to have consistent code style and structure for easier cooperation.
43 |
44 | ## Versioning
45 |
46 | Don't change the plugin version manually, the version change is automated with `standard-version` package.
47 |
48 | ## Publishing
49 |
50 | First run:
51 |
52 | ```shell
53 | npm run release
54 | ```
55 |
56 | That will update the plugin version and update the `CHANGELOG.md` file with latest changes. Then it will ask you to run:
57 |
58 | ```shell
59 | git push --follow-tags origin master && npm publish
60 | ```
61 |
62 | That creates a tag on gitbhub and publishes the package on npm.
63 |
64 | Go to the [github tags section](https://github.com/capacitor-community/speech-recognition/tags), pick the latest tag and create a release for it.
65 |
66 | > **Note**: The [`files`](https://docs.npmjs.com/cli/v7/configuring-npm/package-json#files) array in `package.json` specifies which files get published. If you rename files/directories or add files elsewhere, you may need to update it.
67 |
--------------------------------------------------------------------------------
/CapacitorCommunitySpeechRecognition.podspec:
--------------------------------------------------------------------------------
1 | require 'json'
2 |
3 | package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
4 |
5 | Pod::Spec.new do |s|
6 | s.name = 'CapacitorCommunitySpeechRecognition'
7 | s.version = package['version']
8 | s.summary = package['description']
9 | s.license = package['license']
10 | s.homepage = package['repository']['url']
11 | s.author = package['author']
12 | s.source = { :git => package['repository']['url'], :tag => s.version.to_s }
13 | s.source_files = 'ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}'
14 | s.ios.deployment_target = '14.0'
15 | s.dependency 'Capacitor'
16 | s.swift_version = '5.1'
17 | end
18 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) COPYRIGHT_YEAR COPYRIGHT_HOLDER
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Capacitor Speech Recognition Plugin
2 |
3 | Capacitor community plugin for speech recognition.
4 |
5 | ## Maintainers
6 |
7 | | Maintainer | GitHub | Social |
8 | | --------------- | ------------------------------------------- | ------------------------------------------------ |
9 | | Priyank Patel | [priyankpat](https://github.com/priyankpat) | [@priyankpat\_](https://twitter.com/priyankpat_) |
10 | | Matteo Padovano | [mrbatista](https://github.com/mrbatista) | [@mrba7ista](https://twitter.com/mrba7ista) |
11 |
12 | Maintenance Status: Actively Maintained
13 |
14 | ## Installation
15 |
16 | To use npm
17 |
18 | ```bash
19 | npm install @capacitor-community/speech-recognition
20 | ```
21 |
22 | To use yarn
23 |
24 | ```bash
25 | yarn add @capacitor-community/speech-recognition
26 | ```
27 |
28 | Sync native files
29 |
30 | ```bash
31 | npx cap sync
32 | ```
33 |
34 | ## iOS
35 |
36 | iOS requires the following usage descriptions be added and filled out for your app in `Info.plist`:
37 |
38 | - `NSSpeechRecognitionUsageDescription` (`Privacy - Speech Recognition Usage Description`)
39 | - `NSMicrophoneUsageDescription` (`Privacy - Microphone Usage Description`)
40 |
41 | ## Android
42 |
43 | No further action required.
44 |
45 | ## Supported methods
46 |
47 |
48 |
49 | * [`available()`](#available)
50 | * [`start(...)`](#start)
51 | * [`stop()`](#stop)
52 | * [`getSupportedLanguages()`](#getsupportedlanguages)
53 | * [`isListening()`](#islistening)
54 | * [`checkPermissions()`](#checkpermissions)
55 | * [`requestPermissions()`](#requestpermissions)
56 | * [`addListener('partialResults', ...)`](#addlistenerpartialresults-)
57 | * [`addListener('listeningState', ...)`](#addlistenerlisteningstate-)
58 | * [`removeAllListeners()`](#removealllisteners)
59 | * [Interfaces](#interfaces)
60 | * [Type Aliases](#type-aliases)
61 |
62 |
63 |
64 | ## Example
65 |
66 | ```typescript
67 | import { SpeechRecognition } from "@capacitor-community/speech-recognition";
68 |
69 | SpeechRecognition.available();
70 |
71 | SpeechRecognition.start({
72 | language: "en-US",
73 | maxResults: 2,
74 | prompt: "Say something",
75 | partialResults: true,
76 | popup: true,
77 | });
78 | // listen to partial results
79 | SpeechRecognition.addListener("partialResults", (data: any) => {
80 | console.log("partialResults was fired", data.matches);
81 | });
82 |
83 | // stop listening partial results
84 | SpeechRecognition.removeAllListeners();
85 |
86 | SpeechRecognition.stop();
87 |
88 | SpeechRecognition.getSupportedLanguages();
89 |
90 | SpeechRecognition.checkPermissions();
91 |
92 | SpeechRecognition.requestPermissions();
93 |
94 | SpeechRecognition.hasPermission();
95 |
96 | SpeechRecognition.requestPermission();
97 | ```
98 |
99 |
100 |
101 |
102 | ### available()
103 |
104 | ```typescript
105 | available() => Promise<{ available: boolean; }>
106 | ```
107 |
108 | This method will check if speech recognition feature is available on the device.
109 |
110 | **Returns:** Promise<{ available: boolean; }>
111 |
112 | --------------------
113 |
114 |
115 | ### start(...)
116 |
117 | ```typescript
118 | start(options?: UtteranceOptions | undefined) => Promise<{ matches?: string[]; }>
119 | ```
120 |
121 | This method will start to listen for utterance.
122 |
123 | if `partialResults` is `true`, the function respond directly without result and
124 | event `partialResults` will be emit for each partial result, until stopped.
125 |
126 | | Param | Type |
127 | | ------------- | ------------------------------------------------------------- |
128 | | **`options`** | UtteranceOptions
|
129 |
130 | **Returns:** Promise<{ matches?: string[]; }>
131 |
132 | --------------------
133 |
134 |
135 | ### stop()
136 |
137 | ```typescript
138 | stop() => Promise
139 | ```
140 |
141 | This method will stop listening for utterance
142 |
143 | --------------------
144 |
145 |
146 | ### getSupportedLanguages()
147 |
148 | ```typescript
149 | getSupportedLanguages() => Promise<{ languages: any[]; }>
150 | ```
151 |
152 | This method will return list of languages supported by the speech recognizer.
153 |
154 | It's not available on Android 13 and newer.
155 |
156 | **Returns:** Promise<{ languages: any[]; }>
157 |
158 | --------------------
159 |
160 |
161 | ### isListening()
162 |
163 | ```typescript
164 | isListening() => Promise<{ listening: boolean; }>
165 | ```
166 |
167 | This method will check if speech recognition is listening.
168 |
169 | **Returns:** Promise<{ listening: boolean; }>
170 |
171 | **Since:** 5.1.0
172 |
173 | --------------------
174 |
175 |
176 | ### checkPermissions()
177 |
178 | ```typescript
179 | checkPermissions() => Promise
180 | ```
181 |
182 | Check the speech recognition permission.
183 |
184 | **Returns:** Promise<PermissionStatus>
185 |
186 | **Since:** 5.0.0
187 |
188 | --------------------
189 |
190 |
191 | ### requestPermissions()
192 |
193 | ```typescript
194 | requestPermissions() => Promise
195 | ```
196 |
197 | Request the speech recognition permission.
198 |
199 | **Returns:** Promise<PermissionStatus>
200 |
201 | **Since:** 5.0.0
202 |
203 | --------------------
204 |
205 |
206 | ### addListener('partialResults', ...)
207 |
208 | ```typescript
209 | addListener(eventName: 'partialResults', listenerFunc: (data: { matches: string[]; }) => void) => Promise
210 | ```
211 |
212 | Called when partialResults set to true and result received.
213 |
214 | On Android it doesn't work if popup is true.
215 |
216 | Provides partial result.
217 |
218 | | Param | Type |
219 | | ------------------ | ------------------------------------------------------ |
220 | | **`eventName`** | 'partialResults'
|
221 | | **`listenerFunc`** | (data: { matches: string[]; }) => void
|
222 |
223 | **Returns:** Promise<PluginListenerHandle>
224 |
225 | **Since:** 2.0.2
226 |
227 | --------------------
228 |
229 |
230 | ### addListener('listeningState', ...)
231 |
232 | ```typescript
233 | addListener(eventName: 'listeningState', listenerFunc: (data: { status: 'started' | 'stopped'; }) => void) => Promise
234 | ```
235 |
236 | Called when listening state changed.
237 |
238 | | Param | Type |
239 | | ------------------ | ------------------------------------------------------------------- |
240 | | **`eventName`** | 'listeningState'
|
241 | | **`listenerFunc`** | (data: { status: 'started' \| 'stopped'; }) => void
|
242 |
243 | **Returns:** Promise<PluginListenerHandle>
244 |
245 | **Since:** 5.1.0
246 |
247 | --------------------
248 |
249 |
250 | ### removeAllListeners()
251 |
252 | ```typescript
253 | removeAllListeners() => Promise
254 | ```
255 |
256 | Remove all the listeners that are attached to this plugin.
257 |
258 | **Since:** 4.0.0
259 |
260 | --------------------
261 |
262 |
263 | ### Interfaces
264 |
265 |
266 | #### UtteranceOptions
267 |
268 | | Prop | Type | Description |
269 | | -------------------- | -------------------- | ---------------------------------------------------------------- |
270 | | **`language`** | string
| key returned from `getSupportedLanguages()` |
271 | | **`maxResults`** | number
| maximum number of results to return (5 is max) |
272 | | **`prompt`** | string
| prompt message to display on popup (Android only) |
273 | | **`popup`** | boolean
| display popup window when listening for utterance (Android only) |
274 | | **`partialResults`** | boolean
| return partial results if found |
275 |
276 |
277 | #### PermissionStatus
278 |
279 | | Prop | Type | Description | Since |
280 | | ----------------------- | ----------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----- |
281 | | **`speechRecognition`** | PermissionState
| Permission state for speechRecognition alias. On Android it requests/checks RECORD_AUDIO permission On iOS it requests/checks the speech recognition and microphone permissions. | 5.0.0 |
282 |
283 |
284 | #### PluginListenerHandle
285 |
286 | | Prop | Type |
287 | | ------------ | ----------------------------------------- |
288 | | **`remove`** | () => Promise<void>
|
289 |
290 |
291 | ### Type Aliases
292 |
293 |
294 | #### PermissionState
295 |
296 | 'prompt' | 'prompt-with-rationale' | 'granted' | 'denied'
297 |
298 |
299 |
--------------------------------------------------------------------------------
/android/.npmignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | ext {
2 | junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.2'
3 | androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.7.0'
4 | androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.2.1'
5 | androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.6.1'
6 | }
7 |
8 | buildscript {
9 | repositories {
10 | google()
11 | mavenCentral()
12 | }
13 | dependencies {
14 | classpath 'com.android.tools.build:gradle:8.7.2'
15 | }
16 | }
17 |
18 | apply plugin: 'com.android.library'
19 |
20 | android {
21 | namespace "com.getcapacitor.community.speechrecognition.speechrecognition"
22 | compileSdk project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 35
23 | defaultConfig {
24 | minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 23
25 | targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 35
26 | versionCode 1
27 | versionName '1.0'
28 | testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
29 | }
30 | buildTypes {
31 | release {
32 | minifyEnabled false
33 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
34 | }
35 | }
36 | lintOptions {
37 | abortOnError false
38 | }
39 | compileOptions {
40 | sourceCompatibility JavaVersion.VERSION_21
41 | targetCompatibility JavaVersion.VERSION_21
42 | }
43 | }
44 |
45 | repositories {
46 | google()
47 | mavenCentral()
48 | }
49 |
50 | dependencies {
51 | implementation fileTree(dir: 'libs', include: ['*.jar'])
52 | implementation project(':capacitor-android')
53 | implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"
54 | testImplementation "junit:junit:$junitVersion"
55 | androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion"
56 | androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion"
57 | }
58 |
--------------------------------------------------------------------------------
/android/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | org.gradle.jvmargs=-Xmx1536m
13 |
14 | # When configured, Gradle will run in incubating parallel mode.
15 | # This option should only be used with decoupled projects. More details, visit
16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
17 | # org.gradle.parallel=true
18 |
19 | # Supports AndroidX
20 | android.useAndroidX=true
21 |
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/capacitor-community/speech-recognition/498ed497cf49459dd6badb4b366b61b250333252/android/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-all.zip
4 | networkTimeout=10000
5 | validateDistributionUrl=true
6 | zipStoreBase=GRADLE_USER_HOME
7 | zipStorePath=wrapper/dists
8 |
--------------------------------------------------------------------------------
/android/gradlew:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | #
4 | # Copyright © 2015-2021 the original authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 | # SPDX-License-Identifier: Apache-2.0
19 | #
20 |
21 | ##############################################################################
22 | #
23 | # Gradle start up script for POSIX generated by Gradle.
24 | #
25 | # Important for running:
26 | #
27 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
28 | # noncompliant, but you have some other compliant shell such as ksh or
29 | # bash, then to run this script, type that shell name before the whole
30 | # command line, like:
31 | #
32 | # ksh Gradle
33 | #
34 | # Busybox and similar reduced shells will NOT work, because this script
35 | # requires all of these POSIX shell features:
36 | # * functions;
37 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
38 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»;
39 | # * compound commands having a testable exit status, especially «case»;
40 | # * various built-in commands including «command», «set», and «ulimit».
41 | #
42 | # Important for patching:
43 | #
44 | # (2) This script targets any POSIX shell, so it avoids extensions provided
45 | # by Bash, Ksh, etc; in particular arrays are avoided.
46 | #
47 | # The "traditional" practice of packing multiple parameters into a
48 | # space-separated string is a well documented source of bugs and security
49 | # problems, so this is (mostly) avoided, by progressively accumulating
50 | # options in "$@", and eventually passing that to Java.
51 | #
52 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
53 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
54 | # see the in-line comments for details.
55 | #
56 | # There are tweaks for specific operating systems such as AIX, CygWin,
57 | # Darwin, MinGW, and NonStop.
58 | #
59 | # (3) This script is generated from the Groovy template
60 | # https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
61 | # within the Gradle project.
62 | #
63 | # You can find Gradle at https://github.com/gradle/gradle/.
64 | #
65 | ##############################################################################
66 |
67 | # Attempt to set APP_HOME
68 |
69 | # Resolve links: $0 may be a link
70 | app_path=$0
71 |
72 | # Need this for daisy-chained symlinks.
73 | while
74 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
75 | [ -h "$app_path" ]
76 | do
77 | ls=$( ls -ld "$app_path" )
78 | link=${ls#*' -> '}
79 | case $link in #(
80 | /*) app_path=$link ;; #(
81 | *) app_path=$APP_HOME$link ;;
82 | esac
83 | done
84 |
85 | # This is normally unused
86 | # shellcheck disable=SC2034
87 | APP_BASE_NAME=${0##*/}
88 | # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
89 | APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
90 | ' "$PWD" ) || exit
91 |
92 | # Use the maximum available, or set MAX_FD != -1 to use that value.
93 | MAX_FD=maximum
94 |
95 | warn () {
96 | echo "$*"
97 | } >&2
98 |
99 | die () {
100 | echo
101 | echo "$*"
102 | echo
103 | exit 1
104 | } >&2
105 |
106 | # OS specific support (must be 'true' or 'false').
107 | cygwin=false
108 | msys=false
109 | darwin=false
110 | nonstop=false
111 | case "$( uname )" in #(
112 | CYGWIN* ) cygwin=true ;; #(
113 | Darwin* ) darwin=true ;; #(
114 | MSYS* | MINGW* ) msys=true ;; #(
115 | NONSTOP* ) nonstop=true ;;
116 | esac
117 |
118 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
119 |
120 |
121 | # Determine the Java command to use to start the JVM.
122 | if [ -n "$JAVA_HOME" ] ; then
123 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
124 | # IBM's JDK on AIX uses strange locations for the executables
125 | JAVACMD=$JAVA_HOME/jre/sh/java
126 | else
127 | JAVACMD=$JAVA_HOME/bin/java
128 | fi
129 | if [ ! -x "$JAVACMD" ] ; then
130 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
131 |
132 | Please set the JAVA_HOME variable in your environment to match the
133 | location of your Java installation."
134 | fi
135 | else
136 | JAVACMD=java
137 | if ! command -v java >/dev/null 2>&1
138 | then
139 | die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
140 |
141 | Please set the JAVA_HOME variable in your environment to match the
142 | location of your Java installation."
143 | fi
144 | fi
145 |
146 | # Increase the maximum file descriptors if we can.
147 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
148 | case $MAX_FD in #(
149 | max*)
150 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
151 | # shellcheck disable=SC2039,SC3045
152 | MAX_FD=$( ulimit -H -n ) ||
153 | warn "Could not query maximum file descriptor limit"
154 | esac
155 | case $MAX_FD in #(
156 | '' | soft) :;; #(
157 | *)
158 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
159 | # shellcheck disable=SC2039,SC3045
160 | ulimit -n "$MAX_FD" ||
161 | warn "Could not set maximum file descriptor limit to $MAX_FD"
162 | esac
163 | fi
164 |
165 | # Collect all arguments for the java command, stacking in reverse order:
166 | # * args from the command line
167 | # * the main class name
168 | # * -classpath
169 | # * -D...appname settings
170 | # * --module-path (only if needed)
171 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
172 |
173 | # For Cygwin or MSYS, switch paths to Windows format before running java
174 | if "$cygwin" || "$msys" ; then
175 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
176 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
177 |
178 | JAVACMD=$( cygpath --unix "$JAVACMD" )
179 |
180 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
181 | for arg do
182 | if
183 | case $arg in #(
184 | -*) false ;; # don't mess with options #(
185 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
186 | [ -e "$t" ] ;; #(
187 | *) false ;;
188 | esac
189 | then
190 | arg=$( cygpath --path --ignore --mixed "$arg" )
191 | fi
192 | # Roll the args list around exactly as many times as the number of
193 | # args, so each arg winds up back in the position where it started, but
194 | # possibly modified.
195 | #
196 | # NB: a `for` loop captures its iteration list before it begins, so
197 | # changing the positional parameters here affects neither the number of
198 | # iterations, nor the values presented in `arg`.
199 | shift # remove old arg
200 | set -- "$@" "$arg" # push replacement arg
201 | done
202 | fi
203 |
204 |
205 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
206 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
207 |
208 | # Collect all arguments for the java command:
209 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
210 | # and any embedded shellness will be escaped.
211 | # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
212 | # treated as '${Hostname}' itself on the command line.
213 |
214 | set -- \
215 | "-Dorg.gradle.appname=$APP_BASE_NAME" \
216 | -classpath "$CLASSPATH" \
217 | org.gradle.wrapper.GradleWrapperMain \
218 | "$@"
219 |
220 | # Stop when "xargs" is not available.
221 | if ! command -v xargs >/dev/null 2>&1
222 | then
223 | die "xargs is not available"
224 | fi
225 |
226 | # Use "xargs" to parse quoted args.
227 | #
228 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed.
229 | #
230 | # In Bash we could simply go:
231 | #
232 | # readarray ARGS < <( xargs -n1 <<<"$var" ) &&
233 | # set -- "${ARGS[@]}" "$@"
234 | #
235 | # but POSIX shell has neither arrays nor command substitution, so instead we
236 | # post-process each arg (as a line of input to sed) to backslash-escape any
237 | # character that might be a shell metacharacter, then use eval to reverse
238 | # that process (while maintaining the separation between arguments), and wrap
239 | # the whole thing up as a single "set" statement.
240 | #
241 | # This will of course break if any of these variables contains a newline or
242 | # an unmatched quote.
243 | #
244 |
245 | eval "set -- $(
246 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
247 | xargs -n1 |
248 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
249 | tr '\n' ' '
250 | )" '"$@"'
251 |
252 | exec "$JAVACMD" "$@"
253 |
--------------------------------------------------------------------------------
/android/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 | @rem SPDX-License-Identifier: Apache-2.0
17 | @rem
18 |
19 | @if "%DEBUG%"=="" @echo off
20 | @rem ##########################################################################
21 | @rem
22 | @rem Gradle startup script for Windows
23 | @rem
24 | @rem ##########################################################################
25 |
26 | @rem Set local scope for the variables with windows NT shell
27 | if "%OS%"=="Windows_NT" setlocal
28 |
29 | set DIRNAME=%~dp0
30 | if "%DIRNAME%"=="" set DIRNAME=.
31 | @rem This is normally unused
32 | set APP_BASE_NAME=%~n0
33 | set APP_HOME=%DIRNAME%
34 |
35 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
36 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
37 |
38 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
39 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
40 |
41 | @rem Find java.exe
42 | if defined JAVA_HOME goto findJavaFromJavaHome
43 |
44 | set JAVA_EXE=java.exe
45 | %JAVA_EXE% -version >NUL 2>&1
46 | if %ERRORLEVEL% equ 0 goto execute
47 |
48 | echo. 1>&2
49 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
50 | echo. 1>&2
51 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2
52 | echo location of your Java installation. 1>&2
53 |
54 | goto fail
55 |
56 | :findJavaFromJavaHome
57 | set JAVA_HOME=%JAVA_HOME:"=%
58 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
59 |
60 | if exist "%JAVA_EXE%" goto execute
61 |
62 | echo. 1>&2
63 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
64 | echo. 1>&2
65 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2
66 | echo location of your Java installation. 1>&2
67 |
68 | goto fail
69 |
70 | :execute
71 | @rem Setup the command line
72 |
73 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
74 |
75 |
76 | @rem Execute Gradle
77 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
78 |
79 | :end
80 | @rem End local scope for the variables with windows NT shell
81 | if %ERRORLEVEL% equ 0 goto mainEnd
82 |
83 | :fail
84 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
85 | rem the _cmd.exe /c_ return code!
86 | set EXIT_CODE=%ERRORLEVEL%
87 | if %EXIT_CODE% equ 0 set EXIT_CODE=1
88 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
89 | exit /b %EXIT_CODE%
90 |
91 | :mainEnd
92 | if "%OS%"=="Windows_NT" endlocal
93 |
94 | :omega
95 |
--------------------------------------------------------------------------------
/android/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/android/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':capacitor-android'
2 | project(':capacitor-android').projectDir = new File('../node_modules/@capacitor/android/capacitor')
--------------------------------------------------------------------------------
/android/src/androidTest/java/com/getcapacitor/android/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.getcapacitor.android;
2 |
3 | import static org.junit.Assert.*;
4 |
5 | import android.content.Context;
6 | import androidx.test.ext.junit.runners.AndroidJUnit4;
7 | import androidx.test.platform.app.InstrumentationRegistry;
8 | import org.junit.Test;
9 | import org.junit.runner.RunWith;
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * @see Testing documentation
15 | */
16 | @RunWith(AndroidJUnit4.class)
17 | public class ExampleInstrumentedTest {
18 |
19 | @Test
20 | public void useAppContext() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
23 |
24 | assertEquals("com.getcapacitor.android", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/android/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/android/src/main/java/com/getcapacitor/community/speechrecognition/Constants.java:
--------------------------------------------------------------------------------
1 | package com.getcapacitor.community.speechrecognition;
2 |
3 | import android.Manifest;
4 |
5 | public interface Constants {
6 | int REQUEST_CODE_PERMISSION = 2001;
7 | int REQUEST_CODE_SPEECH = 2002;
8 | String IS_RECOGNITION_AVAILABLE = "isRecognitionAvailable";
9 | String START_LISTENING = "startListening";
10 | String STOP_LISTENING = "stopListening";
11 | String GET_SUPPORTED_LANGUAGES = "getSupportedLanguages";
12 | String HAS_PERMISSION = "hasPermission";
13 | String REQUEST_PERMISSION = "requestPermission";
14 | int MAX_RESULTS = 5;
15 | String NOT_AVAILABLE = "Speech recognition service is not available.";
16 | String MISSING_PERMISSION = "Missing permission";
17 | String RECORD_AUDIO_PERMISSION = Manifest.permission.RECORD_AUDIO;
18 | String ERROR = "Could not get list of languages";
19 | }
20 |
--------------------------------------------------------------------------------
/android/src/main/java/com/getcapacitor/community/speechrecognition/Receiver.java:
--------------------------------------------------------------------------------
1 | package com.getcapacitor.community.speechrecognition;
2 |
3 | import android.content.BroadcastReceiver;
4 | import android.content.Context;
5 | import android.content.Intent;
6 | import android.os.Bundle;
7 | import android.speech.RecognizerIntent;
8 | import com.getcapacitor.JSArray;
9 | import com.getcapacitor.JSObject;
10 | import com.getcapacitor.PluginCall;
11 | import java.util.List;
12 |
13 | public class Receiver extends BroadcastReceiver implements Constants {
14 |
15 | public static final String TAG = "Receiver";
16 |
17 | private List supportedLanguagesList;
18 | private String languagePref;
19 | private PluginCall call;
20 |
21 | public Receiver(PluginCall call) {
22 | super();
23 | this.call = call;
24 | }
25 |
26 | @Override
27 | public void onReceive(Context context, Intent intent) {
28 | Bundle extras = getResultExtras(true);
29 |
30 | if (extras.containsKey(RecognizerIntent.EXTRA_LANGUAGE_PREFERENCE)) {
31 | languagePref = extras.getString(RecognizerIntent.EXTRA_LANGUAGE_PREFERENCE);
32 | }
33 |
34 | if (extras.containsKey(RecognizerIntent.EXTRA_SUPPORTED_LANGUAGES)) {
35 | supportedLanguagesList = extras.getStringArrayList(RecognizerIntent.EXTRA_SUPPORTED_LANGUAGES);
36 |
37 | JSArray languagesList = new JSArray(supportedLanguagesList);
38 | call.resolve(new JSObject().put("languages", languagesList));
39 | return;
40 | }
41 |
42 | call.reject(ERROR);
43 | }
44 |
45 | public List getSupportedLanguages() {
46 | return supportedLanguagesList;
47 | }
48 |
49 | public String getLanguagePreference() {
50 | return languagePref;
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/android/src/main/java/com/getcapacitor/community/speechrecognition/SpeechRecognition.java:
--------------------------------------------------------------------------------
1 | package com.getcapacitor.community.speechrecognition;
2 |
3 | import android.Manifest;
4 | import android.app.Activity;
5 | import android.content.Intent;
6 | import android.os.Build;
7 | import android.os.Bundle;
8 | import android.speech.RecognitionListener;
9 | import android.speech.RecognizerIntent;
10 | import android.speech.SpeechRecognizer;
11 | import androidx.activity.result.ActivityResult;
12 | import com.getcapacitor.JSArray;
13 | import com.getcapacitor.JSObject;
14 | import com.getcapacitor.Logger;
15 | import com.getcapacitor.PermissionState;
16 | import com.getcapacitor.Plugin;
17 | import com.getcapacitor.PluginCall;
18 | import com.getcapacitor.PluginMethod;
19 | import com.getcapacitor.annotation.ActivityCallback;
20 | import com.getcapacitor.annotation.CapacitorPlugin;
21 | import com.getcapacitor.annotation.Permission;
22 | import java.util.ArrayList;
23 | import java.util.List;
24 | import java.util.Locale;
25 | import java.util.concurrent.locks.ReentrantLock;
26 | import org.json.JSONArray;
27 |
28 | @CapacitorPlugin(
29 | permissions = { @Permission(strings = { Manifest.permission.RECORD_AUDIO }, alias = SpeechRecognition.SPEECH_RECOGNITION) }
30 | )
31 | public class SpeechRecognition extends Plugin implements Constants {
32 |
33 | public static final String TAG = "SpeechRecognition";
34 | private static final String LISTENING_EVENT = "listeningState";
35 | static final String SPEECH_RECOGNITION = "speechRecognition";
36 |
37 | private Receiver languageReceiver;
38 | private SpeechRecognizer speechRecognizer;
39 |
40 | private final ReentrantLock lock = new ReentrantLock();
41 | private boolean listening = false;
42 |
43 | private JSONArray previousPartialResults = new JSONArray();
44 |
45 | @Override
46 | public void load() {
47 | super.load();
48 | bridge
49 | .getWebView()
50 | .post(() -> {
51 | speechRecognizer = SpeechRecognizer.createSpeechRecognizer(bridge.getActivity());
52 | SpeechRecognitionListener listener = new SpeechRecognitionListener();
53 | speechRecognizer.setRecognitionListener(listener);
54 | Logger.info(getLogTag(), "Instantiated SpeechRecognizer in load()");
55 | });
56 | }
57 |
58 | @PluginMethod
59 | public void available(PluginCall call) {
60 | Logger.info(getLogTag(), "Called for available(): " + isSpeechRecognitionAvailable());
61 | boolean val = isSpeechRecognitionAvailable();
62 | JSObject result = new JSObject();
63 | result.put("available", val);
64 | call.resolve(result);
65 | }
66 |
67 | @PluginMethod
68 | public void start(PluginCall call) {
69 | if (!isSpeechRecognitionAvailable()) {
70 | call.unavailable(NOT_AVAILABLE);
71 | return;
72 | }
73 |
74 | if (getPermissionState(SPEECH_RECOGNITION) != PermissionState.GRANTED) {
75 | call.reject(MISSING_PERMISSION);
76 | return;
77 | }
78 |
79 | String language = call.getString("language", Locale.getDefault().toString());
80 | int maxResults = call.getInt("maxResults", MAX_RESULTS);
81 | String prompt = call.getString("prompt", null);
82 | boolean partialResults = call.getBoolean("partialResults", false);
83 | boolean popup = call.getBoolean("popup", false);
84 | beginListening(language, maxResults, prompt, partialResults, popup, call);
85 | }
86 |
87 | @PluginMethod
88 | public void stop(final PluginCall call) {
89 | try {
90 | stopListening();
91 | } catch (Exception ex) {
92 | call.reject(ex.getLocalizedMessage());
93 | }
94 | }
95 |
96 | @PluginMethod
97 | public void getSupportedLanguages(PluginCall call) {
98 | if (languageReceiver == null) {
99 | languageReceiver = new Receiver(call);
100 | }
101 |
102 | List supportedLanguages = languageReceiver.getSupportedLanguages();
103 | if (supportedLanguages != null) {
104 | JSONArray languages = new JSONArray(supportedLanguages);
105 | call.resolve(new JSObject().put("languages", languages));
106 | return;
107 | }
108 |
109 | Intent detailsIntent = new Intent(RecognizerIntent.ACTION_GET_LANGUAGE_DETAILS);
110 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
111 | detailsIntent.setPackage("com.google.android.googlequicksearchbox");
112 | }
113 | bridge.getActivity().sendOrderedBroadcast(detailsIntent, null, languageReceiver, null, Activity.RESULT_OK, null, null);
114 | }
115 |
116 | @PluginMethod
117 | public void isListening(PluginCall call) {
118 | call.resolve(new JSObject().put("listening", SpeechRecognition.this.listening));
119 | }
120 |
121 | @ActivityCallback
122 | private void listeningResult(PluginCall call, ActivityResult result) {
123 | if (call == null) {
124 | return;
125 | }
126 |
127 | int resultCode = result.getResultCode();
128 | if (resultCode == Activity.RESULT_OK) {
129 | try {
130 | ArrayList matchesList = result.getData().getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);
131 | JSObject resultObj = new JSObject();
132 | resultObj.put("matches", new JSArray(matchesList));
133 | call.resolve(resultObj);
134 | } catch (Exception ex) {
135 | call.reject(ex.getMessage());
136 | }
137 | } else {
138 | call.reject(Integer.toString(resultCode));
139 | }
140 |
141 | SpeechRecognition.this.lock.lock();
142 | SpeechRecognition.this.listening(false);
143 | SpeechRecognition.this.lock.unlock();
144 | }
145 |
146 | private boolean isSpeechRecognitionAvailable() {
147 | return SpeechRecognizer.isRecognitionAvailable(bridge.getContext());
148 | }
149 |
150 | private void listening(boolean value) {
151 | this.listening = value;
152 | }
153 |
154 | private void beginListening(
155 | String language,
156 | int maxResults,
157 | String prompt,
158 | final boolean partialResults,
159 | boolean showPopup,
160 | PluginCall call
161 | ) {
162 | Logger.info(getLogTag(), "Beginning to listen for audible speech");
163 |
164 | final Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
165 | intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
166 | intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language);
167 | intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, maxResults);
168 | intent.putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE, bridge.getActivity().getPackageName());
169 | intent.putExtra(RecognizerIntent.EXTRA_PARTIAL_RESULTS, partialResults);
170 | intent.putExtra("android.speech.extra.DICTATION_MODE", partialResults);
171 |
172 | if (prompt != null) {
173 | intent.putExtra(RecognizerIntent.EXTRA_PROMPT, prompt);
174 | }
175 |
176 | if (showPopup) {
177 | startActivityForResult(call, intent, "listeningResult");
178 | } else {
179 | bridge
180 | .getWebView()
181 | .post(() -> {
182 | try {
183 | SpeechRecognition.this.lock.lock();
184 |
185 | if (speechRecognizer != null) {
186 | speechRecognizer.cancel();
187 | speechRecognizer.destroy();
188 | speechRecognizer = null;
189 | }
190 |
191 | speechRecognizer = SpeechRecognizer.createSpeechRecognizer(bridge.getActivity());
192 | SpeechRecognitionListener listener = new SpeechRecognitionListener();
193 | listener.setCall(call);
194 | listener.setPartialResults(partialResults);
195 | speechRecognizer.setRecognitionListener(listener);
196 | speechRecognizer.startListening(intent);
197 | SpeechRecognition.this.listening(true);
198 | if (partialResults) {
199 | call.resolve();
200 | }
201 | } catch (Exception ex) {
202 | call.reject(ex.getMessage());
203 | } finally {
204 | SpeechRecognition.this.lock.unlock();
205 | }
206 | });
207 | }
208 | }
209 |
210 | private void stopListening() {
211 | bridge
212 | .getWebView()
213 | .post(() -> {
214 | try {
215 | SpeechRecognition.this.lock.lock();
216 | if (SpeechRecognition.this.listening) {
217 | speechRecognizer.stopListening();
218 | SpeechRecognition.this.listening(false);
219 | }
220 | } catch (Exception ex) {
221 | throw ex;
222 | } finally {
223 | SpeechRecognition.this.lock.unlock();
224 | }
225 | });
226 | }
227 |
228 | private class SpeechRecognitionListener implements RecognitionListener {
229 |
230 | private PluginCall call;
231 | private boolean partialResults;
232 |
233 | public void setCall(PluginCall call) {
234 | this.call = call;
235 | }
236 |
237 | public void setPartialResults(boolean partialResults) {
238 | this.partialResults = partialResults;
239 | }
240 |
241 | @Override
242 | public void onReadyForSpeech(Bundle params) {}
243 |
244 | @Override
245 | public void onBeginningOfSpeech() {
246 | try {
247 | SpeechRecognition.this.lock.lock();
248 | // Notify listeners that recording has started
249 | JSObject ret = new JSObject();
250 | ret.put("status", "started");
251 | SpeechRecognition.this.notifyListeners(LISTENING_EVENT, ret);
252 | } finally {
253 | SpeechRecognition.this.lock.unlock();
254 | }
255 | }
256 |
257 | @Override
258 | public void onRmsChanged(float rmsdB) {}
259 |
260 | @Override
261 | public void onBufferReceived(byte[] buffer) {}
262 |
263 | @Override
264 | public void onEndOfSpeech() {
265 | bridge
266 | .getWebView()
267 | .post(() -> {
268 | try {
269 | SpeechRecognition.this.lock.lock();
270 | SpeechRecognition.this.listening(false);
271 |
272 | JSObject ret = new JSObject();
273 | ret.put("status", "stopped");
274 | SpeechRecognition.this.notifyListeners(LISTENING_EVENT, ret);
275 | } finally {
276 | SpeechRecognition.this.lock.unlock();
277 | }
278 | });
279 | }
280 |
281 | @Override
282 | public void onError(int error) {
283 | SpeechRecognition.this.stopListening();
284 | String errorMssg = getErrorText(error);
285 |
286 | if (this.call != null) {
287 | call.reject(errorMssg);
288 | }
289 | }
290 |
291 | @Override
292 | public void onResults(Bundle results) {
293 | ArrayList matches = results.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION);
294 |
295 | try {
296 | JSArray jsArray = new JSArray(matches);
297 |
298 | if (this.call != null) {
299 | if (!this.partialResults) {
300 | this.call.resolve(new JSObject().put("status", "success").put("matches", jsArray));
301 | } else {
302 | JSObject ret = new JSObject();
303 | ret.put("matches", jsArray);
304 | notifyListeners("partialResults", ret);
305 | }
306 | }
307 | } catch (Exception ex) {
308 | this.call.resolve(new JSObject().put("status", "error").put("message", ex.getMessage()));
309 | }
310 | }
311 |
312 | @Override
313 | public void onPartialResults(Bundle partialResults) {
314 | ArrayList matches = partialResults.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION);
315 | JSArray matchesJSON = new JSArray(matches);
316 |
317 | try {
318 | if (matches != null && matches.size() > 0 && !previousPartialResults.equals(matchesJSON)) {
319 | previousPartialResults = matchesJSON;
320 | JSObject ret = new JSObject();
321 | ret.put("matches", previousPartialResults);
322 | notifyListeners("partialResults", ret);
323 | }
324 | } catch (Exception ex) {}
325 | }
326 |
327 | @Override
328 | public void onEvent(int eventType, Bundle params) {}
329 | }
330 |
331 | private String getErrorText(int errorCode) {
332 | String message;
333 | switch (errorCode) {
334 | case SpeechRecognizer.ERROR_AUDIO:
335 | message = "Audio recording error";
336 | break;
337 | case SpeechRecognizer.ERROR_CLIENT:
338 | message = "Client side error";
339 | break;
340 | case SpeechRecognizer.ERROR_INSUFFICIENT_PERMISSIONS:
341 | message = "Insufficient permissions";
342 | break;
343 | case SpeechRecognizer.ERROR_NETWORK:
344 | message = "Network error";
345 | break;
346 | case SpeechRecognizer.ERROR_NETWORK_TIMEOUT:
347 | message = "Network timeout";
348 | break;
349 | case SpeechRecognizer.ERROR_NO_MATCH:
350 | message = "No match";
351 | break;
352 | case SpeechRecognizer.ERROR_RECOGNIZER_BUSY:
353 | message = "RecognitionService busy";
354 | break;
355 | case SpeechRecognizer.ERROR_SERVER:
356 | message = "error from server";
357 | break;
358 | case SpeechRecognizer.ERROR_SPEECH_TIMEOUT:
359 | message = "No speech input";
360 | break;
361 | default:
362 | message = "Didn't understand, please try again.";
363 | break;
364 | }
365 | return message;
366 | }
367 | }
368 |
--------------------------------------------------------------------------------
/android/src/main/res/layout/bridge_layout_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/android/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/android/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Just a simple string
3 |
4 |
--------------------------------------------------------------------------------
/android/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/android/src/test/java/com/getcapacitor/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.getcapacitor;
2 |
3 | import static org.junit.Assert.*;
4 |
5 | import org.junit.Test;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 |
14 | @Test
15 | public void addition_isCorrect() throws Exception {
16 | assertEquals(4, 2 + 2);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/ios/Plugin.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 48;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 03FC29A292ACC40490383A1F /* Pods_Plugin.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B2A61DA5A1F2DD4F959604D /* Pods_Plugin.framework */; };
11 | 20C0B05DCFC8E3958A738AF2 /* Pods_PluginTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F6753A823D3815DB436415E3 /* Pods_PluginTests.framework */; };
12 | 50ADFF92201F53D600D50D53 /* Plugin.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 50ADFF88201F53D600D50D53 /* Plugin.framework */; };
13 | 50ADFF97201F53D600D50D53 /* PluginTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50ADFF96201F53D600D50D53 /* PluginTests.swift */; };
14 | 50ADFF99201F53D600D50D53 /* Plugin.h in Headers */ = {isa = PBXBuildFile; fileRef = 50ADFF8B201F53D600D50D53 /* Plugin.h */; settings = {ATTRIBUTES = (Public, ); }; };
15 | 50ADFFA42020D75100D50D53 /* Capacitor.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 50ADFFA52020D75100D50D53 /* Capacitor.framework */; };
16 | 50ADFFA82020EE4F00D50D53 /* Plugin.m in Sources */ = {isa = PBXBuildFile; fileRef = 50ADFFA72020EE4F00D50D53 /* Plugin.m */; };
17 | 50E1A94820377CB70090CE1A /* Plugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50E1A94720377CB70090CE1A /* Plugin.swift */; };
18 | /* End PBXBuildFile section */
19 |
20 | /* Begin PBXContainerItemProxy section */
21 | 50ADFF93201F53D600D50D53 /* PBXContainerItemProxy */ = {
22 | isa = PBXContainerItemProxy;
23 | containerPortal = 50ADFF7F201F53D600D50D53 /* Project object */;
24 | proxyType = 1;
25 | remoteGlobalIDString = 50ADFF87201F53D600D50D53;
26 | remoteInfo = Plugin;
27 | };
28 | /* End PBXContainerItemProxy section */
29 |
30 | /* Begin PBXFileReference section */
31 | 3B2A61DA5A1F2DD4F959604D /* Pods_Plugin.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Plugin.framework; sourceTree = BUILT_PRODUCTS_DIR; };
32 | 50ADFF88201F53D600D50D53 /* Plugin.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Plugin.framework; sourceTree = BUILT_PRODUCTS_DIR; };
33 | 50ADFF8B201F53D600D50D53 /* Plugin.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Plugin.h; sourceTree = ""; };
34 | 50ADFF8C201F53D600D50D53 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
35 | 50ADFF91201F53D600D50D53 /* PluginTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PluginTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
36 | 50ADFF96201F53D600D50D53 /* PluginTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PluginTests.swift; sourceTree = ""; };
37 | 50ADFF98201F53D600D50D53 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
38 | 50ADFFA52020D75100D50D53 /* Capacitor.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Capacitor.framework; sourceTree = BUILT_PRODUCTS_DIR; };
39 | 50ADFFA72020EE4F00D50D53 /* Plugin.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Plugin.m; sourceTree = ""; };
40 | 50E1A94720377CB70090CE1A /* Plugin.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Plugin.swift; sourceTree = ""; };
41 | 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 = ""; };
42 | 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 = ""; };
43 | 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 = ""; };
44 | 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 = ""; };
45 | F6753A823D3815DB436415E3 /* Pods_PluginTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_PluginTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
46 | /* End PBXFileReference section */
47 |
48 | /* Begin PBXFrameworksBuildPhase section */
49 | 50ADFF84201F53D600D50D53 /* Frameworks */ = {
50 | isa = PBXFrameworksBuildPhase;
51 | buildActionMask = 2147483647;
52 | files = (
53 | 50ADFFA42020D75100D50D53 /* Capacitor.framework in Frameworks */,
54 | 03FC29A292ACC40490383A1F /* Pods_Plugin.framework in Frameworks */,
55 | );
56 | runOnlyForDeploymentPostprocessing = 0;
57 | };
58 | 50ADFF8E201F53D600D50D53 /* Frameworks */ = {
59 | isa = PBXFrameworksBuildPhase;
60 | buildActionMask = 2147483647;
61 | files = (
62 | 50ADFF92201F53D600D50D53 /* Plugin.framework in Frameworks */,
63 | 20C0B05DCFC8E3958A738AF2 /* Pods_PluginTests.framework in Frameworks */,
64 | );
65 | runOnlyForDeploymentPostprocessing = 0;
66 | };
67 | /* End PBXFrameworksBuildPhase section */
68 |
69 | /* Begin PBXGroup section */
70 | 50ADFF7E201F53D600D50D53 = {
71 | isa = PBXGroup;
72 | children = (
73 | 50ADFF8A201F53D600D50D53 /* Plugin */,
74 | 50ADFF95201F53D600D50D53 /* PluginTests */,
75 | 50ADFF89201F53D600D50D53 /* Products */,
76 | 8C8E7744173064A9F6D438E3 /* Pods */,
77 | A797B9EFA3DCEFEA1FBB66A9 /* Frameworks */,
78 | );
79 | sourceTree = "";
80 | };
81 | 50ADFF89201F53D600D50D53 /* Products */ = {
82 | isa = PBXGroup;
83 | children = (
84 | 50ADFF88201F53D600D50D53 /* Plugin.framework */,
85 | 50ADFF91201F53D600D50D53 /* PluginTests.xctest */,
86 | );
87 | name = Products;
88 | sourceTree = "";
89 | };
90 | 50ADFF8A201F53D600D50D53 /* Plugin */ = {
91 | isa = PBXGroup;
92 | children = (
93 | 50E1A94720377CB70090CE1A /* Plugin.swift */,
94 | 50ADFF8B201F53D600D50D53 /* Plugin.h */,
95 | 50ADFFA72020EE4F00D50D53 /* Plugin.m */,
96 | 50ADFF8C201F53D600D50D53 /* Info.plist */,
97 | );
98 | path = Plugin;
99 | sourceTree = "";
100 | };
101 | 50ADFF95201F53D600D50D53 /* PluginTests */ = {
102 | isa = PBXGroup;
103 | children = (
104 | 50ADFF96201F53D600D50D53 /* PluginTests.swift */,
105 | 50ADFF98201F53D600D50D53 /* Info.plist */,
106 | );
107 | path = PluginTests;
108 | sourceTree = "";
109 | };
110 | 8C8E7744173064A9F6D438E3 /* Pods */ = {
111 | isa = PBXGroup;
112 | children = (
113 | 5E23F77F099397094342571A /* Pods-Plugin.debug.xcconfig */,
114 | 91781294A431A2A7CC6EB714 /* Pods-Plugin.release.xcconfig */,
115 | 96ED1B6440D6672E406C8D19 /* Pods-PluginTests.debug.xcconfig */,
116 | F65BB2953ECE002E1EF3E424 /* Pods-PluginTests.release.xcconfig */,
117 | );
118 | name = Pods;
119 | sourceTree = "";
120 | };
121 | A797B9EFA3DCEFEA1FBB66A9 /* Frameworks */ = {
122 | isa = PBXGroup;
123 | children = (
124 | 50ADFFA52020D75100D50D53 /* Capacitor.framework */,
125 | 3B2A61DA5A1F2DD4F959604D /* Pods_Plugin.framework */,
126 | F6753A823D3815DB436415E3 /* Pods_PluginTests.framework */,
127 | );
128 | name = Frameworks;
129 | sourceTree = "";
130 | };
131 | /* End PBXGroup section */
132 |
133 | /* Begin PBXHeadersBuildPhase section */
134 | 50ADFF85201F53D600D50D53 /* Headers */ = {
135 | isa = PBXHeadersBuildPhase;
136 | buildActionMask = 2147483647;
137 | files = (
138 | 50ADFF99201F53D600D50D53 /* Plugin.h in Headers */,
139 | );
140 | runOnlyForDeploymentPostprocessing = 0;
141 | };
142 | /* End PBXHeadersBuildPhase section */
143 |
144 | /* Begin PBXNativeTarget section */
145 | 50ADFF87201F53D600D50D53 /* Plugin */ = {
146 | isa = PBXNativeTarget;
147 | buildConfigurationList = 50ADFF9C201F53D600D50D53 /* Build configuration list for PBXNativeTarget "Plugin" */;
148 | buildPhases = (
149 | AB5B3E54B4E897F32C2279DA /* [CP] Check Pods Manifest.lock */,
150 | 50ADFF83201F53D600D50D53 /* Sources */,
151 | 50ADFF84201F53D600D50D53 /* Frameworks */,
152 | 50ADFF85201F53D600D50D53 /* Headers */,
153 | 50ADFF86201F53D600D50D53 /* Resources */,
154 | );
155 | buildRules = (
156 | );
157 | dependencies = (
158 | );
159 | name = Plugin;
160 | productName = Plugin;
161 | productReference = 50ADFF88201F53D600D50D53 /* Plugin.framework */;
162 | productType = "com.apple.product-type.framework";
163 | };
164 | 50ADFF90201F53D600D50D53 /* PluginTests */ = {
165 | isa = PBXNativeTarget;
166 | buildConfigurationList = 50ADFF9F201F53D600D50D53 /* Build configuration list for PBXNativeTarget "PluginTests" */;
167 | buildPhases = (
168 | 0596884F929ED6F1DE134961 /* [CP] Check Pods Manifest.lock */,
169 | 50ADFF8D201F53D600D50D53 /* Sources */,
170 | 50ADFF8E201F53D600D50D53 /* Frameworks */,
171 | 50ADFF8F201F53D600D50D53 /* Resources */,
172 | CCA81D3B7E26D0D727D24C84 /* [CP] Embed Pods Frameworks */,
173 | );
174 | buildRules = (
175 | );
176 | dependencies = (
177 | 50ADFF94201F53D600D50D53 /* PBXTargetDependency */,
178 | );
179 | name = PluginTests;
180 | productName = PluginTests;
181 | productReference = 50ADFF91201F53D600D50D53 /* PluginTests.xctest */;
182 | productType = "com.apple.product-type.bundle.unit-test";
183 | };
184 | /* End PBXNativeTarget section */
185 |
186 | /* Begin PBXProject section */
187 | 50ADFF7F201F53D600D50D53 /* Project object */ = {
188 | isa = PBXProject;
189 | attributes = {
190 | LastSwiftUpdateCheck = 0920;
191 | LastUpgradeCheck = 0920;
192 | ORGANIZATIONNAME = "Max Lynch";
193 | TargetAttributes = {
194 | 50ADFF87201F53D600D50D53 = {
195 | CreatedOnToolsVersion = 9.2;
196 | LastSwiftMigration = 1100;
197 | ProvisioningStyle = Automatic;
198 | };
199 | 50ADFF90201F53D600D50D53 = {
200 | CreatedOnToolsVersion = 9.2;
201 | LastSwiftMigration = 1100;
202 | ProvisioningStyle = Automatic;
203 | };
204 | };
205 | };
206 | buildConfigurationList = 50ADFF82201F53D600D50D53 /* Build configuration list for PBXProject "Plugin" */;
207 | compatibilityVersion = "Xcode 8.0";
208 | developmentRegion = en;
209 | hasScannedForEncodings = 0;
210 | knownRegions = (
211 | en,
212 | );
213 | mainGroup = 50ADFF7E201F53D600D50D53;
214 | productRefGroup = 50ADFF89201F53D600D50D53 /* Products */;
215 | projectDirPath = "";
216 | projectRoot = "";
217 | targets = (
218 | 50ADFF87201F53D600D50D53 /* Plugin */,
219 | 50ADFF90201F53D600D50D53 /* PluginTests */,
220 | );
221 | };
222 | /* End PBXProject section */
223 |
224 | /* Begin PBXResourcesBuildPhase section */
225 | 50ADFF86201F53D600D50D53 /* Resources */ = {
226 | isa = PBXResourcesBuildPhase;
227 | buildActionMask = 2147483647;
228 | files = (
229 | );
230 | runOnlyForDeploymentPostprocessing = 0;
231 | };
232 | 50ADFF8F201F53D600D50D53 /* Resources */ = {
233 | isa = PBXResourcesBuildPhase;
234 | buildActionMask = 2147483647;
235 | files = (
236 | );
237 | runOnlyForDeploymentPostprocessing = 0;
238 | };
239 | /* End PBXResourcesBuildPhase section */
240 |
241 | /* Begin PBXShellScriptBuildPhase section */
242 | 0596884F929ED6F1DE134961 /* [CP] Check Pods Manifest.lock */ = {
243 | isa = PBXShellScriptBuildPhase;
244 | buildActionMask = 2147483647;
245 | files = (
246 | );
247 | inputPaths = (
248 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
249 | "${PODS_ROOT}/Manifest.lock",
250 | );
251 | name = "[CP] Check Pods Manifest.lock";
252 | outputPaths = (
253 | "$(DERIVED_FILE_DIR)/Pods-PluginTests-checkManifestLockResult.txt",
254 | );
255 | runOnlyForDeploymentPostprocessing = 0;
256 | shellPath = /bin/sh;
257 | 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";
258 | showEnvVarsInLog = 0;
259 | };
260 | AB5B3E54B4E897F32C2279DA /* [CP] Check Pods Manifest.lock */ = {
261 | isa = PBXShellScriptBuildPhase;
262 | buildActionMask = 2147483647;
263 | files = (
264 | );
265 | inputPaths = (
266 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
267 | "${PODS_ROOT}/Manifest.lock",
268 | );
269 | name = "[CP] Check Pods Manifest.lock";
270 | outputPaths = (
271 | "$(DERIVED_FILE_DIR)/Pods-Plugin-checkManifestLockResult.txt",
272 | );
273 | runOnlyForDeploymentPostprocessing = 0;
274 | shellPath = /bin/sh;
275 | 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";
276 | showEnvVarsInLog = 0;
277 | };
278 | CCA81D3B7E26D0D727D24C84 /* [CP] Embed Pods Frameworks */ = {
279 | isa = PBXShellScriptBuildPhase;
280 | buildActionMask = 2147483647;
281 | files = (
282 | );
283 | inputPaths = (
284 | "${PODS_ROOT}/Target Support Files/Pods-PluginTests/Pods-PluginTests-frameworks.sh",
285 | "${BUILT_PRODUCTS_DIR}/Capacitor/Capacitor.framework",
286 | "${BUILT_PRODUCTS_DIR}/CapacitorCordova/Cordova.framework",
287 | );
288 | name = "[CP] Embed Pods Frameworks";
289 | outputPaths = (
290 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Capacitor.framework",
291 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Cordova.framework",
292 | );
293 | runOnlyForDeploymentPostprocessing = 0;
294 | shellPath = /bin/sh;
295 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-PluginTests/Pods-PluginTests-frameworks.sh\"\n";
296 | showEnvVarsInLog = 0;
297 | };
298 | /* End PBXShellScriptBuildPhase section */
299 |
300 | /* Begin PBXSourcesBuildPhase section */
301 | 50ADFF83201F53D600D50D53 /* Sources */ = {
302 | isa = PBXSourcesBuildPhase;
303 | buildActionMask = 2147483647;
304 | files = (
305 | 50E1A94820377CB70090CE1A /* Plugin.swift in Sources */,
306 | 50ADFFA82020EE4F00D50D53 /* Plugin.m in Sources */,
307 | );
308 | runOnlyForDeploymentPostprocessing = 0;
309 | };
310 | 50ADFF8D201F53D600D50D53 /* Sources */ = {
311 | isa = PBXSourcesBuildPhase;
312 | buildActionMask = 2147483647;
313 | files = (
314 | 50ADFF97201F53D600D50D53 /* PluginTests.swift in Sources */,
315 | );
316 | runOnlyForDeploymentPostprocessing = 0;
317 | };
318 | /* End PBXSourcesBuildPhase section */
319 |
320 | /* Begin PBXTargetDependency section */
321 | 50ADFF94201F53D600D50D53 /* PBXTargetDependency */ = {
322 | isa = PBXTargetDependency;
323 | target = 50ADFF87201F53D600D50D53 /* Plugin */;
324 | targetProxy = 50ADFF93201F53D600D50D53 /* PBXContainerItemProxy */;
325 | };
326 | /* End PBXTargetDependency section */
327 |
328 | /* Begin XCBuildConfiguration section */
329 | 50ADFF9A201F53D600D50D53 /* Debug */ = {
330 | isa = XCBuildConfiguration;
331 | buildSettings = {
332 | ALWAYS_SEARCH_USER_PATHS = NO;
333 | CLANG_ANALYZER_NONNULL = YES;
334 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
335 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
336 | CLANG_CXX_LIBRARY = "libc++";
337 | CLANG_ENABLE_MODULES = YES;
338 | CLANG_ENABLE_OBJC_ARC = YES;
339 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
340 | CLANG_WARN_BOOL_CONVERSION = YES;
341 | CLANG_WARN_COMMA = YES;
342 | CLANG_WARN_CONSTANT_CONVERSION = YES;
343 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
344 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
345 | CLANG_WARN_EMPTY_BODY = YES;
346 | CLANG_WARN_ENUM_CONVERSION = YES;
347 | CLANG_WARN_INFINITE_RECURSION = YES;
348 | CLANG_WARN_INT_CONVERSION = YES;
349 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
350 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
351 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
352 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
353 | CLANG_WARN_STRICT_PROTOTYPES = YES;
354 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
355 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
356 | CLANG_WARN_UNREACHABLE_CODE = YES;
357 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
358 | CODE_SIGN_IDENTITY = "iPhone Developer";
359 | COPY_PHASE_STRIP = NO;
360 | CURRENT_PROJECT_VERSION = 1;
361 | DEBUG_INFORMATION_FORMAT = dwarf;
362 | ENABLE_STRICT_OBJC_MSGSEND = YES;
363 | ENABLE_TESTABILITY = YES;
364 | GCC_C_LANGUAGE_STANDARD = gnu11;
365 | GCC_DYNAMIC_NO_PIC = NO;
366 | GCC_NO_COMMON_BLOCKS = YES;
367 | GCC_OPTIMIZATION_LEVEL = 0;
368 | GCC_PREPROCESSOR_DEFINITIONS = (
369 | "DEBUG=1",
370 | "$(inherited)",
371 | );
372 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
373 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
374 | GCC_WARN_UNDECLARED_SELECTOR = YES;
375 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
376 | GCC_WARN_UNUSED_FUNCTION = YES;
377 | GCC_WARN_UNUSED_VARIABLE = YES;
378 | IPHONEOS_DEPLOYMENT_TARGET = 14.0;
379 | MTL_ENABLE_DEBUG_INFO = YES;
380 | ONLY_ACTIVE_ARCH = YES;
381 | SDKROOT = iphoneos;
382 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
383 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
384 | VERSIONING_SYSTEM = "apple-generic";
385 | VERSION_INFO_PREFIX = "";
386 | };
387 | name = Debug;
388 | };
389 | 50ADFF9B201F53D600D50D53 /* Release */ = {
390 | isa = XCBuildConfiguration;
391 | buildSettings = {
392 | ALWAYS_SEARCH_USER_PATHS = NO;
393 | CLANG_ANALYZER_NONNULL = YES;
394 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
395 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
396 | CLANG_CXX_LIBRARY = "libc++";
397 | CLANG_ENABLE_MODULES = YES;
398 | CLANG_ENABLE_OBJC_ARC = YES;
399 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
400 | CLANG_WARN_BOOL_CONVERSION = YES;
401 | CLANG_WARN_COMMA = YES;
402 | CLANG_WARN_CONSTANT_CONVERSION = YES;
403 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
404 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
405 | CLANG_WARN_EMPTY_BODY = YES;
406 | CLANG_WARN_ENUM_CONVERSION = YES;
407 | CLANG_WARN_INFINITE_RECURSION = YES;
408 | CLANG_WARN_INT_CONVERSION = YES;
409 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
410 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
411 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
412 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
413 | CLANG_WARN_STRICT_PROTOTYPES = YES;
414 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
415 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
416 | CLANG_WARN_UNREACHABLE_CODE = YES;
417 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
418 | CODE_SIGN_IDENTITY = "iPhone Developer";
419 | COPY_PHASE_STRIP = NO;
420 | CURRENT_PROJECT_VERSION = 1;
421 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
422 | ENABLE_NS_ASSERTIONS = NO;
423 | ENABLE_STRICT_OBJC_MSGSEND = YES;
424 | GCC_C_LANGUAGE_STANDARD = gnu11;
425 | GCC_NO_COMMON_BLOCKS = YES;
426 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
427 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
428 | GCC_WARN_UNDECLARED_SELECTOR = YES;
429 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
430 | GCC_WARN_UNUSED_FUNCTION = YES;
431 | GCC_WARN_UNUSED_VARIABLE = YES;
432 | IPHONEOS_DEPLOYMENT_TARGET = 14.0;
433 | MTL_ENABLE_DEBUG_INFO = NO;
434 | SDKROOT = iphoneos;
435 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
436 | VALIDATE_PRODUCT = YES;
437 | VERSIONING_SYSTEM = "apple-generic";
438 | VERSION_INFO_PREFIX = "";
439 | };
440 | name = Release;
441 | };
442 | 50ADFF9D201F53D600D50D53 /* Debug */ = {
443 | isa = XCBuildConfiguration;
444 | baseConfigurationReference = 5E23F77F099397094342571A /* Pods-Plugin.debug.xcconfig */;
445 | buildSettings = {
446 | CLANG_ENABLE_MODULES = YES;
447 | CODE_SIGN_IDENTITY = "";
448 | CODE_SIGN_STYLE = Automatic;
449 | DEFINES_MODULE = YES;
450 | DYLIB_COMPATIBILITY_VERSION = 1;
451 | DYLIB_CURRENT_VERSION = 1;
452 | DYLIB_INSTALL_NAME_BASE = "@rpath";
453 | INFOPLIST_FILE = Plugin/Info.plist;
454 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
455 | IPHONEOS_DEPLOYMENT_TARGET = 14.0;
456 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks $(FRAMEWORK_SEARCH_PATHS)\n$(FRAMEWORK_SEARCH_PATHS)\n$(FRAMEWORK_SEARCH_PATHS)";
457 | ONLY_ACTIVE_ARCH = YES;
458 | PRODUCT_BUNDLE_IDENTIFIER = com.getcapacitor.Plugin;
459 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
460 | SKIP_INSTALL = YES;
461 | SUPPORTS_MACCATALYST = NO;
462 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
463 | SWIFT_VERSION = 5.0;
464 | TARGETED_DEVICE_FAMILY = "1,2";
465 | };
466 | name = Debug;
467 | };
468 | 50ADFF9E201F53D600D50D53 /* Release */ = {
469 | isa = XCBuildConfiguration;
470 | baseConfigurationReference = 91781294A431A2A7CC6EB714 /* Pods-Plugin.release.xcconfig */;
471 | buildSettings = {
472 | CLANG_ENABLE_MODULES = YES;
473 | CODE_SIGN_IDENTITY = "";
474 | CODE_SIGN_STYLE = Automatic;
475 | DEFINES_MODULE = YES;
476 | DYLIB_COMPATIBILITY_VERSION = 1;
477 | DYLIB_CURRENT_VERSION = 1;
478 | DYLIB_INSTALL_NAME_BASE = "@rpath";
479 | INFOPLIST_FILE = Plugin/Info.plist;
480 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
481 | IPHONEOS_DEPLOYMENT_TARGET = 14.0;
482 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks $(FRAMEWORK_SEARCH_PATHS)";
483 | ONLY_ACTIVE_ARCH = NO;
484 | PRODUCT_BUNDLE_IDENTIFIER = com.getcapacitor.Plugin;
485 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
486 | SKIP_INSTALL = YES;
487 | SUPPORTS_MACCATALYST = NO;
488 | SWIFT_VERSION = 5.0;
489 | TARGETED_DEVICE_FAMILY = "1,2";
490 | };
491 | name = Release;
492 | };
493 | 50ADFFA0201F53D600D50D53 /* Debug */ = {
494 | isa = XCBuildConfiguration;
495 | baseConfigurationReference = 96ED1B6440D6672E406C8D19 /* Pods-PluginTests.debug.xcconfig */;
496 | buildSettings = {
497 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
498 | CODE_SIGN_STYLE = Automatic;
499 | INFOPLIST_FILE = PluginTests/Info.plist;
500 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
501 | PRODUCT_BUNDLE_IDENTIFIER = com.getcapacitor.PluginTests;
502 | PRODUCT_NAME = "$(TARGET_NAME)";
503 | SWIFT_VERSION = 5.0;
504 | TARGETED_DEVICE_FAMILY = "1,2";
505 | };
506 | name = Debug;
507 | };
508 | 50ADFFA1201F53D600D50D53 /* Release */ = {
509 | isa = XCBuildConfiguration;
510 | baseConfigurationReference = F65BB2953ECE002E1EF3E424 /* Pods-PluginTests.release.xcconfig */;
511 | buildSettings = {
512 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
513 | CODE_SIGN_STYLE = Automatic;
514 | INFOPLIST_FILE = PluginTests/Info.plist;
515 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
516 | PRODUCT_BUNDLE_IDENTIFIER = com.getcapacitor.PluginTests;
517 | PRODUCT_NAME = "$(TARGET_NAME)";
518 | SWIFT_VERSION = 5.0;
519 | TARGETED_DEVICE_FAMILY = "1,2";
520 | };
521 | name = Release;
522 | };
523 | /* End XCBuildConfiguration section */
524 |
525 | /* Begin XCConfigurationList section */
526 | 50ADFF82201F53D600D50D53 /* Build configuration list for PBXProject "Plugin" */ = {
527 | isa = XCConfigurationList;
528 | buildConfigurations = (
529 | 50ADFF9A201F53D600D50D53 /* Debug */,
530 | 50ADFF9B201F53D600D50D53 /* Release */,
531 | );
532 | defaultConfigurationIsVisible = 0;
533 | defaultConfigurationName = Release;
534 | };
535 | 50ADFF9C201F53D600D50D53 /* Build configuration list for PBXNativeTarget "Plugin" */ = {
536 | isa = XCConfigurationList;
537 | buildConfigurations = (
538 | 50ADFF9D201F53D600D50D53 /* Debug */,
539 | 50ADFF9E201F53D600D50D53 /* Release */,
540 | );
541 | defaultConfigurationIsVisible = 0;
542 | defaultConfigurationName = Release;
543 | };
544 | 50ADFF9F201F53D600D50D53 /* Build configuration list for PBXNativeTarget "PluginTests" */ = {
545 | isa = XCConfigurationList;
546 | buildConfigurations = (
547 | 50ADFFA0201F53D600D50D53 /* Debug */,
548 | 50ADFFA1201F53D600D50D53 /* Release */,
549 | );
550 | defaultConfigurationIsVisible = 0;
551 | defaultConfigurationName = Release;
552 | };
553 | /* End XCConfigurationList section */
554 | };
555 | rootObject = 50ADFF7F201F53D600D50D53 /* Project object */;
556 | }
557 |
--------------------------------------------------------------------------------
/ios/Plugin.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Plugin/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | $(CURRENT_PROJECT_VERSION)
21 | NSPrincipalClass
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/ios/Plugin/Plugin.h:
--------------------------------------------------------------------------------
1 | #import
2 |
3 | //! Project version number for Plugin.
4 | FOUNDATION_EXPORT double PluginVersionNumber;
5 |
6 | //! Project version string for Plugin.
7 | FOUNDATION_EXPORT const unsigned char PluginVersionString[];
8 |
9 | // In this header, you should import all the public headers of your framework using statements like #import
10 |
11 |
--------------------------------------------------------------------------------
/ios/Plugin/Plugin.m:
--------------------------------------------------------------------------------
1 | #import
2 | #import
3 |
4 | // Define the plugin using the CAP_PLUGIN Macro, and
5 | // each method the plugin supports using the CAP_PLUGIN_METHOD macro.
6 | CAP_PLUGIN(SpeechRecognition, "SpeechRecognition",
7 | CAP_PLUGIN_METHOD(available, CAPPluginReturnPromise);
8 | CAP_PLUGIN_METHOD(start, CAPPluginReturnPromise);
9 | CAP_PLUGIN_METHOD(stop, CAPPluginReturnPromise);
10 | CAP_PLUGIN_METHOD(getSupportedLanguages, CAPPluginReturnPromise);
11 | CAP_PLUGIN_METHOD(hasPermission, CAPPluginReturnPromise);
12 | CAP_PLUGIN_METHOD(isListening, CAPPluginReturnPromise);
13 | CAP_PLUGIN_METHOD(requestPermission, CAPPluginReturnPromise);
14 | CAP_PLUGIN_METHOD(checkPermissions, CAPPluginReturnPromise);
15 | CAP_PLUGIN_METHOD(requestPermissions, CAPPluginReturnPromise);
16 | CAP_PLUGIN_METHOD(removeAllListeners, CAPPluginReturnPromise);
17 | )
18 |
--------------------------------------------------------------------------------
/ios/Plugin/Plugin.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 | import Capacitor
3 | import Speech
4 |
5 | @objc(SpeechRecognition)
6 | public class SpeechRecognition: CAPPlugin {
7 |
8 | let defaultMatches = 5
9 | let messageMissingPermission = "Missing permission"
10 | let messageAccessDenied = "User denied access to speech recognition"
11 | let messageRestricted = "Speech recognition restricted on this device"
12 | let messageNotDetermined = "Speech recognition not determined on this device"
13 | let messageAccessDeniedMicrophone = "User denied access to microphone"
14 | let messageOngoing = "Ongoing speech recognition"
15 | let messageUnknown = "Unknown error occured"
16 |
17 | private var speechRecognizer: SFSpeechRecognizer?
18 | private var audioEngine: AVAudioEngine?
19 | private var recognitionRequest: SFSpeechAudioBufferRecognitionRequest?
20 | private var recognitionTask: SFSpeechRecognitionTask?
21 |
22 | @objc func available(_ call: CAPPluginCall) {
23 | guard let recognizer = SFSpeechRecognizer() else {
24 | call.resolve([
25 | "available": false
26 | ])
27 | return
28 | }
29 | call.resolve([
30 | "available": recognizer.isAvailable
31 | ])
32 | }
33 |
34 | @objc func start(_ call: CAPPluginCall) {
35 | if self.audioEngine != nil {
36 | if self.audioEngine!.isRunning {
37 | call.reject(self.messageOngoing)
38 | return
39 | }
40 | }
41 |
42 | let status: SFSpeechRecognizerAuthorizationStatus = SFSpeechRecognizer.authorizationStatus()
43 | if status != SFSpeechRecognizerAuthorizationStatus.authorized {
44 | call.reject(self.messageMissingPermission)
45 | return
46 | }
47 |
48 | AVAudioSession.sharedInstance().requestRecordPermission { (granted) in
49 | if !granted {
50 | call.reject(self.messageAccessDeniedMicrophone)
51 | return
52 | }
53 |
54 | let language: String = call.getString("language") ?? "en-US"
55 | let maxResults: Int = call.getInt("maxResults") ?? self.defaultMatches
56 | let partialResults: Bool = call.getBool("partialResults") ?? false
57 |
58 | if self.recognitionTask != nil {
59 | self.recognitionTask?.cancel()
60 | self.recognitionTask = nil
61 | }
62 |
63 | self.audioEngine = AVAudioEngine.init()
64 | self.speechRecognizer = SFSpeechRecognizer.init(locale: Locale(identifier: language))
65 |
66 | let audioSession: AVAudioSession = AVAudioSession.sharedInstance()
67 | do {
68 | try audioSession.setCategory(AVAudioSession.Category.playAndRecord, options: AVAudioSession.CategoryOptions.defaultToSpeaker)
69 | try audioSession.setMode(AVAudioSession.Mode.default)
70 | do {
71 | try audioSession.setActive(true, options: AVAudioSession.SetActiveOptions.notifyOthersOnDeactivation)
72 | } catch {
73 | call.reject("Microphone is already in use by another application.")
74 | return
75 | }
76 | } catch {
77 |
78 | }
79 |
80 | self.recognitionRequest = SFSpeechAudioBufferRecognitionRequest()
81 | self.recognitionRequest?.shouldReportPartialResults = partialResults
82 |
83 | let inputNode: AVAudioInputNode = self.audioEngine!.inputNode
84 | let format: AVAudioFormat = inputNode.outputFormat(forBus: 0)
85 |
86 | self.recognitionTask = self.speechRecognizer?.recognitionTask(with: self.recognitionRequest!, resultHandler: { (result, error) in
87 | if result != nil {
88 | let resultArray: NSMutableArray = NSMutableArray()
89 | var counter: Int = 0
90 |
91 | for transcription: SFTranscription in result!.transcriptions {
92 | if maxResults > 0 && counter < maxResults {
93 | resultArray.add(transcription.formattedString)
94 | }
95 | counter+=1
96 | }
97 |
98 | if partialResults {
99 | self.notifyListeners("partialResults", data: ["matches": resultArray])
100 | } else {
101 | call.resolve([
102 | "matches": resultArray
103 | ])
104 | }
105 |
106 | if result!.isFinal {
107 | self.audioEngine!.stop()
108 | self.audioEngine?.inputNode.removeTap(onBus: 0)
109 | self.notifyListeners("listeningState", data: ["status": "stopped"])
110 | self.recognitionTask = nil
111 | self.recognitionRequest = nil
112 | }
113 | }
114 |
115 | if error != nil {
116 | self.audioEngine!.stop()
117 | self.audioEngine?.inputNode.removeTap(onBus: 0)
118 | self.recognitionRequest = nil
119 | self.recognitionTask = nil
120 | self.notifyListeners("listeningState", data: ["status": "stopped"])
121 | call.reject(error!.localizedDescription)
122 | }
123 | })
124 |
125 | inputNode.installTap(onBus: 0, bufferSize: 1024, format: format) { (buffer: AVAudioPCMBuffer, _: AVAudioTime) in
126 | self.recognitionRequest?.append(buffer)
127 | }
128 |
129 | self.audioEngine?.prepare()
130 | do {
131 | try self.audioEngine?.start()
132 | self.notifyListeners("listeningState", data: ["status": "started"])
133 | if partialResults {
134 | call.resolve()
135 | }
136 | } catch {
137 | call.reject(self.messageUnknown)
138 | }
139 | }
140 | }
141 |
142 | @objc func stop(_ call: CAPPluginCall) {
143 | DispatchQueue.global(qos: DispatchQoS.QoSClass.default).async {
144 | if let engine = self.audioEngine, engine.isRunning {
145 | engine.stop()
146 | self.recognitionRequest?.endAudio()
147 | self.notifyListeners("listeningState", data: ["status": "stopped"])
148 | }
149 | call.resolve()
150 | }
151 | }
152 |
153 | @objc func isListening(_ call: CAPPluginCall) {
154 | let isListening = self.audioEngine?.isRunning ?? false
155 | call.resolve([
156 | "listening": isListening
157 | ])
158 | }
159 |
160 | @objc func getSupportedLanguages(_ call: CAPPluginCall) {
161 | let supportedLanguages: Set! = SFSpeechRecognizer.supportedLocales() as Set
162 | let languagesArr: NSMutableArray = NSMutableArray()
163 |
164 | for lang: Locale in supportedLanguages {
165 | languagesArr.add(lang.identifier)
166 | }
167 |
168 | call.resolve([
169 | "languages": languagesArr
170 | ])
171 | }
172 |
173 | @objc override public func checkPermissions(_ call: CAPPluginCall) {
174 | let status: SFSpeechRecognizerAuthorizationStatus = SFSpeechRecognizer.authorizationStatus()
175 | let permission: String
176 | switch status {
177 | case .authorized:
178 | permission = "granted"
179 | case .denied, .restricted:
180 | permission = "denied"
181 | case .notDetermined:
182 | permission = "prompt"
183 | @unknown default:
184 | permission = "prompt"
185 | }
186 | call.resolve(["speechRecognition": permission])
187 | }
188 |
189 | @objc override public func requestPermissions(_ call: CAPPluginCall) {
190 | SFSpeechRecognizer.requestAuthorization { (status: SFSpeechRecognizerAuthorizationStatus) in
191 | DispatchQueue.main.async {
192 | switch status {
193 | case .authorized:
194 | AVAudioSession.sharedInstance().requestRecordPermission { (granted: Bool) in
195 | if granted {
196 | call.resolve(["speechRecognition": "granted"])
197 | } else {
198 | call.resolve(["speechRecognition": "denied"])
199 | }
200 | }
201 | break
202 | case .denied, .restricted, .notDetermined:
203 | self.checkPermissions(call)
204 | break
205 | @unknown default:
206 | self.checkPermissions(call)
207 | }
208 | }
209 | }
210 | }
211 | }
212 |
--------------------------------------------------------------------------------
/ios/PluginTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/ios/PluginTests/PluginTests.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | import Capacitor
3 | @testable import Plugin
4 |
5 | class PluginTests: XCTestCase {
6 |
7 | func testEcho() {
8 | // This is an example of a functional test case for a plugin.
9 | // Use XCTAssert and related functions to verify your tests produce the correct results.
10 |
11 | let value = "Hello, World!"
12 | let plugin = MyPlugin()
13 |
14 | let call = CAPPluginCall(callbackId: "test", options: [
15 | "value": value
16 | ], resolve: { (result, _) in
17 | let resultValue = result!.data["value"] as? String
18 | XCTAssertEqual(value, resultValue)
19 | }, reject: { (_) in
20 | XCTFail("Error shouldn't have been called")
21 | })
22 |
23 | plugin.echo(call!)
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/ios/Podfile:
--------------------------------------------------------------------------------
1 | platform :ios, '14.0'
2 |
3 | def capacitor_pods
4 | # Comment the next line if you're not using Swift and don't want to use dynamic frameworks
5 | use_frameworks!
6 | pod 'Capacitor', :path => '../node_modules/@capacitor/ios'
7 | pod 'CapacitorCordova', :path => '../node_modules/@capacitor/ios'
8 | end
9 |
10 | target 'Plugin' do
11 | capacitor_pods
12 | end
13 |
14 | target 'PluginTests' do
15 | capacitor_pods
16 | end
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@capacitor-community/speech-recognition",
3 | "version": "7.0.1",
4 | "description": "A native plugin for speech recognition",
5 | "main": "dist/plugin.cjs.js",
6 | "module": "dist/esm/index.js",
7 | "types": "dist/esm/index.d.ts",
8 | "unpkg": "dist/plugin.js",
9 | "files": [
10 | "android/src/main/",
11 | "android/build.gradle",
12 | "dist/",
13 | "ios/Plugin/",
14 | "CapacitorCommunitySpeechRecognition.podspec"
15 | ],
16 | "author": "Priyank Patel ",
17 | "contributors": [
18 | "Matteo Padovano "
19 | ],
20 | "license": "MIT",
21 | "repository": {
22 | "type": "git",
23 | "url": "git+https://github.com/capacitor-community/speech-recognition.git"
24 | },
25 | "bugs": {
26 | "url": "https://github.com/capacitor-community/speech-recognition/issues"
27 | },
28 | "keywords": [
29 | "capacitor",
30 | "plugin",
31 | "native"
32 | ],
33 | "scripts": {
34 | "verify": "npm run verify:ios && npm run verify:android && npm run verify:web",
35 | "verify:ios": "cd ios && pod install && xcodebuild -workspace Plugin.xcworkspace -scheme Plugin -destination generic/platform=iOS && cd ..",
36 | "verify:android": "cd android && ./gradlew clean build test && cd ..",
37 | "verify:web": "npm run build",
38 | "lint": "npm run eslint && npm run prettier -- --check && npm run swiftlint -- lint",
39 | "fmt": "npm run eslint -- --fix && npm run prettier -- --write && npm run swiftlint -- --fix --format",
40 | "eslint": "eslint . --ext ts",
41 | "prettier": "prettier \"**/*.{css,html,ts,js,java}\" --plugin=prettier-plugin-java",
42 | "swiftlint": "node-swiftlint",
43 | "docgen": "docgen --api SpeechRecognitionPlugin --output-readme README.md --output-json dist/docs.json",
44 | "build": "npm run clean && npm run docgen && tsc && rollup -c rollup.config.mjs",
45 | "clean": "rimraf ./dist",
46 | "watch": "tsc --watch",
47 | "prepublishOnly": "npm run build",
48 | "release": "standard-version"
49 | },
50 | "devDependencies": {
51 | "@capacitor/android": "^7.0.0",
52 | "@capacitor/cli": "^7.0.0",
53 | "@capacitor/core": "^7.0.0",
54 | "@capacitor/docgen": "^0.3.0",
55 | "@capacitor/ios": "^7.0.0",
56 | "@ionic/eslint-config": "^0.4.0",
57 | "@ionic/prettier-config": "^4.0.0",
58 | "@ionic/swiftlint-config": "^2.0.0",
59 | "eslint": "^8.57.0",
60 | "prettier": "^3.4.2",
61 | "prettier-plugin-java": "^2.6.6",
62 | "rimraf": "^6.0.1",
63 | "rollup": "^4.30.1",
64 | "standard-version": "9.5.0",
65 | "swiftlint": "^2.0.0",
66 | "typescript": "4.1.5"
67 | },
68 | "peerDependencies": {
69 | "@capacitor/core": ">=7.0.0"
70 | },
71 | "prettier": "@ionic/prettier-config",
72 | "swiftlint": "@ionic/swiftlint-config",
73 | "eslintConfig": {
74 | "extends": "@ionic/eslint-config/recommended"
75 | },
76 | "capacitor": {
77 | "ios": {
78 | "src": "ios"
79 | },
80 | "android": {
81 | "src": "android"
82 | }
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/rollup.config.mjs:
--------------------------------------------------------------------------------
1 | export default {
2 | input: 'dist/esm/index.js',
3 | output: [
4 | {
5 | file: 'dist/plugin.js',
6 | format: 'iife',
7 | name: 'capacitorSpeechRecognition',
8 | globals: {
9 | '@capacitor/core': 'capacitorExports',
10 | },
11 | sourcemap: true,
12 | inlineDynamicImports: true,
13 | },
14 | {
15 | file: 'dist/plugin.cjs.js',
16 | format: 'cjs',
17 | sourcemap: true,
18 | inlineDynamicImports: true,
19 | },
20 | ],
21 | external: ['@capacitor/core'],
22 | };
23 |
--------------------------------------------------------------------------------
/src/definitions.ts:
--------------------------------------------------------------------------------
1 | import type { PermissionState, PluginListenerHandle } from '@capacitor/core';
2 |
3 | export interface PermissionStatus {
4 | /**
5 | * Permission state for speechRecognition alias.
6 | *
7 | * On Android it requests/checks RECORD_AUDIO permission
8 | *
9 | * On iOS it requests/checks the speech recognition and microphone permissions.
10 | *
11 | * @since 5.0.0
12 | */
13 | speechRecognition: PermissionState;
14 | }
15 |
16 | export interface SpeechRecognitionPlugin {
17 | /**
18 | * This method will check if speech recognition feature is available on the device.
19 | * @param none
20 | * @returns available - boolean true/false for availability
21 | */
22 | available(): Promise<{ available: boolean }>;
23 | /**
24 | * This method will start to listen for utterance.
25 | *
26 | * if `partialResults` is `true`, the function respond directly without result and
27 | * event `partialResults` will be emit for each partial result, until stopped.
28 | *
29 | * @param options
30 | * @returns void or array of string results
31 | */
32 | start(options?: UtteranceOptions): Promise<{ matches?: string[] }>;
33 | /**
34 | * This method will stop listening for utterance
35 | * @param none
36 | * @returns void
37 | */
38 | stop(): Promise;
39 | /**
40 | * This method will return list of languages supported by the speech recognizer.
41 | *
42 | * It's not available on Android 13 and newer.
43 | *
44 | * @param none
45 | * @returns languages - array string of languages
46 | */
47 | getSupportedLanguages(): Promise<{ languages: any[] }>;
48 | /**
49 | * This method will check if speech recognition is listening.
50 | * @param none
51 | * @returns boolean true/false if speech recognition is currently listening
52 | *
53 | * @since 5.1.0
54 | */
55 | isListening(): Promise<{ listening: boolean }>;
56 | /**
57 | * Check the speech recognition permission.
58 | *
59 | * @since 5.0.0
60 | */
61 | checkPermissions(): Promise;
62 | /**
63 | * Request the speech recognition permission.
64 | *
65 | * @since 5.0.0
66 | */
67 | requestPermissions(): Promise;
68 | /**
69 | * Called when partialResults set to true and result received.
70 | *
71 | * On Android it doesn't work if popup is true.
72 | *
73 | * Provides partial result.
74 | *
75 | * @since 2.0.2
76 | */
77 | addListener(
78 | eventName: 'partialResults',
79 | listenerFunc: (data: { matches: string[] }) => void,
80 | ): Promise;
81 |
82 | /**
83 | * Called when listening state changed.
84 | *
85 | * @since 5.1.0
86 | */
87 | addListener(
88 | eventName: 'listeningState',
89 | listenerFunc: (data: { status: 'started' | 'stopped' }) => void,
90 | ): Promise;
91 | /**
92 | * Remove all the listeners that are attached to this plugin.
93 | *
94 | * @since 4.0.0
95 | */
96 | removeAllListeners(): Promise;
97 | }
98 |
99 | export interface UtteranceOptions {
100 | /**
101 | * key returned from `getSupportedLanguages()`
102 | */
103 | language?: string;
104 | /**
105 | * maximum number of results to return (5 is max)
106 | */
107 | maxResults?: number;
108 | /**
109 | * prompt message to display on popup (Android only)
110 | */
111 | prompt?: string;
112 | /**
113 | * display popup window when listening for utterance (Android only)
114 | */
115 | popup?: boolean;
116 | /**
117 | * return partial results if found
118 | */
119 | partialResults?: boolean;
120 | }
121 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | import { registerPlugin } from '@capacitor/core';
2 |
3 | import type { SpeechRecognitionPlugin } from './definitions';
4 |
5 | const SpeechRecognition = registerPlugin('SpeechRecognition', {
6 | web: () => import('./web').then((m) => new m.SpeechRecognitionWeb()),
7 | });
8 |
9 | export * from './definitions';
10 | export { SpeechRecognition };
11 |
--------------------------------------------------------------------------------
/src/web.ts:
--------------------------------------------------------------------------------
1 | import { WebPlugin } from '@capacitor/core';
2 |
3 | import type { PermissionStatus, SpeechRecognitionPlugin, UtteranceOptions } from './definitions';
4 |
5 | export class SpeechRecognitionWeb extends WebPlugin implements SpeechRecognitionPlugin {
6 | available(): Promise<{ available: boolean }> {
7 | throw this.unimplemented('Method not implemented on web.');
8 | }
9 | start(_options?: UtteranceOptions): Promise<{ matches?: string[] }> {
10 | throw this.unimplemented('Method not implemented on web.');
11 | }
12 | stop(): Promise {
13 | throw this.unimplemented('Method not implemented on web.');
14 | }
15 | getSupportedLanguages(): Promise<{ languages: any[] }> {
16 | throw this.unimplemented('Method not implemented on web.');
17 | }
18 | hasPermission(): Promise<{ permission: boolean }> {
19 | throw this.unimplemented('Method not implemented on web.');
20 | }
21 | isListening(): Promise<{ listening: boolean }> {
22 | throw this.unimplemented('Method not implemented on web.');
23 | }
24 | requestPermission(): Promise {
25 | throw this.unimplemented('Method not implemented on web.');
26 | }
27 | checkPermissions(): Promise {
28 | throw this.unimplemented('Method not implemented on web.');
29 | }
30 | requestPermissions(): Promise {
31 | throw this.unimplemented('Method not implemented on web.');
32 | }
33 | }
34 |
35 | const SpeechRecognition = new SpeechRecognitionWeb();
36 |
37 | export { SpeechRecognition };
38 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "allowUnreachableCode": false,
4 | "declaration": true,
5 | "esModuleInterop": true,
6 | "inlineSources": true,
7 | "lib": ["dom", "es2017"],
8 | "module": "esnext",
9 | "moduleResolution": "node",
10 | "noFallthroughCasesInSwitch": true,
11 | "noUnusedLocals": true,
12 | "noUnusedParameters": true,
13 | "outDir": "dist/esm",
14 | "pretty": true,
15 | "sourceMap": true,
16 | "strict": true,
17 | "target": "es2017"
18 | },
19 | "files": ["src/index.ts"]
20 | }
21 |
--------------------------------------------------------------------------------