@capawesome/capacitor-password-autofill 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/CapawesomeCapacitorPasswordAutofill.podspec +17 -0
  2. package/LICENSE +21 -0
  3. package/Package.swift +28 -0
  4. package/README.md +193 -0
  5. package/android/build.gradle +61 -0
  6. package/android/src/main/AndroidManifest.xml +2 -0
  7. package/android/src/main/java/io/capawesome/capacitorjs/plugins/passwordautofill/PasswordAutofill.java +49 -0
  8. package/android/src/main/java/io/capawesome/capacitorjs/plugins/passwordautofill/PasswordAutofillPlugin.java +64 -0
  9. package/android/src/main/java/io/capawesome/capacitorjs/plugins/passwordautofill/classes/CustomException.java +20 -0
  10. package/android/src/main/java/io/capawesome/capacitorjs/plugins/passwordautofill/classes/CustomExceptions.java +15 -0
  11. package/android/src/main/java/io/capawesome/capacitorjs/plugins/passwordautofill/classes/options/SavePasswordOptions.java +47 -0
  12. package/android/src/main/java/io/capawesome/capacitorjs/plugins/passwordautofill/interfaces/Callback.java +5 -0
  13. package/android/src/main/java/io/capawesome/capacitorjs/plugins/passwordautofill/interfaces/EmptyCallback.java +5 -0
  14. package/android/src/main/res/.gitkeep +0 -0
  15. package/dist/docs.json +97 -0
  16. package/dist/esm/definitions.d.ts +66 -0
  17. package/dist/esm/definitions.js +19 -0
  18. package/dist/esm/definitions.js.map +1 -0
  19. package/dist/esm/index.d.ts +4 -0
  20. package/dist/esm/index.js +7 -0
  21. package/dist/esm/index.js.map +1 -0
  22. package/dist/esm/web.d.ts +5 -0
  23. package/dist/esm/web.js +7 -0
  24. package/dist/esm/web.js.map +1 -0
  25. package/dist/plugin.cjs.js +40 -0
  26. package/dist/plugin.cjs.js.map +1 -0
  27. package/dist/plugin.js +43 -0
  28. package/dist/plugin.js.map +1 -0
  29. package/ios/Plugin/Classes/Options/SavePasswordOptions.swift +35 -0
  30. package/ios/Plugin/Enums/CustomError.swift +32 -0
  31. package/ios/Plugin/Info.plist +24 -0
  32. package/ios/Plugin/PasswordAutofill.swift +23 -0
  33. package/ios/Plugin/PasswordAutofillPlugin.swift +44 -0
  34. package/ios/Plugin/Protocols/Result.swift +5 -0
  35. package/package.json +91 -0
@@ -0,0 +1,17 @@
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 = 'CapawesomeCapacitorPasswordAutofill'
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 = '15.0'
15
+ s.dependency 'Capacitor'
16
+ s.swift_version = '5.1'
17
+ end
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Robin Genz
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.
package/Package.swift ADDED
@@ -0,0 +1,28 @@
1
+ // swift-tools-version: 5.9
2
+ import PackageDescription
3
+
4
+ let package = Package(
5
+ name: "CapawesomeCapacitorPasswordAutofill",
6
+ platforms: [.iOS(.v15)],
7
+ products: [
8
+ .library(
9
+ name: "CapawesomeCapacitorPasswordAutofill",
10
+ targets: ["PasswordAutofillPlugin"])
11
+ ],
12
+ dependencies: [
13
+ .package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", from: "8.0.0")
14
+ ],
15
+ targets: [
16
+ .target(
17
+ name: "PasswordAutofillPlugin",
18
+ dependencies: [
19
+ .product(name: "Capacitor", package: "capacitor-swift-pm"),
20
+ .product(name: "Cordova", package: "capacitor-swift-pm")
21
+ ],
22
+ path: "ios/Plugin"),
23
+ .testTarget(
24
+ name: "PasswordAutofillPluginTests",
25
+ dependencies: ["PasswordAutofillPlugin"],
26
+ path: "ios/PluginTests")
27
+ ]
28
+ )
package/README.md ADDED
@@ -0,0 +1,193 @@
1
+ # @capawesome/capacitor-password-autofill
2
+
3
+ Capacitor plugin for saving passwords to the platform credential store.
4
+
5
+ This plugin lets you **save into** the platform autofill system (iCloud Keychain on iOS, Google Password Manager on Android) after a successful in-app login. It does **not** fill forms — it solves the well-known problem that WebView-based apps never trigger the native "Save password?" prompt.
6
+
7
+ <div class="capawesome-z29o10a">
8
+ <a href="https://cloud.capawesome.io/" target="_blank">
9
+ <img alt="Deliver Live Updates to your Capacitor app with Capawesome Cloud" src="https://cloud.capawesome.io/assets/banners/cloud-build-and-deploy-capacitor-apps.png?t=1" />
10
+ </a>
11
+ </div>
12
+
13
+ ## Features
14
+
15
+ We are proud to offer one of the most complete and feature-rich Capacitor plugins for password autofill. Here are some of the key features:
16
+
17
+ - 🖥️ **Cross-platform**: Supports Android and iOS.
18
+ - 🔐 **Credential saving**: Save a username and password to the platform credential store.
19
+ - 🎯 **Deterministic**: Trigger the save prompt explicitly after a successful login, even for non-form flows.
20
+ - 📦 **CocoaPods & SPM**: Supports CocoaPods and Swift Package Manager for iOS.
21
+ - 🔁 **Up-to-date**: Always supports the latest Capacitor version.
22
+
23
+ Missing a feature? Just [open an issue](https://github.com/capawesome-team/capacitor-plugins/issues) and we'll take a look!
24
+
25
+ ## Newsletter
26
+
27
+ Stay up to date with the latest news and updates about the Capawesome, Capacitor, and Ionic ecosystem by subscribing to our [Capawesome Newsletter](https://cloud.capawesome.io/newsletter/).
28
+
29
+ ## Compatibility
30
+
31
+ | Plugin Version | Capacitor Version | Status |
32
+ | -------------- | ----------------- | -------------- |
33
+ | 0.x.x | >=8.x.x | Active support |
34
+
35
+ ## Installation
36
+
37
+ You can use our **AI-Assisted Setup** to install the plugin.
38
+ Add the [Capawesome Skills](https://github.com/capawesome-team/skills) to your AI tool using the following command:
39
+
40
+ ```bash
41
+ npx skills add capawesome-team/skills --skill capacitor-plugins
42
+ ```
43
+
44
+ Then use the following prompt:
45
+
46
+ ```
47
+ Use the `capacitor-plugins` skill from `capawesome-team/skills` to install the `@capawesome/capacitor-password-autofill` plugin in my project.
48
+ ```
49
+
50
+ If you prefer **Manual Setup**, install the plugin by running the following commands and follow the platform-specific instructions below:
51
+
52
+ ```bash
53
+ npm install @capawesome/capacitor-password-autofill
54
+ npx cap sync
55
+ ```
56
+
57
+ This plugin is only available on **Android** and **iOS**. On Web, all methods reject as unimplemented.
58
+
59
+ ### Android
60
+
61
+ #### Variables
62
+
63
+ This plugin will use the following project variables (defined in your app's `variables.gradle` file):
64
+
65
+ - `$androidxCredentials` version of `androidx.credentials:credentials` and `androidx.credentials:credentials-play-services-auth` (default: `1.5.0`)
66
+
67
+ No further setup is required. On Android, saving a credential presents the system "Save password?" prompt provided by the active credential provider (e.g. Google Password Manager).
68
+
69
+ ### iOS
70
+
71
+ The Shared Web Credentials API requires the **Associated Domains** capability and a matching `apple-app-site-association` (AASA) file. Without this setup, `savePassword(...)` cannot save the credential.
72
+
73
+ #### Associated Domains
74
+
75
+ Add the Associated Domains entitlement to your app and include a `webcredentials:` entry for each domain you want to save credentials for:
76
+
77
+ ```xml
78
+ <key>com.apple.developer.associated-domains</key>
79
+ <array>
80
+ <string>webcredentials:example.com</string>
81
+ </array>
82
+ ```
83
+
84
+ The `domain` you pass to `savePassword(...)` must match one of these entries (without the `webcredentials:` prefix).
85
+
86
+ #### Apple App Site Association
87
+
88
+ Host an `apple-app-site-association` file at `https://example.com/.well-known/apple-app-site-association` that lists your app under the `webcredentials` service:
89
+
90
+ ```json
91
+ {
92
+ "webcredentials": {
93
+ "apps": ["TEAMID.com.example.app"]
94
+ }
95
+ }
96
+ ```
97
+
98
+ Replace `TEAMID` with your Apple Developer Team ID and `com.example.app` with your app's bundle identifier. See the [Apple documentation](https://developer.apple.com/documentation/xcode/supporting-associated-domains) for more information.
99
+
100
+ ## Configuration
101
+
102
+ No configuration required for this plugin.
103
+
104
+ ## Usage
105
+
106
+ ```typescript
107
+ import { PasswordAutofill } from '@capawesome/capacitor-password-autofill';
108
+
109
+ const savePassword = async () => {
110
+ await PasswordAutofill.savePassword({
111
+ domain: 'example.com',
112
+ username: 'jane.doe@example.com',
113
+ password: 'super-secret',
114
+ });
115
+ };
116
+ ```
117
+
118
+ ## API
119
+
120
+ <docgen-index>
121
+
122
+ * [`savePassword(...)`](#savepassword)
123
+ * [Interfaces](#interfaces)
124
+
125
+ </docgen-index>
126
+
127
+ <docgen-api>
128
+ <!--Update the source file JSDoc comments and rerun docgen to update the docs below-->
129
+
130
+ ### savePassword(...)
131
+
132
+ ```typescript
133
+ savePassword(options: SavePasswordOptions) => Promise<void>
134
+ ```
135
+
136
+ Save a username and password to the platform credential store.
137
+
138
+ On iOS, the credential is saved to the iCloud Keychain via the
139
+ Shared Web Credentials API. This requires the Associated Domains
140
+ entitlement with a `webcredentials:` entry and a matching
141
+ `apple-app-site-association` file hosted on your domain.
142
+
143
+ On Android, the credential is saved to the Google Password Manager
144
+ (or another provider) via the Credential Manager API. This presents
145
+ the system "Save password?" prompt to the user.
146
+
147
+ Only available on Android and iOS.
148
+
149
+ | Param | Type |
150
+ | ------------- | ------------------------------------------------------------------- |
151
+ | **`options`** | <code><a href="#savepasswordoptions">SavePasswordOptions</a></code> |
152
+
153
+ **Since:** 0.1.0
154
+
155
+ --------------------
156
+
157
+
158
+ ### Interfaces
159
+
160
+
161
+ #### SavePasswordOptions
162
+
163
+ | Prop | Type | Description | Since |
164
+ | -------------- | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----- |
165
+ | **`domain`** | <code>string</code> | The domain to associate the credential with. This must match one of the domains in your app's Associated Domains entitlement (without the `webcredentials:` prefix). Only available on iOS (required). | 0.1.0 |
166
+ | **`password`** | <code>string</code> | The password to save. | 0.1.0 |
167
+ | **`username`** | <code>string</code> | The username to save. | 0.1.0 |
168
+
169
+ </docgen-api>
170
+
171
+ ## When to use this plugin vs. the official guide
172
+
173
+ The [official Capacitor autofill guide](https://capacitorjs.com/docs/guides/autofill-credentials) saves credentials by relying on the operating system's form heuristics. This requires changing `server.hostname` to your real domain, which:
174
+
175
+ - changes the WebView origin and therefore wipes existing users' `localStorage`, `IndexedDB`, and cookies, and
176
+ - can break OAuth redirect allowlists.
177
+
178
+ It also depends on iOS detecting a form submission followed by a navigation — something typical single-page app logins (`fetch()` + `preventDefault()`) never trigger.
179
+
180
+ This plugin takes a different approach: **deterministic credential saving without changing the WebView origin**. Your app keeps `localhost` as its origin, and you call `savePassword(...)` explicitly after a successful login. This also covers non-form flows such as social signup with generated passwords.
181
+
182
+ What this plugin does **not** replace:
183
+
184
+ - The Associated Domains / `apple-app-site-association` setup is required in both approaches.
185
+ - Autofill (reading credentials back into a form) still benefits from the `autocomplete` attributes described in the official guide.
186
+
187
+ ## Changelog
188
+
189
+ See [CHANGELOG.md](https://github.com/capawesome-team/capacitor-plugins/blob/main/packages/password-autofill/CHANGELOG.md).
190
+
191
+ ## License
192
+
193
+ See [LICENSE](https://github.com/capawesome-team/capacitor-plugins/blob/main/packages/password-autofill/LICENSE).
@@ -0,0 +1,61 @@
1
+ ext {
2
+ junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.2'
3
+ androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.7.1'
4
+ androidxCredentialsVersion = project.hasProperty('androidxCredentialsVersion') ? rootProject.ext.androidxCredentialsVersion : '1.5.0'
5
+ androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.3.0'
6
+ androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.7.0'
7
+ }
8
+
9
+ buildscript {
10
+ repositories {
11
+ google()
12
+ mavenCentral()
13
+ }
14
+ dependencies {
15
+ classpath 'com.android.tools.build:gradle:8.13.0'
16
+ }
17
+ }
18
+
19
+ apply plugin: 'com.android.library'
20
+
21
+ android {
22
+ namespace = "io.capawesome.capacitorjs.plugins.passwordautofill"
23
+ compileSdk = project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 36
24
+ defaultConfig {
25
+ minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 24
26
+ targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 36
27
+ versionCode 1
28
+ versionName "1.0"
29
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
30
+ }
31
+ buildTypes {
32
+ release {
33
+ minifyEnabled false
34
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
35
+ }
36
+ }
37
+ lintOptions {
38
+ abortOnError = false
39
+ }
40
+ compileOptions {
41
+ sourceCompatibility JavaVersion.VERSION_21
42
+ targetCompatibility JavaVersion.VERSION_21
43
+ }
44
+ }
45
+
46
+ repositories {
47
+ google()
48
+ mavenCentral()
49
+ }
50
+
51
+
52
+ dependencies {
53
+ implementation fileTree(dir: 'libs', include: ['*.jar'])
54
+ implementation project(':capacitor-android')
55
+ implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"
56
+ implementation "androidx.credentials:credentials:$androidxCredentialsVersion"
57
+ implementation "androidx.credentials:credentials-play-services-auth:$androidxCredentialsVersion"
58
+ testImplementation "junit:junit:$junitVersion"
59
+ androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion"
60
+ androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion"
61
+ }
@@ -0,0 +1,2 @@
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android">
2
+ </manifest>
@@ -0,0 +1,49 @@
1
+ package io.capawesome.capacitorjs.plugins.passwordautofill;
2
+
3
+ import androidx.annotation.NonNull;
4
+ import androidx.credentials.CreateCredentialResponse;
5
+ import androidx.credentials.CreatePasswordRequest;
6
+ import androidx.credentials.CredentialManager;
7
+ import androidx.credentials.CredentialManagerCallback;
8
+ import androidx.credentials.exceptions.CreateCredentialCancellationException;
9
+ import androidx.credentials.exceptions.CreateCredentialException;
10
+ import io.capawesome.capacitorjs.plugins.passwordautofill.classes.CustomExceptions;
11
+ import io.capawesome.capacitorjs.plugins.passwordautofill.classes.options.SavePasswordOptions;
12
+ import io.capawesome.capacitorjs.plugins.passwordautofill.interfaces.EmptyCallback;
13
+
14
+ public class PasswordAutofill {
15
+
16
+ @NonNull
17
+ private final PasswordAutofillPlugin plugin;
18
+
19
+ public PasswordAutofill(@NonNull PasswordAutofillPlugin plugin) {
20
+ this.plugin = plugin;
21
+ }
22
+
23
+ public void savePassword(@NonNull SavePasswordOptions options, @NonNull EmptyCallback callback) {
24
+ CreatePasswordRequest request = new CreatePasswordRequest(options.getUsername(), options.getPassword());
25
+ CredentialManager credentialManager = CredentialManager.create(plugin.getContext());
26
+ credentialManager.createCredentialAsync(
27
+ plugin.getActivity(),
28
+ request,
29
+ null,
30
+ Runnable::run,
31
+ new CredentialManagerCallback<CreateCredentialResponse, CreateCredentialException>() {
32
+ @Override
33
+ public void onResult(@NonNull CreateCredentialResponse response) {
34
+ callback.success();
35
+ }
36
+
37
+ @Override
38
+ public void onError(@NonNull CreateCredentialException exception) {
39
+ if (exception instanceof CreateCredentialCancellationException) {
40
+ callback.error(CustomExceptions.CANCELED);
41
+ } else {
42
+ String message = exception.getMessage();
43
+ callback.error(CustomExceptions.saveFailed(message == null ? "The credential could not be saved." : message));
44
+ }
45
+ }
46
+ }
47
+ );
48
+ }
49
+ }
@@ -0,0 +1,64 @@
1
+ package io.capawesome.capacitorjs.plugins.passwordautofill;
2
+
3
+ import androidx.annotation.NonNull;
4
+ import com.getcapacitor.Logger;
5
+ import com.getcapacitor.Plugin;
6
+ import com.getcapacitor.PluginCall;
7
+ import com.getcapacitor.PluginMethod;
8
+ import com.getcapacitor.annotation.CapacitorPlugin;
9
+ import io.capawesome.capacitorjs.plugins.passwordautofill.classes.CustomException;
10
+ import io.capawesome.capacitorjs.plugins.passwordautofill.classes.options.SavePasswordOptions;
11
+ import io.capawesome.capacitorjs.plugins.passwordautofill.interfaces.EmptyCallback;
12
+
13
+ @CapacitorPlugin(name = "PasswordAutofill")
14
+ public class PasswordAutofillPlugin extends Plugin {
15
+
16
+ public static final String ERROR_UNKNOWN_ERROR = "An unknown error has occurred.";
17
+ public static final String TAG = "PasswordAutofillPlugin";
18
+
19
+ private PasswordAutofill implementation;
20
+
21
+ @Override
22
+ public void load() {
23
+ super.load();
24
+ this.implementation = new PasswordAutofill(this);
25
+ }
26
+
27
+ @PluginMethod
28
+ public void savePassword(PluginCall call) {
29
+ try {
30
+ SavePasswordOptions options = new SavePasswordOptions(call);
31
+ EmptyCallback callback = new EmptyCallback() {
32
+ @Override
33
+ public void success() {
34
+ resolveCall(call);
35
+ }
36
+
37
+ @Override
38
+ public void error(Exception exception) {
39
+ rejectCall(call, exception);
40
+ }
41
+ };
42
+ implementation.savePassword(options, callback);
43
+ } catch (Exception exception) {
44
+ rejectCall(call, exception);
45
+ }
46
+ }
47
+
48
+ private void rejectCall(@NonNull PluginCall call, @NonNull Exception exception) {
49
+ String message = exception.getMessage();
50
+ if (message == null) {
51
+ message = ERROR_UNKNOWN_ERROR;
52
+ }
53
+ String code = null;
54
+ if (exception instanceof CustomException) {
55
+ code = ((CustomException) exception).getCode();
56
+ }
57
+ Logger.error(TAG, message, exception);
58
+ call.reject(message, code);
59
+ }
60
+
61
+ private void resolveCall(@NonNull PluginCall call) {
62
+ call.resolve();
63
+ }
64
+ }
@@ -0,0 +1,20 @@
1
+ package io.capawesome.capacitorjs.plugins.passwordautofill.classes;
2
+
3
+ import androidx.annotation.NonNull;
4
+ import androidx.annotation.Nullable;
5
+
6
+ public class CustomException extends Exception {
7
+
8
+ @Nullable
9
+ private final String code;
10
+
11
+ public CustomException(@Nullable String code, @NonNull String message) {
12
+ super(message);
13
+ this.code = code;
14
+ }
15
+
16
+ @Nullable
17
+ public String getCode() {
18
+ return code;
19
+ }
20
+ }
@@ -0,0 +1,15 @@
1
+ package io.capawesome.capacitorjs.plugins.passwordautofill.classes;
2
+
3
+ import androidx.annotation.NonNull;
4
+
5
+ public class CustomExceptions {
6
+
7
+ public static final CustomException CANCELED = new CustomException("CANCELED", "The user canceled the save operation.");
8
+ public static final CustomException PASSWORD_MISSING = new CustomException(null, "password must be provided.");
9
+ public static final CustomException USERNAME_MISSING = new CustomException(null, "username must be provided.");
10
+
11
+ @NonNull
12
+ public static CustomException saveFailed(@NonNull String message) {
13
+ return new CustomException("SAVE_FAILED", message);
14
+ }
15
+ }
@@ -0,0 +1,47 @@
1
+ package io.capawesome.capacitorjs.plugins.passwordautofill.classes.options;
2
+
3
+ import androidx.annotation.NonNull;
4
+ import com.getcapacitor.PluginCall;
5
+ import io.capawesome.capacitorjs.plugins.passwordautofill.classes.CustomExceptions;
6
+
7
+ public class SavePasswordOptions {
8
+
9
+ @NonNull
10
+ private final String password;
11
+
12
+ @NonNull
13
+ private final String username;
14
+
15
+ public SavePasswordOptions(@NonNull PluginCall call) throws Exception {
16
+ this.password = getPasswordFromCall(call);
17
+ this.username = getUsernameFromCall(call);
18
+ }
19
+
20
+ @NonNull
21
+ public String getPassword() {
22
+ return password;
23
+ }
24
+
25
+ @NonNull
26
+ public String getUsername() {
27
+ return username;
28
+ }
29
+
30
+ @NonNull
31
+ private static String getPasswordFromCall(@NonNull PluginCall call) throws Exception {
32
+ String password = call.getString("password");
33
+ if (password == null) {
34
+ throw CustomExceptions.PASSWORD_MISSING;
35
+ }
36
+ return password;
37
+ }
38
+
39
+ @NonNull
40
+ private static String getUsernameFromCall(@NonNull PluginCall call) throws Exception {
41
+ String username = call.getString("username");
42
+ if (username == null) {
43
+ throw CustomExceptions.USERNAME_MISSING;
44
+ }
45
+ return username;
46
+ }
47
+ }
@@ -0,0 +1,5 @@
1
+ package io.capawesome.capacitorjs.plugins.passwordautofill.interfaces;
2
+
3
+ public interface Callback {
4
+ void error(Exception exception);
5
+ }
@@ -0,0 +1,5 @@
1
+ package io.capawesome.capacitorjs.plugins.passwordautofill.interfaces;
2
+
3
+ public interface EmptyCallback extends Callback {
4
+ void success();
5
+ }
File without changes
package/dist/docs.json ADDED
@@ -0,0 +1,97 @@
1
+ {
2
+ "api": {
3
+ "name": "PasswordAutofillPlugin",
4
+ "slug": "passwordautofillplugin",
5
+ "docs": "",
6
+ "tags": [],
7
+ "methods": [
8
+ {
9
+ "name": "savePassword",
10
+ "signature": "(options: SavePasswordOptions) => Promise<void>",
11
+ "parameters": [
12
+ {
13
+ "name": "options",
14
+ "docs": "",
15
+ "type": "SavePasswordOptions"
16
+ }
17
+ ],
18
+ "returns": "Promise<void>",
19
+ "tags": [
20
+ {
21
+ "name": "since",
22
+ "text": "0.1.0"
23
+ }
24
+ ],
25
+ "docs": "Save a username and password to the platform credential store.\n\nOn iOS, the credential is saved to the iCloud Keychain via the\nShared Web Credentials API. This requires the Associated Domains\nentitlement with a `webcredentials:` entry and a matching\n`apple-app-site-association` file hosted on your domain.\n\nOn Android, the credential is saved to the Google Password Manager\n(or another provider) via the Credential Manager API. This presents\nthe system \"Save password?\" prompt to the user.\n\nOnly available on Android and iOS.",
26
+ "complexTypes": [
27
+ "SavePasswordOptions"
28
+ ],
29
+ "slug": "savepassword"
30
+ }
31
+ ],
32
+ "properties": []
33
+ },
34
+ "interfaces": [
35
+ {
36
+ "name": "SavePasswordOptions",
37
+ "slug": "savepasswordoptions",
38
+ "docs": "",
39
+ "tags": [
40
+ {
41
+ "text": "0.1.0",
42
+ "name": "since"
43
+ }
44
+ ],
45
+ "methods": [],
46
+ "properties": [
47
+ {
48
+ "name": "domain",
49
+ "tags": [
50
+ {
51
+ "text": "'example.com'",
52
+ "name": "example"
53
+ },
54
+ {
55
+ "text": "0.1.0",
56
+ "name": "since"
57
+ }
58
+ ],
59
+ "docs": "The domain to associate the credential with.\n\nThis must match one of the domains in your app's Associated Domains\nentitlement (without the `webcredentials:` prefix).\n\nOnly available on iOS (required).",
60
+ "complexTypes": [],
61
+ "type": "string | undefined"
62
+ },
63
+ {
64
+ "name": "password",
65
+ "tags": [
66
+ {
67
+ "text": "0.1.0",
68
+ "name": "since"
69
+ }
70
+ ],
71
+ "docs": "The password to save.",
72
+ "complexTypes": [],
73
+ "type": "string"
74
+ },
75
+ {
76
+ "name": "username",
77
+ "tags": [
78
+ {
79
+ "text": "'jane.doe@example.com'",
80
+ "name": "example"
81
+ },
82
+ {
83
+ "text": "0.1.0",
84
+ "name": "since"
85
+ }
86
+ ],
87
+ "docs": "The username to save.",
88
+ "complexTypes": [],
89
+ "type": "string"
90
+ }
91
+ ]
92
+ }
93
+ ],
94
+ "enums": [],
95
+ "typeAliases": [],
96
+ "pluginConfigs": []
97
+ }
@@ -0,0 +1,66 @@
1
+ export interface PasswordAutofillPlugin {
2
+ /**
3
+ * Save a username and password to the platform credential store.
4
+ *
5
+ * On iOS, the credential is saved to the iCloud Keychain via the
6
+ * Shared Web Credentials API. This requires the Associated Domains
7
+ * entitlement with a `webcredentials:` entry and a matching
8
+ * `apple-app-site-association` file hosted on your domain.
9
+ *
10
+ * On Android, the credential is saved to the Google Password Manager
11
+ * (or another provider) via the Credential Manager API. This presents
12
+ * the system "Save password?" prompt to the user.
13
+ *
14
+ * Only available on Android and iOS.
15
+ *
16
+ * @since 0.1.0
17
+ */
18
+ savePassword(options: SavePasswordOptions): Promise<void>;
19
+ }
20
+ /**
21
+ * @since 0.1.0
22
+ */
23
+ export interface SavePasswordOptions {
24
+ /**
25
+ * The domain to associate the credential with.
26
+ *
27
+ * This must match one of the domains in your app's Associated Domains
28
+ * entitlement (without the `webcredentials:` prefix).
29
+ *
30
+ * Only available on iOS (required).
31
+ *
32
+ * @example 'example.com'
33
+ * @since 0.1.0
34
+ */
35
+ domain?: string;
36
+ /**
37
+ * The password to save.
38
+ *
39
+ * @since 0.1.0
40
+ */
41
+ password: string;
42
+ /**
43
+ * The username to save.
44
+ *
45
+ * @example 'jane.doe@example.com'
46
+ * @since 0.1.0
47
+ */
48
+ username: string;
49
+ }
50
+ /**
51
+ * @since 0.1.0
52
+ */
53
+ export declare enum ErrorCode {
54
+ /**
55
+ * The user canceled the save operation.
56
+ *
57
+ * @since 0.1.0
58
+ */
59
+ Canceled = "CANCELED",
60
+ /**
61
+ * The credential could not be saved.
62
+ *
63
+ * @since 0.1.0
64
+ */
65
+ SaveFailed = "SAVE_FAILED"
66
+ }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * @since 0.1.0
3
+ */
4
+ export var ErrorCode;
5
+ (function (ErrorCode) {
6
+ /**
7
+ * The user canceled the save operation.
8
+ *
9
+ * @since 0.1.0
10
+ */
11
+ ErrorCode["Canceled"] = "CANCELED";
12
+ /**
13
+ * The credential could not be saved.
14
+ *
15
+ * @since 0.1.0
16
+ */
17
+ ErrorCode["SaveFailed"] = "SAVE_FAILED";
18
+ })(ErrorCode || (ErrorCode = {}));
19
+ //# sourceMappingURL=definitions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"AAmDA;;GAEG;AACH,MAAM,CAAN,IAAY,SAaX;AAbD,WAAY,SAAS;IACnB;;;;OAIG;IACH,kCAAqB,CAAA;IACrB;;;;OAIG;IACH,uCAA0B,CAAA;AAC5B,CAAC,EAbW,SAAS,KAAT,SAAS,QAapB","sourcesContent":["export interface PasswordAutofillPlugin {\n /**\n * Save a username and password to the platform credential store.\n *\n * On iOS, the credential is saved to the iCloud Keychain via the\n * Shared Web Credentials API. This requires the Associated Domains\n * entitlement with a `webcredentials:` entry and a matching\n * `apple-app-site-association` file hosted on your domain.\n *\n * On Android, the credential is saved to the Google Password Manager\n * (or another provider) via the Credential Manager API. This presents\n * the system \"Save password?\" prompt to the user.\n *\n * Only available on Android and iOS.\n *\n * @since 0.1.0\n */\n savePassword(options: SavePasswordOptions): Promise<void>;\n}\n\n/**\n * @since 0.1.0\n */\nexport interface SavePasswordOptions {\n /**\n * The domain to associate the credential with.\n *\n * This must match one of the domains in your app's Associated Domains\n * entitlement (without the `webcredentials:` prefix).\n *\n * Only available on iOS (required).\n *\n * @example 'example.com'\n * @since 0.1.0\n */\n domain?: string;\n /**\n * The password to save.\n *\n * @since 0.1.0\n */\n password: string;\n /**\n * The username to save.\n *\n * @example 'jane.doe@example.com'\n * @since 0.1.0\n */\n username: string;\n}\n\n/**\n * @since 0.1.0\n */\nexport enum ErrorCode {\n /**\n * The user canceled the save operation.\n *\n * @since 0.1.0\n */\n Canceled = 'CANCELED',\n /**\n * The credential could not be saved.\n *\n * @since 0.1.0\n */\n SaveFailed = 'SAVE_FAILED',\n}\n"]}
@@ -0,0 +1,4 @@
1
+ import type { PasswordAutofillPlugin } from './definitions';
2
+ declare const PasswordAutofill: PasswordAutofillPlugin;
3
+ export * from './definitions';
4
+ export { PasswordAutofill };
@@ -0,0 +1,7 @@
1
+ import { registerPlugin } from '@capacitor/core';
2
+ const PasswordAutofill = registerPlugin('PasswordAutofill', {
3
+ web: () => import('./web').then(m => new m.PasswordAutofillWeb()),
4
+ });
5
+ export * from './definitions';
6
+ export { PasswordAutofill };
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAIjD,MAAM,gBAAgB,GAAG,cAAc,CACrC,kBAAkB,EAClB;IACE,GAAG,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,mBAAmB,EAAE,CAAC;CAClE,CACF,CAAC;AAEF,cAAc,eAAe,CAAC;AAC9B,OAAO,EAAE,gBAAgB,EAAE,CAAC","sourcesContent":["import { registerPlugin } from '@capacitor/core';\n\nimport type { PasswordAutofillPlugin } from './definitions';\n\nconst PasswordAutofill = registerPlugin<PasswordAutofillPlugin>(\n 'PasswordAutofill',\n {\n web: () => import('./web').then(m => new m.PasswordAutofillWeb()),\n },\n);\n\nexport * from './definitions';\nexport { PasswordAutofill };\n"]}
@@ -0,0 +1,5 @@
1
+ import { WebPlugin } from '@capacitor/core';
2
+ import type { PasswordAutofillPlugin, SavePasswordOptions } from './definitions';
3
+ export declare class PasswordAutofillWeb extends WebPlugin implements PasswordAutofillPlugin {
4
+ savePassword(_options: SavePasswordOptions): Promise<void>;
5
+ }
@@ -0,0 +1,7 @@
1
+ import { WebPlugin } from '@capacitor/core';
2
+ export class PasswordAutofillWeb extends WebPlugin {
3
+ async savePassword(_options) {
4
+ throw this.unimplemented('Not implemented on web.');
5
+ }
6
+ }
7
+ //# sourceMappingURL=web.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web.js","sourceRoot":"","sources":["../../src/web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAO5C,MAAM,OAAO,mBACX,SAAQ,SAAS;IAGjB,KAAK,CAAC,YAAY,CAAC,QAA6B;QAC9C,MAAM,IAAI,CAAC,aAAa,CAAC,yBAAyB,CAAC,CAAC;IACtD,CAAC;CACF","sourcesContent":["import { WebPlugin } from '@capacitor/core';\n\nimport type {\n PasswordAutofillPlugin,\n SavePasswordOptions,\n} from './definitions';\n\nexport class PasswordAutofillWeb\n extends WebPlugin\n implements PasswordAutofillPlugin\n{\n async savePassword(_options: SavePasswordOptions): Promise<void> {\n throw this.unimplemented('Not implemented on web.');\n }\n}\n"]}
@@ -0,0 +1,40 @@
1
+ 'use strict';
2
+
3
+ var core = require('@capacitor/core');
4
+
5
+ /**
6
+ * @since 0.1.0
7
+ */
8
+ exports.ErrorCode = void 0;
9
+ (function (ErrorCode) {
10
+ /**
11
+ * The user canceled the save operation.
12
+ *
13
+ * @since 0.1.0
14
+ */
15
+ ErrorCode["Canceled"] = "CANCELED";
16
+ /**
17
+ * The credential could not be saved.
18
+ *
19
+ * @since 0.1.0
20
+ */
21
+ ErrorCode["SaveFailed"] = "SAVE_FAILED";
22
+ })(exports.ErrorCode || (exports.ErrorCode = {}));
23
+
24
+ const PasswordAutofill = core.registerPlugin('PasswordAutofill', {
25
+ web: () => Promise.resolve().then(function () { return web; }).then(m => new m.PasswordAutofillWeb()),
26
+ });
27
+
28
+ class PasswordAutofillWeb extends core.WebPlugin {
29
+ async savePassword(_options) {
30
+ throw this.unimplemented('Not implemented on web.');
31
+ }
32
+ }
33
+
34
+ var web = /*#__PURE__*/Object.freeze({
35
+ __proto__: null,
36
+ PasswordAutofillWeb: PasswordAutofillWeb
37
+ });
38
+
39
+ exports.PasswordAutofill = PasswordAutofill;
40
+ //# sourceMappingURL=plugin.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.cjs.js","sources":["esm/definitions.js","esm/index.js","esm/web.js"],"sourcesContent":["/**\n * @since 0.1.0\n */\nexport var ErrorCode;\n(function (ErrorCode) {\n /**\n * The user canceled the save operation.\n *\n * @since 0.1.0\n */\n ErrorCode[\"Canceled\"] = \"CANCELED\";\n /**\n * The credential could not be saved.\n *\n * @since 0.1.0\n */\n ErrorCode[\"SaveFailed\"] = \"SAVE_FAILED\";\n})(ErrorCode || (ErrorCode = {}));\n//# sourceMappingURL=definitions.js.map","import { registerPlugin } from '@capacitor/core';\nconst PasswordAutofill = registerPlugin('PasswordAutofill', {\n web: () => import('./web').then(m => new m.PasswordAutofillWeb()),\n});\nexport * from './definitions';\nexport { PasswordAutofill };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from '@capacitor/core';\nexport class PasswordAutofillWeb extends WebPlugin {\n async savePassword(_options) {\n throw this.unimplemented('Not implemented on web.');\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["ErrorCode","registerPlugin","WebPlugin"],"mappings":";;;;AAAA;AACA;AACA;AACWA;AACX,CAAC,UAAU,SAAS,EAAE;AACtB;AACA;AACA;AACA;AACA;AACA,IAAI,SAAS,CAAC,UAAU,CAAC,GAAG,UAAU;AACtC;AACA;AACA;AACA;AACA;AACA,IAAI,SAAS,CAAC,YAAY,CAAC,GAAG,aAAa;AAC3C,CAAC,EAAEA,iBAAS,KAAKA,iBAAS,GAAG,EAAE,CAAC,CAAC;;AChB5B,MAAC,gBAAgB,GAAGC,mBAAc,CAAC,kBAAkB,EAAE;AAC5D,IAAI,GAAG,EAAE,MAAM,mDAAe,CAAC,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,mBAAmB,EAAE,CAAC;AACrE,CAAC;;ACFM,MAAM,mBAAmB,SAASC,cAAS,CAAC;AACnD,IAAI,MAAM,YAAY,CAAC,QAAQ,EAAE;AACjC,QAAQ,MAAM,IAAI,CAAC,aAAa,CAAC,yBAAyB,CAAC;AAC3D,IAAI;AACJ;;;;;;;;;"}
package/dist/plugin.js ADDED
@@ -0,0 +1,43 @@
1
+ var capacitorPasswordAutofill = (function (exports, core) {
2
+ 'use strict';
3
+
4
+ /**
5
+ * @since 0.1.0
6
+ */
7
+ exports.ErrorCode = void 0;
8
+ (function (ErrorCode) {
9
+ /**
10
+ * The user canceled the save operation.
11
+ *
12
+ * @since 0.1.0
13
+ */
14
+ ErrorCode["Canceled"] = "CANCELED";
15
+ /**
16
+ * The credential could not be saved.
17
+ *
18
+ * @since 0.1.0
19
+ */
20
+ ErrorCode["SaveFailed"] = "SAVE_FAILED";
21
+ })(exports.ErrorCode || (exports.ErrorCode = {}));
22
+
23
+ const PasswordAutofill = core.registerPlugin('PasswordAutofill', {
24
+ web: () => Promise.resolve().then(function () { return web; }).then(m => new m.PasswordAutofillWeb()),
25
+ });
26
+
27
+ class PasswordAutofillWeb extends core.WebPlugin {
28
+ async savePassword(_options) {
29
+ throw this.unimplemented('Not implemented on web.');
30
+ }
31
+ }
32
+
33
+ var web = /*#__PURE__*/Object.freeze({
34
+ __proto__: null,
35
+ PasswordAutofillWeb: PasswordAutofillWeb
36
+ });
37
+
38
+ exports.PasswordAutofill = PasswordAutofill;
39
+
40
+ return exports;
41
+
42
+ })({}, capacitorExports);
43
+ //# sourceMappingURL=plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.js","sources":["esm/definitions.js","esm/index.js","esm/web.js"],"sourcesContent":["/**\n * @since 0.1.0\n */\nexport var ErrorCode;\n(function (ErrorCode) {\n /**\n * The user canceled the save operation.\n *\n * @since 0.1.0\n */\n ErrorCode[\"Canceled\"] = \"CANCELED\";\n /**\n * The credential could not be saved.\n *\n * @since 0.1.0\n */\n ErrorCode[\"SaveFailed\"] = \"SAVE_FAILED\";\n})(ErrorCode || (ErrorCode = {}));\n//# sourceMappingURL=definitions.js.map","import { registerPlugin } from '@capacitor/core';\nconst PasswordAutofill = registerPlugin('PasswordAutofill', {\n web: () => import('./web').then(m => new m.PasswordAutofillWeb()),\n});\nexport * from './definitions';\nexport { PasswordAutofill };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from '@capacitor/core';\nexport class PasswordAutofillWeb extends WebPlugin {\n async savePassword(_options) {\n throw this.unimplemented('Not implemented on web.');\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["ErrorCode","registerPlugin","WebPlugin"],"mappings":";;;IAAA;IACA;IACA;AACWA;IACX,CAAC,UAAU,SAAS,EAAE;IACtB;IACA;IACA;IACA;IACA;IACA,IAAI,SAAS,CAAC,UAAU,CAAC,GAAG,UAAU;IACtC;IACA;IACA;IACA;IACA;IACA,IAAI,SAAS,CAAC,YAAY,CAAC,GAAG,aAAa;IAC3C,CAAC,EAAEA,iBAAS,KAAKA,iBAAS,GAAG,EAAE,CAAC,CAAC;;AChB5B,UAAC,gBAAgB,GAAGC,mBAAc,CAAC,kBAAkB,EAAE;IAC5D,IAAI,GAAG,EAAE,MAAM,mDAAe,CAAC,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,mBAAmB,EAAE,CAAC;IACrE,CAAC;;ICFM,MAAM,mBAAmB,SAASC,cAAS,CAAC;IACnD,IAAI,MAAM,YAAY,CAAC,QAAQ,EAAE;IACjC,QAAQ,MAAM,IAAI,CAAC,aAAa,CAAC,yBAAyB,CAAC;IAC3D,IAAI;IACJ;;;;;;;;;;;;;;;"}
@@ -0,0 +1,35 @@
1
+ import Foundation
2
+ import Capacitor
3
+
4
+ @objc public class SavePasswordOptions: NSObject {
5
+ let domain: String
6
+ let password: String
7
+ let username: String
8
+
9
+ init(_ call: CAPPluginCall) throws {
10
+ self.domain = try SavePasswordOptions.getDomainFromCall(call)
11
+ self.password = try SavePasswordOptions.getPasswordFromCall(call)
12
+ self.username = try SavePasswordOptions.getUsernameFromCall(call)
13
+ }
14
+
15
+ private static func getDomainFromCall(_ call: CAPPluginCall) throws -> String {
16
+ guard let domain = call.getString("domain") else {
17
+ throw CustomError.domainMissing
18
+ }
19
+ return domain
20
+ }
21
+
22
+ private static func getPasswordFromCall(_ call: CAPPluginCall) throws -> String {
23
+ guard let password = call.getString("password") else {
24
+ throw CustomError.passwordMissing
25
+ }
26
+ return password
27
+ }
28
+
29
+ private static func getUsernameFromCall(_ call: CAPPluginCall) throws -> String {
30
+ guard let username = call.getString("username") else {
31
+ throw CustomError.usernameMissing
32
+ }
33
+ return username
34
+ }
35
+ }
@@ -0,0 +1,32 @@
1
+ import Foundation
2
+
3
+ public enum CustomError: Error {
4
+ case domainMissing
5
+ case passwordMissing
6
+ case saveFailed(message: String)
7
+ case usernameMissing
8
+
9
+ public var code: String? {
10
+ switch self {
11
+ case .saveFailed:
12
+ return "SAVE_FAILED"
13
+ default:
14
+ return nil
15
+ }
16
+ }
17
+ }
18
+
19
+ extension CustomError: LocalizedError {
20
+ public var errorDescription: String? {
21
+ switch self {
22
+ case .domainMissing:
23
+ return NSLocalizedString("domain must be provided.", comment: "domainMissing")
24
+ case .passwordMissing:
25
+ return NSLocalizedString("password must be provided.", comment: "passwordMissing")
26
+ case .saveFailed(let message):
27
+ return NSLocalizedString(message, comment: "saveFailed")
28
+ case .usernameMissing:
29
+ return NSLocalizedString("username must be provided.", comment: "usernameMissing")
30
+ }
31
+ }
32
+ }
@@ -0,0 +1,24 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>CFBundleDevelopmentRegion</key>
6
+ <string>$(DEVELOPMENT_LANGUAGE)</string>
7
+ <key>CFBundleExecutable</key>
8
+ <string>$(EXECUTABLE_NAME)</string>
9
+ <key>CFBundleIdentifier</key>
10
+ <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
11
+ <key>CFBundleInfoDictionaryVersion</key>
12
+ <string>6.0</string>
13
+ <key>CFBundleName</key>
14
+ <string>$(PRODUCT_NAME)</string>
15
+ <key>CFBundlePackageType</key>
16
+ <string>FMWK</string>
17
+ <key>CFBundleShortVersionString</key>
18
+ <string>1.0</string>
19
+ <key>CFBundleVersion</key>
20
+ <string>$(CURRENT_PROJECT_VERSION)</string>
21
+ <key>NSPrincipalClass</key>
22
+ <string></string>
23
+ </dict>
24
+ </plist>
@@ -0,0 +1,23 @@
1
+ import Foundation
2
+ import Security
3
+
4
+ @objc public class PasswordAutofill: NSObject {
5
+ private let plugin: PasswordAutofillPlugin
6
+
7
+ init(plugin: PasswordAutofillPlugin) {
8
+ self.plugin = plugin
9
+ }
10
+
11
+ @objc public func savePassword(_ options: SavePasswordOptions, completion: @escaping (_ error: Error?) -> Void) {
12
+ let domain = options.domain
13
+ let username = options.username
14
+ let password = options.password
15
+ SecAddSharedWebCredential(domain as CFString, username as CFString, password as CFString) { error in
16
+ if let error = error {
17
+ completion(CustomError.saveFailed(message: (error as Error).localizedDescription))
18
+ return
19
+ }
20
+ completion(nil)
21
+ }
22
+ }
23
+ }
@@ -0,0 +1,44 @@
1
+ import Foundation
2
+ import Capacitor
3
+
4
+ @objc(PasswordAutofillPlugin)
5
+ public class PasswordAutofillPlugin: CAPPlugin, CAPBridgedPlugin {
6
+ public let identifier = "PasswordAutofillPlugin"
7
+ public let jsName = "PasswordAutofill"
8
+ public let pluginMethods: [CAPPluginMethod] = [
9
+ CAPPluginMethod(name: "savePassword", returnType: CAPPluginReturnPromise)
10
+ ]
11
+
12
+ public static let tag = "PasswordAutofillPlugin"
13
+
14
+ private var implementation: PasswordAutofill?
15
+
16
+ override public func load() {
17
+ self.implementation = PasswordAutofill(plugin: self)
18
+ }
19
+
20
+ @objc func savePassword(_ call: CAPPluginCall) {
21
+ do {
22
+ let options = try SavePasswordOptions(call)
23
+ implementation?.savePassword(options) { error in
24
+ if let error = error {
25
+ self.rejectCall(call, error)
26
+ return
27
+ }
28
+ self.resolveCall(call)
29
+ }
30
+ } catch {
31
+ self.rejectCall(call, error)
32
+ }
33
+ }
34
+
35
+ private func rejectCall(_ call: CAPPluginCall, _ error: Error) {
36
+ CAPLog.print("[", PasswordAutofillPlugin.tag, "] ", error)
37
+ let code = (error as? CustomError)?.code
38
+ call.reject(error.localizedDescription, code)
39
+ }
40
+
41
+ private func resolveCall(_ call: CAPPluginCall) {
42
+ call.resolve()
43
+ }
44
+ }
@@ -0,0 +1,5 @@
1
+ import Capacitor
2
+
3
+ @objc public protocol Result {
4
+ @objc func toJSObject() -> AnyObject
5
+ }
package/package.json ADDED
@@ -0,0 +1,91 @@
1
+ {
2
+ "name": "@capawesome/capacitor-password-autofill",
3
+ "version": "0.0.1",
4
+ "description": "Capacitor plugin for saving passwords to the platform credential store.",
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
+ "CapawesomeCapacitorPasswordAutofill.podspec",
15
+ "Package.swift"
16
+ ],
17
+ "author": "Robin Genz <mail@robingenz.dev>",
18
+ "license": "MIT",
19
+ "repository": {
20
+ "type": "git",
21
+ "url": "git+https://github.com/capawesome-team/capacitor-plugins.git"
22
+ },
23
+ "bugs": {
24
+ "url": "https://github.com/capawesome-team/capacitor-plugins/issues"
25
+ },
26
+ "funding": [
27
+ {
28
+ "type": "github",
29
+ "url": "https://github.com/sponsors/capawesome-team/"
30
+ },
31
+ {
32
+ "type": "opencollective",
33
+ "url": "https://opencollective.com/capawesome"
34
+ }
35
+ ],
36
+ "homepage": "https://capawesome.io/docs/plugins/password-autofill/",
37
+ "keywords": [
38
+ "capacitor",
39
+ "plugin",
40
+ "native"
41
+ ],
42
+ "scripts": {
43
+ "verify": "npm run verify:ios && npm run verify:android && npm run verify:web",
44
+ "verify:ios": "cd ios && pod install && xcodebuild -workspace Plugin.xcworkspace -scheme Plugin -destination generic/platform=iOS && cd ..",
45
+ "verify:android": "cd android && ./gradlew clean build test && cd ..",
46
+ "verify:web": "npm run build",
47
+ "lint": "npm run eslint && npm run prettier -- --check && npm run swiftlint -- lint",
48
+ "fmt": "npm run eslint -- --fix && npm run prettier -- --write && npm run swiftlint -- --fix --format",
49
+ "eslint": "eslint . --ext ts",
50
+ "prettier": "prettier \"**/*.{css,html,ts,js,java}\"",
51
+ "swiftlint": "node-swiftlint",
52
+ "docgen": "docgen --api PasswordAutofillPlugin --output-readme README.md --output-json dist/docs.json",
53
+ "build": "npm run clean && npm run docgen && tsc && rollup -c rollup.config.mjs",
54
+ "clean": "rimraf ./dist",
55
+ "watch": "tsc --watch",
56
+ "ios:pod:install": "cd ios && pod install --repo-update && cd ..",
57
+ "ios:spm:install": "cd ios && swift package resolve && cd ..",
58
+ "prepublishOnly": "npm run build"
59
+ },
60
+ "devDependencies": {
61
+ "@capacitor/android": "8.0.0",
62
+ "@capacitor/cli": "8.0.0",
63
+ "@capacitor/core": "8.0.0",
64
+ "@capacitor/docgen": "0.3.1",
65
+ "@capacitor/ios": "8.0.0",
66
+ "@ionic/eslint-config": "0.4.0",
67
+ "eslint": "8.57.0",
68
+ "prettier-plugin-java": "2.6.7",
69
+ "rimraf": "6.1.2",
70
+ "rollup": "4.53.3",
71
+ "swiftlint": "2.0.0",
72
+ "typescript": "5.9.3"
73
+ },
74
+ "peerDependencies": {
75
+ "@capacitor/core": ">=8.0.0"
76
+ },
77
+ "eslintConfig": {
78
+ "extends": "@ionic/eslint-config/recommended"
79
+ },
80
+ "capacitor": {
81
+ "ios": {
82
+ "src": "ios"
83
+ },
84
+ "android": {
85
+ "src": "android"
86
+ }
87
+ },
88
+ "publishConfig": {
89
+ "access": "public"
90
+ }
91
+ }