# Table of Contents - [Ionic Docs - Ionic Documentation](#ionic-docs-ionic-documentation) - [Couchbase Lite Overview - Couchbase Lite](#couchbase-lite-overview-couchbase-lite) - [Intune Changelog - Couchbase Lite](#intune-changelog-couchbase-lite) - [Installation - Couchbase Lite](#installation-couchbase-lite) - [Hotel Search Tutorial - Couchbase Lite](#hotel-search-tutorial-couchbase-lite) - [Windows Installation - Couchbase Lite](#windows-installation-couchbase-lite) - [Changelog - Secure Storage](#changelog-secure-storage) - [Secure Storage API - Secure Storage](#secure-storage-api-secure-storage) - [Usage - Couchbase Lite](#usage-couchbase-lite) - [Secure Storage - Key Value API - Secure Storage](#secure-storage-key-value-api-secure-storage) - [Create a Tab-based App | Ionic Secure Solutions Starter](#create-a-tab-based-app-ionic-secure-solutions-starter) - [Register Enterprise Key | Ionic Secure Solutions Starter](#register-enterprise-key-ionic-secure-solutions-starter) - [Authentication Service Updates | Ionic Secure Solutions Starter](#authentication-service-updates-ionic-secure-solutions-starter) - [Building Your First Ionic Enterprise Application | Ionic Secure Solutions Starter](#building-your-first-ionic-enterprise-application-ionic-secure-solutions-starter) - [AWS Amplify - Supported Plugins](#aws-amplify-supported-plugins) - [Secure Storage - Encryption Key Management with Identity Vault - Secure Storage](#secure-storage-encryption-key-management-with-identity-vault-secure-storage) - [Gating the App | Ionic Secure Solutions Starter](#gating-the-app-ionic-secure-solutions-starter) - [Installation - Secure Storage](#installation-secure-storage) - [Reference Apps - Secure Storage](#reference-apps-secure-storage) - [Capacitor Supported Plugins - Supported Plugins](#capacitor-supported-plugins-supported-plugins) - [Secure Storage - Troubleshooting - Secure Storage](#secure-storage-troubleshooting-secure-storage) - [Securing Your App's Data | Ionic Secure Solutions Starter](#securing-your-app-s-data-ionic-secure-solutions-starter) - [Single sign-on with Auth Connect | Ionic Secure Solutions Starter](#single-sign-on-with-auth-connect-ionic-secure-solutions-starter) - [Add a Login Page | Ionic Secure Solutions Starter](#add-a-login-page-ionic-secure-solutions-starter) - [Secure Storage - Web Support - Secure Storage](#secure-storage-web-support-secure-storage) - [Creating the Session Vault | Ionic Secure Solutions Starter](#creating-the-session-vault-ionic-secure-solutions-starter) - [Secure Storage Support Policy - Secure Storage](#secure-storage-support-policy-secure-storage) - [Demo App - Intune](#demo-app-intune) - [Azure Configuration - Intune](#azure-configuration-intune) - [Checkbox - Accessibility Guide](#checkbox-accessibility-guide) - [Installation - Intune](#installation-intune) - [SDK Versions - Intune](#sdk-versions-intune) - [Brokered Auth - Intune](#brokered-auth-intune) - [Secure Storage - Secure Storage](#secure-storage-secure-storage) - [Encrypting Your App's Data | Ionic Secure Solutions Starter](#encrypting-your-app-s-data-ionic-secure-solutions-starter) - [Cordova Installation - Intune](#cordova-installation-intune) - [Intune - Intune](#intune-intune) - [Setup App Tabs | Ionic Secure Solutions Starter](#setup-app-tabs-ionic-secure-solutions-starter) - [Apple Payment Pass - Supported Plugins](#apple-payment-pass-supported-plugins) - [Apple Payment Pass - Supported Plugins](#apple-payment-pass-supported-plugins) - [Intune Changelog - Intune](#intune-changelog-intune) - [Deploying Your App with Appflow | Ionic Secure Solutions Starter](#deploying-your-app-with-appflow-ionic-secure-solutions-starter) - [Intune Support Policy - Intune](#intune-support-policy-intune) - [Troubleshooting - Intune](#troubleshooting-intune) - [Installation - iOS - Intune](#installation-ios-intune) - [Installation - Android - Intune](#installation-android-intune) - [Filesystem - Supported Plugins](#filesystem-supported-plugins) - [Contacts - Supported Plugins](#contacts-supported-plugins) - [Usage - Intune](#usage-intune) - [Capacitor and Cordova Android Permissions Plugin | Ionic](#capacitor-and-cordova-android-permissions-plugin-ionic) - [App Version - Supported Plugins](#app-version-supported-plugins) - [Badge - Supported Plugins](#badge-supported-plugins) - [Supported Plugins - Supported Plugins](#supported-plugins-supported-plugins) - [Clipboard - Supported Plugins](#clipboard-supported-plugins) - [Device - Supported Plugins](#device-supported-plugins) - [Dialogs - Supported Plugins](#dialogs-supported-plugins) - [Cordova and Capacitor Calendar Plugin | Ionic](#cordova-and-capacitor-calendar-plugin-ionic) - [Deep Links - Supported Plugins](#deep-links-supported-plugins) - [App Rate - Supported Plugins](#app-rate-supported-plugins) - [Concurrency limits - Appflow](#concurrency-limits-appflow) - [Allow Zooming - Accessibility Guide](#allow-zooming-accessibility-guide) - [Aria Label - Accessibility Guide](#aria-label-accessibility-guide) - [Alternative Text - Accessibility Guide](#alternative-text-accessibility-guide) - [Email Composer - Capacitor/Cordova In-App Email Plugin | Ionic](#email-composer-capacitor-cordova-in-app-email-plugin-ionic) - [Contact Us - Appflow](#contact-us-appflow) - [ARIA - Accessibility Guide](#aria-accessibility-guide) - [Axe Tools - Accessibility Guide](#axe-tools-accessibility-guide) - [Aria Hidden - Accessibility Guide](#aria-hidden-accessibility-guide) - [Contrast - Accessibility Guide](#contrast-accessibility-guide) - [Aria Live Regions - Accessibility Guide](#aria-live-regions-accessibility-guide) - [Icon - Accessibility Guide](#icon-accessibility-guide) - [Custom Components - Accessibility Guide](#custom-components-accessibility-guide) - [Lighthouse - Accessibility Guide](#lighthouse-accessibility-guide) - [Overview - Accessibility Guide](#overview-accessibility-guide) - [Item - Accessibility Guide](#item-accessibility-guide) - [Build Stacks - Appflow](#build-stacks-appflow) - [Introduction - Accessibility Guide](#introduction-accessibility-guide) - [Modals - Accessibility Guide](#modals-accessibility-guide) - [Role - Accessibility Guide](#role-accessibility-guide) - [Radio Groups - Accessibility Guide](#radio-groups-accessibility-guide) - [Contacts - Supported Plugins](#contacts-supported-plugins) - [Using Automations - Appflow](#using-automations-appflow) - [Tabs - Accessibility Guide](#tabs-accessibility-guide) - [Semantic Elements - Accessibility Guide](#semantic-elements-accessibility-guide) - [Skip Links - Accessibility Guide](#skip-links-accessibility-guide) - [Switch / Toggle - Accessibility Guide](#switch-toggle-accessibility-guide) - [Automations - Appflow](#automations-appflow) - [Using Appflow in Jenkins, GitLab CI, & GitHub Actions - Appflow](#using-appflow-in-jenkins-gitlab-ci-github-actions-appflow) - [Error Monitoring - Appflow](#error-monitoring-appflow) - [Filesystem API Plugin for Capacitor and Cordova | Ionic](#filesystem-api-plugin-for-capacitor-and-cordova-ionic) - [Overview - Accessibility Guide](#overview-accessibility-guide) - [Motion - Accessibility Guide](#motion-accessibility-guide) - [TalkBack for Android - Accessibility Guide](#talkback-for-android-accessibility-guide) - [Couchbase Lite - Supported Plugins](#couchbase-lite-supported-plugins) - [Visibility - Accessibility Guide](#visibility-accessibility-guide) - [Deploy to App Stores - Appflow](#deploy-to-app-stores-appflow) - [WCAG - Accessibility Guide](#wcag-accessibility-guide) - [VoiceOver for iOS - Accessibility Guide](#voiceover-for-ios-accessibility-guide) - [Keyboard - Accessibility Guide](#keyboard-accessibility-guide) - [Use Version 7 - Accessibility Guide](#use-version-7-accessibility-guide) - [Ionic DevApp - Appflow](#ionic-devapp-appflow) - [Screen Readers for Web - Accessibility Guide](#screen-readers-for-web-accessibility-guide) - [Workarounds - Accessibility Guide](#workarounds-accessibility-guide) - [Install Errors - Appflow](#install-errors-appflow) - [CLI Errors - Appflow](#cli-errors-appflow) - [API Errors - Appflow](#api-errors-appflow) - [Appflow CLI Changelog - Appflow](#appflow-cli-changelog-appflow) - [Camera API Plugin: Capacitor and Cordova for Ionic Apps](#camera-api-plugin-capacitor-and-cordova-for-ionic-apps) - [Migrate from Ionic CLI - Appflow](#migrate-from-ionic-cli-appflow) - [Appflow CLI - Appflow](#appflow-cli-appflow) - [0.x to 1.x Migration Guide - Appflow](#0-x-to-1-x-migration-guide-appflow) - [Parsing --json Output from Appflow CLI - Appflow](#parsing-json-output-from-appflow-cli-appflow) - [Native Builds - Appflow](#native-builds-appflow) - [Using Appflow CLI with GitHub actions - Appflow](#using-appflow-cli-with-github-actions-appflow) - [Deploy a Live Update on Appflow using the Appflow CLI - Appflow](#deploy-a-live-update-on-appflow-using-the-appflow-cli-appflow) - [Using Appflow CLI with Jenkins - Appflow](#using-appflow-cli-with-jenkins-appflow) - [Using Appflow CLI with Bitbucket Pipelines - Appflow](#using-appflow-cli-with-bitbucket-pipelines-appflow) - [Self-hosted Live Updates with Github Actions and S3 - Appflow](#self-hosted-live-updates-with-github-actions-and-s3-appflow) - [Using Appflow CLI with Azure DevOps - Appflow](#using-appflow-cli-with-azure-devops-appflow) - [Using Appflow CLI with GitLab CI/CD Pipelines - Appflow](#using-appflow-cli-with-gitlab-ci-cd-pipelines-appflow) - [Self-hosted Live Updates with Azure DevOps - Appflow](#self-hosted-live-updates-with-azure-devops-appflow) - [Personal Access Tokens - Appflow](#personal-access-tokens-appflow) - [Manual Deploy - Appflow](#manual-deploy-appflow) - [App Previews - Appflow](#app-previews-appflow) - [Builds/Automations - Appflow](#builds-automations-appflow) - [Deploy To App Stores - Appflow](#deploy-to-app-stores-appflow) - [Exploring Appflow Tutorial - Appflow](#exploring-appflow-tutorial-appflow) - [Native Previews - Appflow](#native-previews-appflow) - [Web Previews - Appflow](#web-previews-appflow) - [Alternate Appflow Build Command - Appflow](#alternate-appflow-build-command-appflow) - [Live Update Builds - Appflow](#live-update-builds-appflow) - [Destinations - Appflow](#destinations-appflow) - [Apple App Store - Appflow](#apple-app-store-appflow) - [Run Scripts During The Build - Appflow](#run-scripts-during-the-build-appflow) - [Cookbook - Appflow](#cookbook-appflow) - [Instantly Update App UI & Fix Bugs | Appflow Live Updates](#instantly-update-app-ui-fix-bugs-appflow-live-updates) - [Channels - Appflow](#channels-appflow) - [Google Play Store - Appflow](#google-play-store-appflow) - [FAQ - Appflow](#faq-appflow) - [Auto-incrementing Build Numbers in Capacitor - Appflow](#auto-incrementing-build-numbers-in-capacitor-appflow) - [Override Java version on Android builds - Appflow](#override-java-version-on-android-builds-appflow) - [Using private Git repositories - Appflow](#using-private-git-repositories-appflow) - [Adding Certificates - Appflow](#adding-certificates-appflow) - [Making Live Updates Faster - Appflow](#making-live-updates-faster-appflow) - [Automations - Appflow](#automations-appflow) - [Native Builds - Appflow](#native-builds-appflow) - [Capacitor SDK Reference - Appflow](#capacitor-sdk-reference-appflow) - [Using private NPM modules - Appflow](#using-private-npm-modules-appflow) - [Using Local NPM modules - Appflow](#using-local-npm-modules-appflow) - [Override Node Version - Appflow](#override-node-version-appflow) - [Native Build Types - Appflow](#native-build-types-appflow) - [Native Configurations - Appflow](#native-configurations-appflow) - [Quickstart - Appflow](#quickstart-appflow) - [Deploying Live Updates - Appflow](#deploying-live-updates-appflow) - [Using Private Git Submodules in Appflow - Appflow](#using-private-git-submodules-in-appflow-appflow) - [Cordova SDK Setup - Appflow](#cordova-sdk-setup-appflow) - [Migrating from Cordova to Capacitor-based SDK - Appflow](#migrating-from-cordova-to-capacitor-based-sdk-appflow) - [Get your UDID - Appflow](#get-your-udid-appflow) - [Wrapping Up - Appflow](#wrapping-up-appflow) - [NPM Caching - Appflow](#npm-caching-appflow) - [Native Configs - Appflow](#native-configs-appflow) - [Web Build and Web Previews - Appflow](#web-build-and-web-previews-appflow) - [Appflow Config Customizations & Monorepo Support - Appflow](#appflow-config-customizations-monorepo-support-appflow) - [SDK Changelog - Appflow](#sdk-changelog-appflow) - [Native Builds - Appflow](#native-builds-appflow) - [Connect Your Repo - Appflow](#connect-your-repo-appflow) - [Private Ionic Native Enterprise Edition Keys in Open Source Apps - Appflow](#private-ionic-native-enterprise-edition-keys-in-open-source-apps-appflow) - [Push a Commit - Appflow](#push-a-commit-appflow) - [Native Builds - Appflow](#native-builds-appflow) - [Add an App - Appflow](#add-an-app-appflow) - [iOS and Android Projects - Appflow](#ios-and-android-projects-appflow) - [Generating App Signing Certificates (iOS & Android)](#generating-app-signing-certificates-ios-android-) - [Native Builds With Signing Certificates - Appflow](#native-builds-with-signing-certificates-appflow) - [Create an Automation - Appflow](#create-an-automation-appflow) - [Project Creation and Git - Appflow](#project-creation-and-git-appflow) - [Self-hosted Live Updates Setup - Appflow](#self-hosted-live-updates-setup-appflow) - [Build Environments - Appflow](#build-environments-appflow) - [Environments - Appflow](#environments-appflow) - [Migrating from App Center to Ionic Appflow - Appflow](#migrating-from-app-center-to-ionic-appflow-appflow) - [Deploying to the App Stores - Appflow](#deploying-to-the-app-stores-appflow) - [Connect Using Bitbucket - Appflow](#connect-using-bitbucket-appflow) - [Live Updates - Appflow](#live-updates-appflow) - [Understanding Webhooks - Appflow](#understanding-webhooks-appflow) - [Create a Native Configuration - Appflow](#create-a-native-configuration-appflow) - [Create an Environment - Appflow](#create-an-environment-appflow) - [Deploy a Live Update - Appflow](#deploy-a-live-update-appflow) - [Connect Using Azure DevOps - Appflow](#connect-using-azure-devops-appflow) - [Capacitor SDK Setup - Appflow](#capacitor-sdk-setup-appflow) - [Connect Using Bitbucket Server - Appflow](#connect-using-bitbucket-server-appflow) - [Integrate a Git Host - Appflow](#integrate-a-git-host-appflow) - [Connect Using GitLab - Appflow](#connect-using-gitlab-appflow) - [Connect Using GitHub - Appflow](#connect-using-github-appflow) - [Cordova SDK Reference - Appflow](#cordova-sdk-reference-appflow) - [Connect Using GitLab Self-Managed - Appflow](#connect-using-gitlab-self-managed-appflow) - [Build a Native Binary - Appflow](#build-a-native-binary-appflow) - [Connect Using GitHub Enterprise - Appflow](#connect-using-github-enterprise-appflow) - [Connect Using Ionic Remote - Appflow](#connect-using-ionic-remote-appflow) - [Migrating from PhoneGap Build to Ionic Appflow - Appflow](#migrating-from-phonegap-build-to-ionic-appflow-appflow) - [Cordova Live Updates API Example - Appflow](#cordova-live-updates-api-example-appflow) - [appflow build - Appflow](#appflow-build-appflow) - [appflow - Appflow](#appflow-appflow) - [appflow build cancel - Appflow](#appflow-build-cancel-appflow) - [appflow build download-artifact - Appflow](#appflow-build-download-artifact-appflow) - [appflow build logs - Appflow](#appflow-build-logs-appflow) - [appflow build list-builds - Appflow](#appflow-build-list-builds-appflow) - [appflow deploy - Appflow](#appflow-deploy-appflow) - [appflow deploy android - Appflow](#appflow-deploy-android-appflow) - [appflow deploy web - Appflow](#appflow-deploy-web-appflow) - [appflow destination create-android - Appflow](#appflow-destination-create-android-appflow) - [appflow deploy ios - Appflow](#appflow-deploy-ios-appflow) - [appflow build get - Appflow](#appflow-build-get-appflow) - [appflow destination create-ios - Appflow](#appflow-destination-create-ios-appflow) - [appflow environment set - Appflow](#appflow-environment-set-appflow) - [appflow destination - Appflow](#appflow-destination-appflow) - [appflow destination delete - Appflow](#appflow-destination-delete-appflow) - [appflow environment list - Appflow](#appflow-environment-list-appflow) - [appflow destination update-ios - Appflow](#appflow-destination-update-ios-appflow) - [appflow destination update-android - Appflow](#appflow-destination-update-android-appflow) - [appflow environment get - Appflow](#appflow-environment-get-appflow) - [appflow destination list - Appflow](#appflow-destination-list-appflow) - [appflow environment - Appflow](#appflow-environment-appflow) - [appflow destination list-deployments - Appflow](#appflow-destination-list-deployments-appflow) - [appflow environment create - Appflow](#appflow-environment-create-appflow) - [appflow build android - Appflow](#appflow-build-android-appflow) - [appflow live-update list-channels - Appflow](#appflow-live-update-list-channels-appflow) - [appflow live-update bundle-artifact - Appflow](#appflow-live-update-bundle-artifact-appflow) - [appflow live-update create-channel - Appflow](#appflow-live-update-create-channel-appflow) - [appflow live-update channel-details - Appflow](#appflow-live-update-channel-details-appflow) - [appflow environment unset - Appflow](#appflow-environment-unset-appflow) - [appflow live-update - Appflow](#appflow-live-update-appflow) - [appflow environment delete - Appflow](#appflow-environment-delete-appflow) - [appflow live-update delete-channel - Appflow](#appflow-live-update-delete-channel-appflow) - [appflow live-update list-deployments - Appflow](#appflow-live-update-list-deployments-appflow) - [appflow live-update download-artifact - Appflow](#appflow-live-update-download-artifact-appflow) - [appflow destination get - Appflow](#appflow-destination-get-appflow) - [appflow live-update generate-manifest - Appflow](#appflow-live-update-generate-manifest-appflow) - [appflow environment update - Appflow](#appflow-environment-update-appflow) - [appflow live-update register-artifact - Appflow](#appflow-live-update-register-artifact-appflow) - [appflow live-update generate-signing-key - Appflow](#appflow-live-update-generate-signing-key-appflow) - [appflow native-config - Appflow](#appflow-native-config-appflow) - [appflow live-update set-native-versions - Appflow](#appflow-live-update-set-native-versions-appflow) - [appflow build web - Appflow](#appflow-build-web-appflow) - [appflow build ios - Appflow](#appflow-build-ios-appflow) - [appflow version - Appflow](#appflow-version-appflow) - [appflow native-config create - Appflow](#appflow-native-config-create-appflow) - [appflow native-config list - Appflow](#appflow-native-config-list-appflow) - [appflow native-config delete - Appflow](#appflow-native-config-delete-appflow) - [appflow live-update upload-artifact - Appflow](#appflow-live-update-upload-artifact-appflow) - [appflow native-config get - Appflow](#appflow-native-config-get-appflow) - [appflow native-config update - Appflow](#appflow-native-config-update-appflow) --- # Ionic Docs - Ionic Documentation [Skip to main content](https://ionic.io/docs#__docusaurus_skipToContent_fallback) On this page Ionic is a platform for building and deploying modern mobile applications and micro frontend experiences. Explore our products below, and check out our guides, examples, and references to help you learn to build and ship incredible apps faster than ever. Get started[​](https://ionic.io/docs#get-started "Direct link to Get started") ------------------------------------------------------------------------------- Start building with Ionic’s cross-platform development kit, or import any existing mobile app to build, publish, and update your apps from the cloud with Appflow: [#### Start a new app\ \ Create a new app via our CLI or visually with our App Wizard\ \ Create app →](https://ionicframework.com/docs/cli) [#### Import an app\ \ Import an existing app into the Appflow dashboard\ \ Import an app →](https://ionicframework.com/start#basics) * * * Mobile DevOps[​](https://ionic.io/docs#mobile-devops "Direct link to Mobile DevOps") ------------------------------------------------------------------------------------- [Appflow](https://ionic.io/docs/appflow) cloud services enable development teams to continuously build, automate, and ship their Ionic apps faster than ever. [![](https://ionic.io/docs/pages/index/icon-appflow-quickstart.png)![](https://ionic.io/docs/pages/index/icon-quickstart-active.png)\ \ Ionic's suite of cloud products for superpowered app development.](https://ionic.io/docs/appflow/quickstart) [![](https://ionic.io/docs/pages/index/icon-appflow-live-updates.png)![](https://ionic.io/docs/pages/index/icon-live-updates-active.png)\ \ Send live updates to your users at the speed of development.](https://ionic.io/docs/appflow/deploy/intro) [![](https://ionic.io/docs/pages/index/icon-appflow-native-builds.png)![](https://ionic.io/docs/pages/index/icon-appflow-native-builds-active.png)\ \ Compile native app binaries in the cloud without build servers.](https://ionic.io/docs/appflow/package/intro) [![](https://ionic.io/docs/pages/index/icon-appflow-app-publishing.png)![](https://ionic.io/docs/pages/index/icon-appflow-app-publishing-active.png)\ \ Publish directly to Testflight, App Store, Google Play, and Play Beta.](https://ionic.io/docs/appflow/destinations/intro) [![](https://ionic.io/docs/pages/index/icon-appflow-automations.png)![](https://ionic.io/docs/pages/index/icon-appflow-automations-active.png)\ \ Enable your team to utilize the full CI/CD powers of Appflow.](https://ionic.io/docs/appflow/automation/intro) [![](https://ionic.io/docs/pages/index/icon-appflow-cloud-cli.png)![](https://ionic.io/docs/pages/index/icon-appflow-cloud-cli-active.png)\ \ Use your own CI/CD platform for control of Appflow features.](https://ionic.io/docs/appflow/cli/overview) Mobile Micro Frontends[​](https://ionic.io/docs#mobile-micro-frontends "Direct link to Mobile Micro Frontends") ---------------------------------------------------------------------------------------------------------------- [Portals](https://ionic.io/docs/portals) is a solution for delivering embedded web apps and mobile micro frontend experiences. For apps built with Swift, Kotlin, React Native, or Capacitor. [![](https://ionic.io/docs/pages/index/icon-portals-overview.png)![](https://ionic.io/docs/pages/index/icon-portals-overview-active.png)\ \ Native iOS runtime to bridge JavaScript and Swift or Obj-C.](https://ionic.io/docs/portals) [![](https://ionic.io/docs/pages/index/icon-portals-for-ios.png)![](https://ionic.io/docs/pages/index/icon-portals-for-ios-active.png)\ \ Native iOS runtime to bridge JavaScript and Swift or Obj-C.](https://ionic.io/docs/portals/getting-started/iOS) [![](https://ionic.io/docs/pages/index/icon-portals-for-android.png)![](https://ionic.io/docs/pages/index/icon-portals-for-android-active.png)\ \ Native Android runtime to bridge JavaScript and Java or Kotlin.](https://ionic.io/docs/portals/getting-started/android) [![](https://ionic.io/docs/pages/index/icon-portals-for-react-native.png)![](https://ionic.io/docs/pages/index/icon-portals-for-react-native-active.png)\ \ Native Android runtime to bridge JavaScript and React Native.](https://ionic.io/docs/portals/getting-started/react-native) [![](https://ionic.io/docs/pages/index/icon-federated-capacitor.png)![](https://ionic.io/docs/pages/index/icon-federated-capacitor-active.png)\ \ Divide Capacitor apps into smaller micro frontends.](https://ionic.io/docs/portals/for-capacitor/overview) Mobile App Development[​](https://ionic.io/docs#mobile-app-development "Direct link to Mobile App Development") ---------------------------------------------------------------------------------------------------------------- ### Mobile UI[​](https://ionic.io/docs#mobile-ui "Direct link to Mobile UI") [Ionic Framework](https://ionicframework.com/) is a mobile UI toolkit that includes mobile-optimized UI controls, interactions, gestures, animations, and integrations with React, Angular, and Vue. [![](https://ionic.io/docs/pages/index/icon-ionic-react.png)![](https://ionic.io/docs/pages/index/icon-ionic-react-active.png)\ \ Learn how to build cross-platform mobile app UIs with React.](https://ionicframework.com/docs/react) [![](https://ionic.io/docs/pages/index/icon-ionic-angular.png)![](https://ionic.io/docs/pages/index/icon-ionic-angular-active.png)\ \ Learn how to build cross-platform mobile app UIs with Angular.](https://ionicframework.com/docs/angular/overview) [![](https://ionic.io/docs/pages/index/icon-ionic-vue.png)![](https://ionic.io/docs/pages/index/icon-ionic-vue-active.png)\ \ Learn how to build cross-platform mobile app UIs with Vue.](https://ionicframework.com/docs/vue/overview) ### Native plugins[​](https://ionic.io/docs#native-plugins "Direct link to Native plugins") [Capacitor](https://capacitorjs.com/) enables you to deploy an web application to iOS and Android. Add native functionality and experiences from a collection of open source and premium plugins, solutions, and integrations. [![](https://ionic.io/docs/pages/index/icon-capacitor-ios.png)![](https://ionic.io/docs/pages/index/icon-capacitor-ios-active.png)\ \ Native iOS runtime to bridge JavaScript and Swift or Obj-C.](https://capacitorjs.com/docs/ios) [![](https://ionic.io/docs/pages/index/icon-capacitor-for-android.png)![](https://ionic.io/docs/pages/index/icon-capacitor-for-android-active.png)\ \ Native Android runtime to bridge JavaScript and Java or Kotlin.](https://capacitorjs.com/docs/android) [![](https://ionic.io/docs/pages/index/icon-explore-plugins.png)![](https://ionic.io/docs/pages/index/icon-explore-plugins-active.png)\ \ Capacitor plugins for JavaScript to Native API connections.](https://capacitorjs.com/docs/plugins) ### Mobile Security[​](https://ionic.io/docs#mobile-security "Direct link to Mobile Security") Advanced mobile security solutions that are pre-built and ready to deploy in minutes, and fully supported by Ionic. [![](https://ionic.io/docs/pages/index/logo-identity-vault.png)![](https://ionic.io/docs/pages/index/icon-identity-vault-active.png)\ \ Lock down sensitive data with advanced biometrics](https://ionic.io/docs/identity-vault) [![](https://ionic.io/docs/pages/index/logo-auth-connect.png)![](https://ionic.io/docs/pages/index/icon-auth-connect-active.png)\ \ Connect to your authentication providers from any mobile device](https://ionic.io/docs/auth-connect) [![](https://ionic.io/docs/pages/index/logo-secure-storage.png)![](https://ionic.io/docs/pages/index/icon-secure-storage-active.png)\ \ High performance, secure mobile data storage](https://ionic.io/docs/secure-storage) Contents -------- * [Get started](https://ionic.io/docs#get-started) * [Mobile DevOps](https://ionic.io/docs#mobile-devops) * [Mobile Micro Frontends](https://ionic.io/docs#mobile-micro-frontends) * [Mobile App Development](https://ionic.io/docs#mobile-app-development) * [Mobile UI](https://ionic.io/docs#mobile-ui) * [Native plugins](https://ionic.io/docs#native-plugins) * [Mobile Security](https://ionic.io/docs#mobile-security) --- # Couchbase Lite Overview - Couchbase Lite [Skip to main content](https://ionic.io/docs/couchbase-lite#) Ionic's [Couchbase Lite](https://www.couchbase.com/products/lite) integration makes it easy to build secure, high-performance, offline-enabled apps using the industry-leading Couchbase Lite storage solution. This integration supports apps built for iOS, Android, and native Windows when using the new [Windows](https://ionic.io/docs/windows) platform support from Ionic. **Interested in Couchbase Lite support?** [Get in touch](https://ionic.io/contact/sales) . Ionic's Couchbase Lite integration is built and supported by the Ionic's native mobile experts and includes ongoing updates and maintenance, including new API features, patches, updates, and compatibility upgrades for new iOS & Android releases. --- # Intune Changelog - Couchbase Lite [Skip to main content](https://ionic.io/docs/couchbase-lite/changelog#) --- # Installation - Couchbase Lite [Skip to main content](https://ionic.io/docs/couchbase-lite/installation#) To installing Ionic's Couchbase Lite integration into your app, first check the prerequisites to make sure your app is compatible, and then install the package into your app. Prerequisites[#](https://ionic.io/docs/couchbase-lite/installation#prerequisites "Direct link to heading") ----------------------------------------------------------------------------------------------------------- **Important:** Ionic's Couchbase Lite integration uses Couchbase Lite Enterprise, and requires an existing Couchbase subscription with access to enterprise mobile functionality. Ionic's Couchbase Lite integration requires Capacitor 3.0 or above, and is _not_ compatible with Cordova-based Ionic apps. We _strongly_ recommend migrating to Capacitor and we offer [official migration support](https://ionic.io/advisory) to help your team navigate the transition. Installation[#](https://ionic.io/docs/couchbase-lite/installation#installation "Direct link to heading") --------------------------------------------------------------------------------------------------------- To get started, install the `@ionic-enterprise/couchbase-lite` package into your Ionic/Capacitor app: npm install @ionic-enterprise/couchbase-lite Copy Android: Add Maven Repo[#](https://ionic.io/docs/couchbase-lite/installation#android-add-maven-repo "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------------ Edit your `android/build.gradle` file and update the `allprojects` entry to make sure the Couchbase maven repository is listed: allprojects { repositories { google() jcenter() maven { url 'https://mobile.maven.couchbase.com/maven2/dev/' } }} Copy Sync Project[#](https://ionic.io/docs/couchbase-lite/installation#sync-project "Direct link to heading") --------------------------------------------------------------------------------------------------------- Then, sync your Capacitor app to load any native dependencies: npx cap sync# orionic capacitor sync Copy Once installed, move onto [Usage](https://ionic.io/docs/couchbase-lite/usage) to see how to start using Couchbase Lite in your app. * [Prerequisites](https://ionic.io/docs/couchbase-lite/installation#prerequisites) * [Installation](https://ionic.io/docs/couchbase-lite/installation#installation) * [Android: Add Maven Repo](https://ionic.io/docs/couchbase-lite/installation#android-add-maven-repo) * [Sync Project](https://ionic.io/docs/couchbase-lite/installation#sync-project) --- # Hotel Search Tutorial - Couchbase Lite [Skip to main content](https://ionic.io/docs/couchbase-lite/tutorials/hotel-search#) Learn how to build an Angular app with Capacitor that allows users to search and bookmark hotels using data loaded from a Couchbase Lite database. The complete reference app is [available here](https://github.com/ionic-team/demo-couchbaselite-hotels) . > Not an Angular developer? Couchbase Lite concepts and syntax are applicable to all web frameworks. By completing this tutorial, you'll create an app that: * Loads and stores data, including bookmarked hotels, in a Couchbase Lite database. * Uses UI components from Ionic: search bar, bookmarks, icons, list items, and more. * Runs on iOS, Android, and native Windows apps all from the same codebase. Setup[#](https://ionic.io/docs/couchbase-lite/tutorials/hotel-search#setup "Direct link to heading") ----------------------------------------------------------------------------------------------------- Begin by installing the Ionic CLI then creating an Ionic app: npm install -g @ionic/cliionic start Copy In this tutorial, we'll choose the "tabs" starter template, but any template will suffice. Next, install Capacitor, Ionic's native runtime tool for building cross-platform web native apps: # Add Capacitor along with iOS and Android native projectsionic integrations enable capacitornpx capacitor add iosnpx capacitor add android Copy Integrate Couchbase Lite[#](https://ionic.io/docs/couchbase-lite/tutorials/hotel-search#integrate-couchbase-lite "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------------------------- With the application setup, it's time to add the Couchbase Lite solution: npm install @ionic-enterprise/couchbase-litenpx cap sync Copy Next, create a model class to represent `Hotel` data: // src/app/data/hotels.tsexport class Hotel { id?: number; name: string; address: string; phone: string; bookmarked: boolean = false;} Copy It's recommended to create a service that encapsulates all Couchbase Lite functionality, so create it: ionic generate service services/database Copy Within `database.service.ts`, import the Couchbase Lite integration and the new `Hotel` model: // src/app/services/database.service.tsimport { Injectable } from '@angular/core';import { Database, DatabaseConfiguration, MutableDocument} from '@ionic-enterprise/couchbase-lite';import { Hotel } from '../models/hotel'; @Injectable({ providedIn: 'root'})export class DatabaseService { } Copy Next, add some private variables to the beginning of the `DatabaseService` class. `database` will hold an open connection to the Couchbase Lite database so we can perform operations on it, `bookmarkDocument` will be used for allowing users to bookmark hotels, and the two `DOC_TYPE` constants will be used repeatably in database querying. // src/app/services/database.service.tsexport class DatabaseService { private database: Database; private DOC_TYPE_HOTEL = "hotel"; private DOC_TYPE_BOOKMARKED_HOTELS = "bookmarked_hotels"; private bookmarkDocument: MutableDocument;} Copy ### Initialize the Database[#](https://ionic.io/docs/couchbase-lite/tutorials/hotel-search#initialize-the-database "Direct link to heading") Next, create an initialization function that will run every time the app loads, configuring the Couchbase Lite database. // src/app/services/database.service.tsprivate async initializeDatabase() { await this.seedInitialData();} Copy Next, create a function to seed the Couchbase database with hotel data. First, create then open the Couchbase Lite database. You can set an encryption key to encrypt the database with if you'd like, too. Give the database a name like "travel." // src/app/services/database.service.tsprivate async seedInitialData() { /* Note about encryption: In a real-world app, the encryption key should not be hardcoded like it is here. One strategy is to auto generate a unique encryption key per user on initial app load, then store it securely in the device's keychain for later retrieval. Ionic's Identity Vault (https://ionic.io/docs/identity-vault) plugin is an option. Using IV’s storage API, you can ensure that the key cannot be read or accessed without the user being authenticated first. */ let dc = new DatabaseConfiguration(); dc.setEncryptionKey('8e31f8f6-60bd-482a-9c70-69855dd02c39'); this.database = new Database("travel", dc); await this.database.open(); Copy Finish up the `seedInitialData` function by inserting hotel data into the database if this is the first time the app has been loaded. Create a new `MutableDocument` for each hotel record, then insert it into the database. // src/app/services/database.service.ts, seedInitialData() const len = (await this.getAllHotels()).length; if (len === 0) { const hotelFile = await import("../data/hotels"); for (let hotel of hotelFile.hotelData) { let doc = new MutableDocument() .setNumber('id', hotel.id) .setString('name', hotel.name) .setString('address', hotel.address) .setString('phone', hotel.phone) .setString('type', this.DOC_TYPE_HOTEL); this.database.save(doc); } }} Copy Next, implement the `getAllHotels` helper function that returns all hotels from the database. The steps are the same for retrieving data from a Couchbase Lite database: create a query, execute it, then parse the results. `SELECT *` means select all records, `FROM _` means from the current database (Couchbase can query multiple databases at once, but since there is only one, `_` refers to the main one), `WHERE type = '${this.DOC_TYPE_HOTEL}'` means where the type property is equal to 'hotel' (database documents are either of type 'hotel' or 'bookmarked\_hotels' in our dataset), and `ORDER BY name` means to return the results in ascending order using the hotel name property. // src/app/services/database.service.tsprivate async getAllHotels() { const query = this.database.createQuery(`SELECT * FROM _ WHERE type = '${this.DOC_TYPE_HOTEL}' ORDER BY name`); const result = await query.execute(); return await result.allResults();} Copy ### Display Hotel Data[#](https://ionic.io/docs/couchbase-lite/tutorials/hotel-search#display-hotel-data "Direct link to heading") With database setup in place, we can retrieve and display hotel data next. Create a public function that the UI will call, `getHotels`, that calls the above work we just created to initialize the Couchbase Lite database and return the list of all hotels. // src/app/services/database.service.tspublic async getHotels(): Promise { await this.initializeDatabase(); return await this.retrieveHotelList();} Copy Next, create a function that queries the database for all hotel records and transforms them into an array of `Hotel` objects. Since Couchbase can query multiple databases at once, the array format is a bit unique. Access each hotel record by using `hotelResults[key]["_"]`. // src/app/services/database.service.tsprivate async retrieveHotelList(): Promise { // Get all hotels const hotelResults = this.getAllHotels(); let hotelList: Hotel[] = []; for (let key in hotelResults) { // Couchbase can query multiple databases at once, so "_" is just this single database. // [ { "_": { id: "1", firstName: "Matt" } }, { "_": { id: "2", firstName: "Max" } }] let singleHotel = hotelResults[key]["_"] as Hotel; hotelList.push(singleHotel); } return hotelList;} Copy We now have enough of the `DatabaseService` functionality built to be able to display hotels to the user. Open `tab1.page.ts` then import the `DatabaseService`. Retrieve the hotel data when the page first loads. // src/app/tab1/tab1.page.tsimport { Component } from '@angular/core';import { Hotel } from '../models/hotel';import { DatabaseService } from '../services/database.service'; @Component({ selector: 'app-tab1', templateUrl: 'tab1.page.html', styleUrls: ['tab1.page.scss']})export class Tab1Page { hotels: Hotel[] = []; hotelsDisplayed: Hotel[] = []; constructor(private databaseService: DatabaseService) {} async ngOnInit() { this.hotels = await this.databaseService.getHotels(); this.hotelsDisplayed = this.hotels; }} Copy To display the hotels on the `tab1.page.html` page, use the `ion-list` component: Hotels Hotels

{{ hotel.name }}

{{ hotel.address }}

{{ hotel.phone }}

Copy A list of all hotels are now displayed on the page. Search Hotels[#](https://ionic.io/docs/couchbase-lite/tutorials/hotel-search#search-hotels "Direct link to heading") --------------------------------------------------------------------------------------------------------------------- Now that all hotels are displayed, we can build some interactive features such as search functionality. Open `database.service.ts` then create a `searchHotels` function. First, build a N1QL query that searches the Couchbase Lite database for hotels that match the provided hotel name the user types into a search bar. The query is similar to the one that retrieves all hotel data, except for the `LIKE` comparison operator which performs string wildcard pattern matching comparisons. In this case, we're searching broadly - any hotel name that includes any of the characters the user enters. `%` here will match zero or more characters. Finally, return the list of filtered hotels back to the UI layer. // src/app/services/database.service.tspublic async searchHotels(name): Promise { const query = this.database.createQuery( `SELECT * FROM _ WHERE name LIKE '%${name}%' AND type = '${this.DOC_TYPE_HOTEL}' ORDER BY name`); const results = await (await query.execute()).allResults(); let filteredHotels: Hotel[] = []; for (var key in results) { let singleHotel = results[key]["_"] as Hotel; filteredHotels.push(singleHotel); } return filteredHotels;} Copy Over in `tab1.page.html`, add an `ion-searchbar` search bar component above the `ion-list`. The `ionChange` event fires each time the user enters new text into the search bar. Copy Within `searchQueryChanged`, pass along the hotel name string into the database service. Since `hotelsDisplayed` represents the array of filtered list of hotels to display to the end user, the UI will update automatically after each character is typed by the user. // src/app/tab1/tab1.page.tsasync searchQueryChanged(hotelName) { this.hotelsDisplayed = await this.databaseService.searchHotels(hotelName);} Copy With this code in place, the user can successfully filter through hotels. Bookmark Hotels[#](https://ionic.io/docs/couchbase-lite/tutorials/hotel-search#bookmark-hotels "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------- The final feature we'll add is the ability to bookmark hotels that the user is interested in staying at. This includes saving the bookmark data in Couchbase Lite as well as offering the ability to toggle between all hotels and bookmarked hotels in the UI. ### Retrieve Bookmark Data[#](https://ionic.io/docs/couchbase-lite/tutorials/hotel-search#retrieve-bookmark-data "Direct link to heading") First, add a call to `findOrCreateBookmarkDocument()` in the initialize method: // src/app/services/database.service.tsprivate async initializeDatabase() { await this.seedInitialData(); // Create the "bookmarked_hotels" document if it doesn't exist this.bookmarkDocument = await this.findOrCreateBookmarkDocument();} Copy The bookmarked hotels will be stored in a Couchbase Lite document as an array of hotel ids. Next, implement the method which will retrieve the bookmark document or create it if it doesn't exist. // src/app/services/database.service.tsprivate async findOrCreateBookmarkDocument(): Promise { // Meta().id is a GUID like e15d1aa2-9be3-4e02-92d8-82bd9d05d8e3 const bookmarkQuery = this.database.createQuery( `SELECT META().id AS id FROM _ WHERE type = '${this.DOC_TYPE_BOOKMARKED_HOTELS}'`); const resultSet = await bookmarkQuery.execute(); const resultList = await resultSet.allResults(); let mutableDocument: MutableDocument; if (resultList.length === 0) { mutableDocument = new MutableDocument() .setString("type", this.DOC_TYPE_BOOKMARKED_HOTELS) .setArray("hotels", new Array()); this.database.save(mutableDocument); } else { const docId = resultList[0]["id"]; const doc = await this.database.getDocument(docId); mutableDocument = MutableDocument.fromDocument(doc); } return mutableDocument;} Copy Next, update the `retrieveHotelList()` method to toggle the `bookmarked` hotel property if the hotel's id is found in the bookmarked hotels document. The `bookmarked` boolean property determines whether to display the hotel as bookmarked in the UI. Here's the complete function: // src/app/services/database.service.tsprivate async retrieveHotelList(): Promise { // Get all hotels const hotelResults = this.getAllHotels(); // Get all bookmarked hotels let bookmarks = this.bookmarkDocument.getArray("hotels") as number[]; let hotelList: Hotel[] = []; for (let key in hotelResults) { // Couchbase can query multiple databases at once, so "_" is just this single database. // [ { "_": { id: "1", name: "Matt" } }, { "_": { id: "2", name: "Max" } }] let singleHotel = hotelResults[key]["_"] as Hotel; // Set bookmark status singleHotel.bookmarked = bookmarks.includes(singleHotel.id); hotelList.push(singleHotel); } return hotelList;} Copy Finally, update the UI to display each hotel's bookmark status. Show a transparent bookmark icon from Ionicons next to each hotel listing. If the hotel has been bookmarked, then show a red filled-in icon.

{{ hotel.name }}

{{ hotel.address }}

{{ hotel.phone }}

Copy Now that bookmarked hotel data is being displayed, we can introduce more interactivity. ### Save Bookmarked Hotels[#](https://ionic.io/docs/couchbase-lite/tutorials/hotel-search#save-bookmarked-hotels "Direct link to heading") When the user taps on the bookmark icon next to a hotel entry, we need to update the Couchbase Lite database to reflect that state change. First, implement the toggle function to invert the hotel's bookmark status, then save the change using the database service: // src/app/tab1/tab1.page.tsasync toggleBookmark(hotel) { hotel.bookmarked = !hotel.bookmarked; if (hotel.bookmarked) { await this.databaseService.bookmarkHotel(hotel.id); } else { await this.databaseService.unbookmarkHotel(hotel.id); }} Copy Next, implement a function to apply the bookmark change to the Couchbase Lite database. Add the hotel id to the array of hotels that are bookmarked: // src/app/services/database.service.tspublic async bookmarkHotel(hotelId: number) { let hotelArray = this.bookmarkDocument.getArray("hotels") as number[]; hotelArray.push(hotelId); this.bookmarkDocument.setArray("hotels", hotelArray); this.database.save(this.bookmarkDocument);} Copy ### Remove Bookmark[#](https://ionic.io/docs/couchbase-lite/tutorials/hotel-search#remove-bookmark "Direct link to heading") If the user can bookmark a hotel, they should also be able to remove the bookmark. A similar implementation as bookmarking hotels, but instead of adding the hotel id, remove it from the bookmark array. // src/app/services/database.service.tspublic async unbookmarkHotel(hotelId: number) { let hotelArray = this.bookmarkDocument.getValue("hotels") as number[]; hotelArray = hotelArray.filter(id => id !== hotelId); this.bookmarkDocument.setArray("hotels", hotelArray); this.database.save(this.bookmarkDocument);} Copy ### Filter by Bookmarked Hotels[#](https://ionic.io/docs/couchbase-lite/tutorials/hotel-search#filter-by-bookmarked-hotels "Direct link to heading") The last feature to add is the ability to toggle between all hotels and only bookmarked hotels. Begin by creating a variable to hold the state of the bookmark filter toggle and default it to false. // src/app/tab1/tab1.page.tsexport class Tab1Page { toggleBookmarkFilter: boolean = false; // snip - other variables Copy Next, implement a function that toggles between bookmark states. Invert the bookmark filter property and check if it's `true`. If true, filter the hotel list for only those that have the `bookmarked` property set to true. Refresh the UI to reflect the updated hotel list. // src/app/tab1/tab1.page.tsasync toggleShowBookmarks() { this.toggleBookmarkFilter = !this.toggleBookmarkFilter; if (this.toggleBookmarkFilter) { const filtered = this.hotels.filter(h => h.bookmarked == true); this.hotelsDisplayed = filtered; } else { this.hotelsDisplayed = this.hotels; }} Copy Finally, update the UI so that when a bookmark filter icon is tapped, the `toggleShowBookmarks()` function is called. Display the same bookmark icon also displayed next to each hotel entry. Hotels Copy Wrap Up[#](https://ionic.io/docs/couchbase-lite/tutorials/hotel-search#wrap-up "Direct link to heading") --------------------------------------------------------------------------------------------------------- That's it! You've built an Angular app that allows users to search and bookmark hotels using data loaded from a Couchbase Lite database. Happy app building! * [Setup](https://ionic.io/docs/couchbase-lite/tutorials/hotel-search#setup) * [Integrate Couchbase Lite](https://ionic.io/docs/couchbase-lite/tutorials/hotel-search#integrate-couchbase-lite) * [Initialize the Database](https://ionic.io/docs/couchbase-lite/tutorials/hotel-search#initialize-the-database) * [Display Hotel Data](https://ionic.io/docs/couchbase-lite/tutorials/hotel-search#display-hotel-data) * [Search Hotels](https://ionic.io/docs/couchbase-lite/tutorials/hotel-search#search-hotels) * [Bookmark Hotels](https://ionic.io/docs/couchbase-lite/tutorials/hotel-search#bookmark-hotels) * [Retrieve Bookmark Data](https://ionic.io/docs/couchbase-lite/tutorials/hotel-search#retrieve-bookmark-data) * [Save Bookmarked Hotels](https://ionic.io/docs/couchbase-lite/tutorials/hotel-search#save-bookmarked-hotels) * [Remove Bookmark](https://ionic.io/docs/couchbase-lite/tutorials/hotel-search#remove-bookmark) * [Filter by Bookmarked Hotels](https://ionic.io/docs/couchbase-lite/tutorials/hotel-search#filter-by-bookmarked-hotels) * [Wrap Up](https://ionic.io/docs/couchbase-lite/tutorials/hotel-search#wrap-up) --- # Windows Installation - Couchbase Lite [Skip to main content](https://ionic.io/docs/couchbase-lite/windows-installation#) To install the Ionic Couchbase Lite integration into Capacitor Windows, first follow the [Installation](https://ionic.io/docs/couchbase-lite/installation) guide to install the `@ionic-enterprise/couchbase-lite` package. Note: this plugin requires `@ionic-enterprise/capacitor-windows` `1.5.0` or greater. Then, run: npx cap sync @ionic-enterprise/capacitor-windows Copy Follow the guide below that is most relevant to your app (packaged or unpackaged): Packaged Apps (using Windows App SDK)[#](https://ionic.io/docs/couchbase-lite/windows-installation#packaged-apps-using-windows-app-sdk "Direct link to heading") ----------------------------------------------------------------------------------------------------------------------------------------------------------------- When using Ionic Couchbase Lite in a packaged app context, ### Open in Visual Studio[#](https://ionic.io/docs/couchbase-lite/windows-installation#open-in-visual-studio "Direct link to heading") Open your project in visual studio by running npx cap open @ionic-enterprise/capacitor-windows Copy This will attempt to automatically locate your Visual Studio 2022 or 2019 installation, in that order. If your installation is in a non-standard location, set the `CAPACITOR_VISUAL_STUDIO_PATH` environment variable to the location of `devenv.exe` for your Visual Studio install, and then re-run the above command. ### Install the Plugin in Visual Studio[#](https://ionic.io/docs/couchbase-lite/windows-installation#install-the-plugin-in-visual-studio "Direct link to heading") Open the Package Manager Console: ![Package Manager Console](https://ionic.io/docs/couchbase-lite/assets/images/package-manager-console-8838e708656cd0e6bf764e6d381f268d.png) Then run: Install-Package IonicCouchbaseLite -ProjectName AppInstall-Package Couchbase.Lite.Enterprise -Version 2.8.6 -ProjectName App Copy Unpackaged Apps (using WPF):[#](https://ionic.io/docs/couchbase-lite/windows-installation#unpackaged-apps-using-wpf "Direct link to heading") ---------------------------------------------------------------------------------------------------------------------------------------------- When using Ionic Couchbase Lite in an unpackaged (standard .exe/win32) context, use the following instructions to install the plugin. Note: this requires `@ionic-enterprise/couchbase-lite` `2.5.5` or greater. ### Open in Visual Studio[#](https://ionic.io/docs/couchbase-lite/windows-installation#open-in-visual-studio-1 "Direct link to heading") Open your project in visual studio by running npx cap open @ionic-enterprise/capacitor-windows Copy This will attempt to automatically locate your Visual Studio 2022 or 2019 installation, in that order. If your installation is in a non-standard location, set the `CAPACITOR_VISUAL_STUDIO_PATH` environment variable to the location of `devenv.exe` for your Visual Studio install, and then re-run the above command. ### Install the Plugin in Visual Studio[#](https://ionic.io/docs/couchbase-lite/windows-installation#install-the-plugin-in-visual-studio-1 "Direct link to heading") Open the Package Manager Console and install the package: ![Package Manager Console](https://ionic.io/docs/couchbase-lite/assets/images/package-manager-console-8838e708656cd0e6bf764e6d381f268d.png) Then, enter into the console the following (note the `.WPF` package name): Install-Package IonicCouchbaseLite.WPF -ProjectName AppInstall-Package Couchbase.Lite.Enterprise -Version 2.8.6 -ProjectName App Copy Installation Complete[#](https://ionic.io/docs/couchbase-lite/windows-installation#installation-complete "Direct link to heading") ----------------------------------------------------------------------------------------------------------------------------------- The plugin should now be installed in your project. Rerun the above commands to update the package in the future. * [Packaged Apps (using Windows App SDK)](https://ionic.io/docs/couchbase-lite/windows-installation#packaged-apps-using-windows-app-sdk) * [Open in Visual Studio](https://ionic.io/docs/couchbase-lite/windows-installation#open-in-visual-studio) * [Install the Plugin in Visual Studio](https://ionic.io/docs/couchbase-lite/windows-installation#install-the-plugin-in-visual-studio) * [Unpackaged Apps (using WPF):](https://ionic.io/docs/couchbase-lite/windows-installation#unpackaged-apps-using-wpf) * [Open in Visual Studio](https://ionic.io/docs/couchbase-lite/windows-installation#open-in-visual-studio-1) * [Install the Plugin in Visual Studio](https://ionic.io/docs/couchbase-lite/windows-installation#install-the-plugin-in-visual-studio-1) * [Installation Complete](https://ionic.io/docs/couchbase-lite/windows-installation#installation-complete) --- # Changelog - Secure Storage [Skip to main content](https://ionic.io/docs/secure-storage/changelog#__docusaurus_skipToContent_fallback) [3.0.6\ -----](https://ionic.io/docs/secure-storage/changelog#release-3.0.6) patch ### April 15, 2025 ### What's Changed * **Fix:** Correct build artifacts missing in v3.0.5 [3.0.5\ -----](https://ionic.io/docs/secure-storage/changelog#release-3.0.5) patch ### April 14, 2025 ### What's Changed * **Fix:** Update sqlcipher to 4.7.1 ([RMET-4173](https://outsystemsrd.atlassian.net/browse/RMET-4173) ) [3.0.4\ -----](https://ionic.io/docs/secure-storage/changelog#release-3.0.4) patch ### December 18, 2024 ### What's Changed * **Fix:** Delete KV store DB without key [3.0.3\ -----](https://ionic.io/docs/secure-storage/changelog#release-3.0.3) patch ### March 13, 2023 ### What's Changed * **Fix:** Use one-time transactions for SQLite operations within the `KeyValueStorage` API. ([RMET-3136](https://outsystemsrd.atlassian.net/browse/RMET-3136) ) [3.0.2\ -----](https://ionic.io/docs/secure-storage/changelog#release-3.0.2) patch ### July 12, 2023 ### What's Changed * **Fix:** iOS Use podspec tag for dependencies [3.0.1\ -----](https://ionic.io/docs/secure-storage/changelog#release-3.0.1) patch ### May 17, 2023 ### What's Changed * **Fix:** Supports Angular partial compiler flag [3.0.0\ -----](https://ionic.io/docs/secure-storage/changelog#release-3.0.0) major ### February 10, 2023 ### What's Changed * **Breaking Change:** Updates compatibility with awesome-cordova 6 [2.3.1\ -----](https://ionic.io/docs/secure-storage/changelog#release-2.3.1) patch ### October 14, 2022 ### What's Changed * **Fix:** Updates `sqlcipher` to 4.5.2 [2.3.3\ -----](https://ionic.io/docs/secure-storage/changelog#release-2.3.3) patch ### September 9, 2022 ### What's Changed * **Fix:** Address an compiler issue with Angular AOT. [2.3.2\ -----](https://ionic.io/docs/secure-storage/changelog#release-2.3.2) patch ### July 6, 2022 ### What's Changed * **Fix:** Update dependencies [2.3.1\ -----](https://ionic.io/docs/secure-storage/changelog#release-2.3.1) patch ### June 16, 2022 ### What's Changed * **Fix:** Add missing exports path [2.3.0\ -----](https://ionic.io/docs/secure-storage/changelog#release-2.3.0) minor ### June 13, 2022 ### What's Changed * **Feature:** Add `KeyValueStorage` support --- # Secure Storage API - Secure Storage [Skip to main content](https://ionic.io/docs/secure-storage/api#__docusaurus_skipToContent_fallback) On this page Index[​](https://ionic.io/docs/secure-storage/api#index "Direct link to Index") -------------------------------------------------------------------------------- ### Classes[​](https://ionic.io/docs/secure-storage/api#classes "Direct link to Classes") * [SQLite](https://ionic.io/docs/secure-storage/api#sqlite) ### Interfaces[​](https://ionic.io/docs/secure-storage/api#interfaces "Direct link to Interfaces") * [SQLiteDatabaseConfig](https://ionic.io/docs/secure-storage/api#sqlitedatabaseconfig) * * * Classes[​](https://ionic.io/docs/secure-storage/api#classes-1 "Direct link to Classes") ---------------------------------------------------------------------------------------- ### SQLite[​](https://ionic.io/docs/secure-storage/api#sqlite "Direct link to SQLite") **SQLite**: _**name**_: SQLite _**description**_: Access SQLite databases on the device. _**usage**_: import { SQLite, SQLiteObject } from '@ionic-enterprise/secure-storage/ngx';constructor(private sqlite: SQLite) { }...this.sqlite.create({ name: 'data.db', location: 'default'}) .then((db: SQLiteObject) => { db.executeSql('create table danceMoves(name VARCHAR(32))', []) .then(() => console.log('Executed SQL')) .catch(e => console.log(e)); }) .catch(e => console.log(e)); _**classes**_: SQLiteObject _**interfaces**_: SQLiteDatabaseConfig SQLiteTransaction ### create[​](https://ionic.io/docs/secure-storage/api#create "Direct link to create") ▸ **create**(config: _[SQLiteDatabaseConfig](https://ionic.io/docs/secure-storage/api#sqlitedatabaseconfig) _): `Promise`<`SQLiteObject`\> Open or create a SQLite database file. See the plugin docs for an explanation of all options: [https://github.com/litehelpers/Cordova-sqlite-storage#opening-a-database](https://github.com/litehelpers/Cordova-sqlite-storage#opening-a-database) **Parameters:** | Name | Type | Description | | --- | --- | --- | | config | [SQLiteDatabaseConfig](https://ionic.io/docs/secure-storage/api#sqlitedatabaseconfig) | database configuration | **Returns:** `Promise`<`SQLiteObject`\> `Promise` * * * ### deleteDatabase[​](https://ionic.io/docs/secure-storage/api#deletedatabase "Direct link to deleteDatabase") ▸ **deleteDatabase**(config: _[SQLiteDatabaseConfig](https://ionic.io/docs/secure-storage/api#sqlitedatabaseconfig) _): `Promise`<`any`\> Deletes a database **Parameters:** | Name | Type | Description | | --- | --- | --- | | config | [SQLiteDatabaseConfig](https://ionic.io/docs/secure-storage/api#sqlitedatabaseconfig) | database configuration | **Returns:** `Promise`<`any`\> * * * ### echoTest[​](https://ionic.io/docs/secure-storage/api#echotest "Direct link to echoTest") ▸ **echoTest**(): `Promise`<`any`\> Verify that both the Javascript and native part of this plugin are installed in your application **Returns:** `Promise`<`any`\> * * * ### selfTest[​](https://ionic.io/docs/secure-storage/api#selftest "Direct link to selfTest") ▸ **selfTest**(): `Promise`<`any`\> Automatically verify basic database access operations including opening a database **Returns:** `Promise`<`any`\> * * * * * * Interfaces[​](https://ionic.io/docs/secure-storage/api#interfaces-1 "Direct link to Interfaces") ------------------------------------------------------------------------------------------------- ### SQLiteDatabaseConfig[​](https://ionic.io/docs/secure-storage/api#sqlitedatabaseconfig "Direct link to SQLiteDatabaseConfig") **SQLiteDatabaseConfig**: ### `` createFromLocation[​](https://ionic.io/docs/secure-storage/api#optional-createfromlocation "Direct link to optional-createfromlocation") **● createFromLocation**: _`number`_ support opening pre-filled databases with [https://github.com/litehelpers/cordova-sqlite-ext](https://github.com/litehelpers/cordova-sqlite-ext) * * * ### `` iosDatabaseLocation[​](https://ionic.io/docs/secure-storage/api#optional-iosdatabaselocation "Direct link to optional-iosdatabaselocation") **● iosDatabaseLocation**: _`string`_ iOS Database Location. Example: 'Library' * * * ### `` key[​](https://ionic.io/docs/secure-storage/api#optional-key "Direct link to optional-key") **● key**: _`string`_ support encrypted databases with [https://github.com/litehelpers/Cordova-sqlcipher-adapter](https://github.com/litehelpers/Cordova-sqlcipher-adapter) * * * ### `` location[​](https://ionic.io/docs/secure-storage/api#optional-location "Direct link to optional-location") **● location**: _`string`_ Location of the database. Example: 'default' * * * ### name[​](https://ionic.io/docs/secure-storage/api#name "Direct link to name") **● name**: _`string`_ Name of the database. Example: 'my.db' * * * Contents -------- * [Index](https://ionic.io/docs/secure-storage/api#index) * [Classes](https://ionic.io/docs/secure-storage/api#classes) * [Interfaces](https://ionic.io/docs/secure-storage/api#interfaces) * [Classes](https://ionic.io/docs/secure-storage/api#classes-1) * [SQLite](https://ionic.io/docs/secure-storage/api#sqlite) * [create](https://ionic.io/docs/secure-storage/api#create) * [deleteDatabase](https://ionic.io/docs/secure-storage/api#deletedatabase) * [echoTest](https://ionic.io/docs/secure-storage/api#echotest) * [selfTest](https://ionic.io/docs/secure-storage/api#selftest) * [Interfaces](https://ionic.io/docs/secure-storage/api#interfaces-1) * [SQLiteDatabaseConfig](https://ionic.io/docs/secure-storage/api#sqlitedatabaseconfig) * [`` createFromLocation](https://ionic.io/docs/secure-storage/api#optional-createfromlocation) * [`` iosDatabaseLocation](https://ionic.io/docs/secure-storage/api#optional-iosdatabaselocation) * [`` key](https://ionic.io/docs/secure-storage/api#optional-key) * [`` location](https://ionic.io/docs/secure-storage/api#optional-location) * [name](https://ionic.io/docs/secure-storage/api#name) --- # Usage - Couchbase Lite [Skip to main content](https://ionic.io/docs/couchbase-lite/usage#) After installing the plugin, import `@ionic-enterprise/couchbase-lite` into the desired class (A dedicated service class that encapsulates Couchbase Lite logic is recommended). import { BasicAuthenticator, CordovaEngine, Database, Function, Meta, MutableDocument, QueryBuilder, SelectResult, DataSource, Expression, Ordering, Query, ResultSet, Result, Replicator, ReplicatorConfiguration, ReplicatorChange, URLEndpoint, ArrayFunction, PropertyExpression, Join,} from '@ionic-enterprise/couchbase-lite'; Copy Next, initialize the database: /* Note about encryption: In a real-world app, the encryption key should not be hardcoded like it is here. One strategy is to auto generate a unique encryption key per user on initial app load, then store it securely in the device's keychain for later retrieval. Ionic's Identity Vault plugin is an option. Using IV’s storage API, you can ensure that the key cannot be read or accessed without the user being authenticated first.*/private async initializeDatabase(): Promise { return new Promise(resolve => { IonicCBL.onReady(async () => { const config = new DatabaseConfiguration(); // On windows, specify the path to the directory the database will be stored // in explicitly to ensure user can write to it // config.directory = 'C:\\Users\\...'; config.setEncryptionKey('8e31f8f6-60bd-482a-9c70-69855dd02c38'); this.database = new Database('DATABASE_NAME', config); await this.database.open(); resolve(); }); });} Copy Create a new document and save it to the database: // Create a new document (i.e. a record) in the database.let mutableDoc = new MutableDocument() .setFloat('version', 2.0) .setString('type', 'SDK') .setString('company', 'Ionic'); // Save it to the database.await this.database.save(mutableDoc); Copy Run a simple Query: // Create a query to fetch documents of type SDK.let query = QueryBuilder.select( SelectResult.property('version'), SelectResult.property('type'), SelectResult.property('company'),) .from(DataSource.database(database)) .where(Expression.property('type').equalTo(Expression.string('SDK')));const result = await(await query.execute()).allResults();console.log('Number of rows: ' + result.size()); Copy Build and run. You should see a row count of one printed to the console, as the document was successfully persisted to the database. Bi-directional replications with Sync Gateway: // Create replicators to push and pull changes to and from the cloud.let targetEndpoint = new URLEndpoint( new URI('ws://localhost:4984/example_sg_db'),);let replConfig = new ReplicatorConfiguration(database, targetEndpoint);replConfig.setReplicatorType( ReplicatorConfiguration.ReplicatorType.PUSH_AND_PULL,); // Add authentication.replConfig.setAuthenticator(new BasicAuthenticator('john', 'pass')); // Create replicator.let replicator = new Replicator(replConfig); // Listen to replicator change events.replicator.addChangeListener(status => {}); // Start replication.replicator.start(); Copy Beyond these docs, reference [Couchbase Lite's documentation](https://docs.couchbase.com/couchbase-lite/current/swift.html#blobs) for more functionality details and examples. Database[#](https://ionic.io/docs/couchbase-lite/usage#database "Direct link to heading") ------------------------------------------------------------------------------------------ ### New Database[#](https://ionic.io/docs/couchbase-lite/usage#new-database "Direct link to heading") As the top-level entity in the API, new databases can be created using the `Database` class by passing in a name, configuration, or both. The following example creates a database using the `Database(name: string)` constructor: let config = new DatabaseConfiguration();let database = new Database('my-database', config); Copy The database will be created on the device. Alternatively, the `Database(name: string, config: DatabaseConfiguration)` initializer can be used to provide specific options in the [`DatabaseConfiguration`](http://docs.couchbase.com/mobile/2.0/couchbase-lite-java/db022/com/couchbase/lite/DatabaseConfiguration.html) object such as the database directory. ### Loading a pre-built Database[#](https://ionic.io/docs/couchbase-lite/usage#loading-a-pre-built-database "Direct link to heading") If your app needs to sync a lot of data initially, but that data is fairly static and won’t change much, it can be a lot more efficient to bundle a database in your application and install it on the first launch. Even if some of the content changes on the server after you create the app, the app’s first pull replication will bring the database up to date. To use a prebuilt database, you need to set up the database, build the database into your app bundle as a resource, and install the database during the initial launch. After your app launches, it needs to check whether the database exists. If the database does not exist, the app should copy it from the app bundle using the [`Database.copy(File path, String name, DatabaseConfiguration config)`](http://docs.couchbase.com/mobile/2.0/couchbase-lite-java/db022/com/couchbase/lite/Database.html#copy-java.io.File-java.lang.String-com.couchbase.lite.DatabaseConfiguration-) method as shown below. let config = new DatabaseConfiguration(getApplicationContext());ZipUtils.unzip( getAsset('replacedb/android200-sqlite.cblite2.zip'), getApplicationContext().getFilesDir(),);let path = new File(getApplicationContext().getFilesDir(), 'android-sqlite');try { Database.copy(path, 'travel-sample', config);} catch (e) { console.log('Could not load pre-built database');} Copy Document[#](https://ionic.io/docs/couchbase-lite/usage#document "Direct link to heading") ------------------------------------------------------------------------------------------ In Couchbase Lite, a document’s body takes the form of a JSON object — a collection of key/value pairs where the values can be different types of data such as numbers, strings, arrays or even nested objects. Every document is identified by a document ID, which can be automatically generated (as a UUID) or specified programmatically; the only constraints are that it must be unique within the database, and it can’t be changed. ### Initializers[#](https://ionic.io/docs/couchbase-lite/usage#initializers "Direct link to heading") The following methods/initializers can be used: The `MutableDocument()` initializer can be used to create a new document where the document ID is randomly generated by the database. The `MutableDocument(withID: string)` initializer can be used to create a new document with a specific ID. The `database.getDocument(id: string)` method can be used to get a document. If it doesn’t exist in the database, it will return `null`. This method can be used to check if a document with a given ID already exists in the database. The following code example creates a document and persists it to the database: let newTask = new MutableDocument();newTask.setString('type', 'task');newTask.setString('owner', 'todo');newTask.setDate('createdAt', new Date());try { database.save(newTask);} catch (e) { console.log(e.toString());} Copy Changes to the document are persisted to the database when the `save` method is called. ### Typed Accessors[#](https://ionic.io/docs/couchbase-lite/usage#typed-accessors "Direct link to heading") The `Document` class offers a set of `property accessors` for various scalar types, including boolean, integers, floating-point and strings. These accessors take care of converting to/from JSON encoding, and make sure you get the type you’re expecting. In addition, as a convenience we offer `Date` accessors. Dates are a common data type, but JSON doesn’t natively support them, so the convention is to store them as strings in ISO-8601 format. The following example sets the date on the `createdAt` property and reads it back using the `document.getDate(String key)` accessor method. newTask.setValue('createdAt', new Date());let date = newTask.getDate('createdAt'); Copy If the property doesn’t exist in the document it will return the default value for that getter method (0 for `getInt`, 0.0 for `getFloat` etc.). ### Batch Operations[#](https://ionic.io/docs/couchbase-lite/usage#batch-operations "Direct link to heading") If you need to make multiple changes to a database at once, it’s faster to group them together. The following example persists a few documents in batch: await this.database.inBatch(() => { for (let sdk of sdkDataToLoad) { let doc = new MutableDocument() .setNumber('version', sdk.version) .setString('type', sdk.type) .setString('company', sdk.company); this.database.save(doc); }}); Copy At the **local** level this operation is still transactional: no other `Database` instances, including ones managed by the replicator can make changes during the execution of the block, and other instances will not see partial changes. But Couchbase Mobile is a distributed system, and due to the way replication works, there’s no guarantee that Sync Gateway or other devices will receive your changes all at once. Blobs[#](https://ionic.io/docs/couchbase-lite/usage#blobs "Direct link to heading") ------------------------------------------------------------------------------------ Used to store large data, such as images. The following code example adds a blob to the document under the `avatar` property. public async saveImageBlob() { // Get a reference to a file - various ways to do so let filepath = getAsset("avatar.jpg"); try { // Ionic Native File plugin let fileEntry = await this.file.resolveLocalFilesystemUrl(filepath) as any; fileEntry.file((file) => { const fileReader = new FileReader(); fileReader.onloadend = () => { let blob = new Blob("image/jpeg", fileReader.result as ArrayBuffer); newTask.setBlob("avatar", blob); database.save(newTask); } fileReader.readAsArrayBuffer(file); } } catch (e) { console.log(e.toString()); }} // Retrieve image blob then convert to base64 formatpublic getImageAsBase64() { return new Promise((resolve, reject) => { this.savedDoc.getBlobContent("avatar", this.database).then((docBlob) => { var bytes = new Uint8Array(docBlob); var blob = new window.Blob([bytes.buffer], { type: "image/jpeg"}); var reader = new FileReader(); reader.onloadend = () => { resolve(reader.result); }; reader.readAsDataURL(blob); }); });} // Alternatively, retrieve blog image then convert to objectURLpublic async getImageUsingObjectUrl() { let docBlob = await this.savedDoc.getBlobContent("test", this.database); let arrayBufferView = new Uint8Array(docBlob); let blob = new window.Blob([ arrayBufferView.buffer ], { type: "image/jpeg"}); let objectUrl = window.URL.createObjectURL(blob); return this.sanitizer.bypassSecurityTrustUrl(objectUrl);} Copy The `Blob` API lets you access the contents as in-memory data (a `Data` object) or as a `InputStream`. It also supports an optional `type` property that by convention stores the MIME type of the contents. In the example above, "image/jpeg" is the MIME type and "avatar" is the key which references that `Blob`. That key can be used to retrieve the `Blob` object at a later time. When a document is synchronized, the Couchbase Lite replicator will add an `_attachments` dictionary to the document’s properties if it contains a blob. A random access name will be generated for each `Blob` which is different to the "avatar" key that was used in the example above. A blob also has properties such as `"digest"` (a SHA-1 digest of the data), `"length"` (the length in bytes), and optionally `"content_type"` (the MIME type). The data is not stored in the document, but in a separate content-addressable store, indexed by the digest. Query[#](https://ionic.io/docs/couchbase-lite/usage#query "Direct link to heading") ------------------------------------------------------------------------------------ Database queries are based on expressions, of the form "return **from documents where** , ordered by \_\_", with semantics based on Couchbase’s N1QL query language. There are several parts to specifying a query: * SELECT: specifies the projection, which is the part of the document that is to be returned. * FROM: specifies the database to query the documents from. * JOIN: specifies the matching criteria in which to join multiple documents. * WHERE: specifies the query criteria that the result must satisfy. * GROUP BY: specifies the query criteria to group rows by. * ORDER BY: specifies the query criteria to sort the rows in the result. ### SELECT statement[#](https://ionic.io/docs/couchbase-lite/usage#select-statement "Direct link to heading") With the SELECT statement, you can query and manipulate JSON data. With projections, you retrieve just the fields that you need and not the entire document. A `SelectResult` represents a single return value of the query statement. You can specify a comma separated list of `SelectResult` expressions in the select statement of your query. For instance, the following select statement queries for the document `_id` as well as the `type` and `name` properties of all documents in the database. In the query result, we print the `_id` and `name` properties of each row using the property name getter method. { "_id": "hotel123", "type": "hotel", "name": "Apple Droid"} Copy let query = QueryBuilder.select( SelectResult.expression(Meta.id), SelectResult.property('name'), SelectResult.property('type'),) .from(DataSource.database(database)) .where(Expression.property('type').equalTo(Expression.string('hotel'))) .orderBy(Ordering.expression(Meta.id)); try { const resultSet = await(await query.execute()).allResults(); for (let result of resultSet) { console.log( 'Sample', String.format('hotel id -> %s', result.getString('id')), ); console.log( 'Sample', String.format('hotel name -> %s', result.getString('name')), ); }} catch (e) { Log.e('Sample', e.getLocalizedMessage());} Copy The `SelectResult.all()` method can be used to query all the properties of a document. In this case, the document in the result is embedded in a dictionary where the key is the database name. The following snippet shows the same query using `SelectResult.all()` and the result in JSON. let query = QueryBuilder.select(SelectResult.all()) .from(DataSource.database(database)) .where(Expression.property('type').equalTo(Expression.string('airline'))); const results = await(await query.execute()).allResults(); for (var key in results) { // SelectResult.all() returns all properties, but puts them into this JSON format: // [ { "*": { version: "2.0", type: "SDK", company: "Ionic" } } ] // Couchbase can query multiple databases at once, so "*" represents just this single database. let singleResult = results[key]['*']; // do something with the data} Copy [ { "*": { "callsign": "MILE-AIR", "country": "United States", "iata": "Q5", "icao": "MLA", "id": 10, "name": "40-Mile Air", "type": "airline" } }, { "*": { "callsign": "TXW", "country": "United States", "iata": "TQ", "icao": "TXW", "id": 10123, "name": "Texas Wings", "type": "airline" } }] Copy #### Retrieve nested document objects[#](https://ionic.io/docs/couchbase-lite/usage#retrieve-nested-document-objects "Direct link to heading") { "_id": "airport123", "type": "airport", "country": "United States", "geo": { "altitude": 456 }, "tz": "America/Anchorage"} Copy In the above example, access nested objects like `altitude` using periods (`geo.altitude`): let query = QueryBuilder.select(SelectResult.property('geo.altitude')).from( DataSource.database(database),); Copy #### Retrieve All Unique Values for One Column[#](https://ionic.io/docs/couchbase-lite/usage#retrieve-all-unique-values-for-one-column "Direct link to heading") Retrieve all unique values in the database for one specific column of data. Useful for populating [dropdown controls](https://ionicframework.com/docs/api/select) as part of a search interface, for example. // Find all unique Hotel names, for example// documentPropertyName = "hotel"public async getAllUniqueValues(documentPropertyName: string) { const query = QueryBuilder.selectDistinct( SelectResult.property(documentPropertyName)) .from(DataSource.database(this.database)) .orderBy(Ordering.property(documentPropertyName).ascending()); const results = await (await query.execute()).allResults(); return results.map(x => x[documentPropertyName]);} Copy ### WHERE Statement[#](https://ionic.io/docs/couchbase-lite/usage#where-statement "Direct link to heading") Similar to SQL, you can use the where clause to filter the documents to be returned as part of the query. The select statement takes in an `Expression`. You can chain any number of Expressions in order to implement sophisticated filtering capabilities. #### Comparison[#](https://ionic.io/docs/couchbase-lite/usage#comparison "Direct link to heading") The [comparison operators](http://docs.couchbase.com/mobile/2.0/couchbase-lite-java/db022/com/couchbase/lite/Expression.html) can be used in the WHERE statement to specify on which property to match documents. In the example below, we use the `equalTo` operator to query documents where the `type` property equals "hotel". { "_id": "hotel123", "type": "hotel", "name": "Apple Droid"} Copy let query = QueryBuilder.select(SelectResult.all()) .from(DataSource.database(database)) .where(Expression.property('type').equalTo(Expression.string('hotel'))) .limit(Expression.intValue(10));let rs = await(await query.execute()).allResults();for (let result of rs) { let all = result.getDictionary(DATABASE_NAME); console.log('Sample', String.format('name -> %s', all.getString('name'))); console.log('Sample', String.format('type -> %s', all.getString('type')));} Copy #### Collection Operators[#](https://ionic.io/docs/couchbase-lite/usage#collection-operators "Direct link to heading") [Collection operators](http://docs.couchbase.com/mobile/2.0/couchbase-lite-java/db022/com/couchbase/lite/ArrayFunction.html) are useful to check if a given value is present in an array. ##### CONTAINS Operator[#](https://ionic.io/docs/couchbase-lite/usage#contains-operator "Direct link to heading") The following example uses the `Function.arrayContains` to find documents whose `public_likes` array property contain a value equal to "Armani Langworth". { "_id": "hotel123", "name": "Apple Droid", "public_likes": ["Armani Langworth", "Elfrieda Gutkowski", "Maureen Ruecker"]} Copy let query = QueryBuilder.select( SelectResult.expression(Meta.id), SelectResult.property('name'), SelectResult.property('public_likes'),) .from(DataSource.database(database)) .where( Expression.property('type') .equalTo(Expression.string('hotel')) .and( ArrayFunction.contains( Expression.property('public_likes'), Expression.string('Armani Langworth'), ), ), );let rs = await(await query.execute()).allResults();for (let result of rs) console.log( 'Sample', String.format( 'public_likes -> %s', result.getArray('public_likes').toList(), ), ); Copy #### IN Operator[#](https://ionic.io/docs/couchbase-lite/usage#in-operator "Direct link to heading") The `IN` operator is useful when you need to explicitly list out the values to test against. The following example looks for documents whose `first`, `last` or `username` property value equals "Armani". let values = new Expression[] { Expression.property("first"), Expression.property("last"), Expression.property("username")}; let query = QueryBuilder.select(SelectResult.all()) .from(DataSource.database(database)) .where(Expression.string("Armani").in(values)); Copy #### Like Operator[#](https://ionic.io/docs/couchbase-lite/usage#like-operator "Direct link to heading") The [`like`](http://docs.couchbase.com/mobile/2.0/couchbase-lite-java/db022/com/couchbase/lite/Expression.html#like-com.couchbase.lite.Expression-) operator can be used for string matching. It is recommended to use the `like` operator for case insensitive matches and the `regex` operator (see below) for case sensitive matches. In the example below, we are looking for documents of type `landmark` where the name property exactly matches the string "Royal engineers museum". Note that since `like` does a case insensitive match, the following query will return "landmark" type documents with name matching "Royal Engineers Museum", "royal engineers museum", "ROYAL ENGINEERS MUSEUM" and so on. let query = QueryBuilder.select( SelectResult.expression(Meta.id), SelectResult.property('country'), SelectResult.property('name'),) .from(DataSource.database(database)) .where( Expression.property('type') .equalTo(Expression.string('landmark')) .and( Expression.property('name').like( Expression.string('Royal Engineers Museum'), ), ), );let rs = await(await query.execute()).allResults();for (let result of rs) { console.log('Sample', `name -> ${result.getString('name')}`);} Copy #### Wildcard Match[#](https://ionic.io/docs/couchbase-lite/usage#wildcard-match "Direct link to heading") We can use `%` sign within a `like` expression to do a wildcard match against zero or more characters. Using wildcards allows you to have some fuzziness in your search string. In the example below, we are looking for documents of `type` "landmark" where the name property matches any string that begins with "eng" followed by zero or more characters, the letter "e", followed by zero or more characters. The following query will return "landmark" type documents with name matching "Engineers", "engine", "english egg" , "England Eagle" and so on. Notice that the matches may span word boundaries. let query = QueryBuilder.select( SelectResult.expression(Meta.id), SelectResult.property('country'), SelectResult.property('name'),) .from(DataSource.database(database)) .where( Expression.property('type') .equalTo(Expression.string('landmark')) .and(Expression.property('name').like(Expression.string('Eng%e%'))), );let rs = await(await query.execute()).allResults();for (let result of rs) console.log('Sample', `name -> ${result.getString('name')}`); Copy A reusable function can easily be created that formats an expression, usable in a Where clause, for fuzzy searching: // Specify a reserved wordprivate EMPTY_PLACEHOLDER = "Any"; private formatWildcardExpression(propValue) { return Expression.string( `%${propValue === this.EMPTY_PLACEHOLDER ? "" : propValue}%`);} Copy // snippet:.where(Expression.property("office").like( this.formatWildcardExpression(office)) Copy #### Wildcard Character Match[#](https://ionic.io/docs/couchbase-lite/usage#wildcard-character-match "Direct link to heading") We can use `_` sign within a like expression to do a wildcard match against a single character. In the example below, we are looking for documents of type "landmark" where the `name` property matches any string that begins with "eng" followed by exactly 4 wildcard characters and ending in the letter "r". The following query will return "landmark" `type` documents with the `name` matching "Engineer", "engineer" and so on. let query = QueryBuilder.select( SelectResult.expression(Meta.id), SelectResult.property('country'), SelectResult.property('name'),) .from(DataSource.database(database)) .where( Expression.property('type') .equalTo(Expression.string('landmark')) .and(Expression.property('name').like(Expression.string('Eng____r'))), );let rs = await(await query.execute()).allResults();for (let result of rs) console.log('Sample', `name -> ${result.getString('name')}`); Copy #### Regex Operator[#](https://ionic.io/docs/couchbase-lite/usage#regex-operator "Direct link to heading") The `regex` expression can be used for case sensitive matches. Similar to wildcard `like` expressions, `regex` expressions based pattern matching allow you to have some fuzziness in your search string. In the example below, we are looking for documents of `type` "landmark" where the name property matches any string (on word boundaries) that begins with "eng" followed by exactly 4 wildcard characters and ending in the letter "r". The following query will return "landmark" type documents with name matching "Engine", "engine" and so on. Note that the `\b` specifies that the match must occur on word boundaries. let query = QueryBuilder.select( SelectResult.expression(Meta.id), SelectResult.property('country'), SelectResult.property('name'),) .from(DataSource.database(database)) .where( Expression.property('type') .equalTo(Expression.string('landmark')) .and( Expression.property('name').regex(Expression.string('\\bEng.*r\\b')), ), );let rs = await(await query.execute()).allResults();for (let result of rs) console.log('Sample', `name -> ${result.getString('name')}`); Copy ### JOIN Statement[#](https://ionic.io/docs/couchbase-lite/usage#join-statement "Direct link to heading") The JOIN clause enables you to create new input objects by combining two or more source objects. The following example uses a JOIN clause to find the airline details which have routes that start from RIX. This example JOINS the document of type "route" with documents of type "airline" using the document ID (`_id`) on the "airline" document and `airlineid` on the "route" document. let query = QueryBuilder.select( SelectResult.expression(Expression.property('name').from('airline')), SelectResult.expression(Expression.property('callsign').from('airline')), SelectResult.expression( Expression.property('destinationairport').from('route'), ), SelectResult.expression(Expression.property('stops').from('route')), SelectResult.expression(Expression.property('airline').from('route')),) .from(DataSource.database(database).as('airline')) .join( Join.join(DataSource.database(database).as('route')).on( Meta.id .from('airline') .equalTo(Expression.property('airlineid').from('route')), ), ) .where( Expression.property('type') .from('route') .equalTo(Expression.string('route')) .and( Expression.property('type') .from('airline') .equalTo(Expression.string('airline')), ) .and( Expression.property('sourceairport') .from('route') .equalTo(Expression.string('RIX')), ), );let rs = await(await query.execute()).allResults();for (let result of rs) console.log('Sample', String.format('%s', result.toMap().toString())); Copy ### GROUP BY statement[#](https://ionic.io/docs/couchbase-lite/usage#group-by-statement "Direct link to heading") You can perform further processing on the data in your result set before the final projection is generated. The following example looks for the number of airports at an altitude of 300 ft or higher and groups the results by country and timezone. { "_id": "airport123", "type": "airport", "country": "United States", "geo": { "alt": 456 }, "tz": "America/Anchorage"} Copy let query = QueryBuilder.select( SelectResult.expression(Function.count(Expression.string('*'))), SelectResult.property('country'), SelectResult.property('tz'),) .from(DataSource.database(database)) .where( Expression.property('type') .equalTo(Expression.string('airport')) .and( Expression.property('geo.alt').greaterThanOrEqualTo( Expression.intValue(300), ), ), ) .groupBy(Expression.property('country'), Expression.property('tz')) .orderBy( Ordering.expression(Function.count(Expression.string('*'))).descending(), );let rs = await(await query.execute()).allResults();for (let result of rs) console.log( 'Sample', String.format( 'There are %d airports on the %s timezone located in %s and above 300ft', result.getInt('$1'), result.getString('tz'), result.getString('country'), ), ); Copy There are 138 airports on the Europe/Paris timezone located in France and above 300 ftThere are 29 airports on the Europe/London timezone located in United Kingdom and above 300 ftThere are 50 airports on the America/Anchorage timezone located in United States and above 300 ftThere are 279 airports on the America/Chicago timezone located in United States and above 300 ftThere are 123 airports on the America/Denver timezone located in United States and above 300 ft Copy ### ORDER BY statement[#](https://ionic.io/docs/couchbase-lite/usage#order-by-statement "Direct link to heading") It is possible to sort the results of a query based on a given expression result. The example below returns documents of type equal to "hotel" sorted in ascending order by the value of the title property. let query = QueryBuilder.select( SelectResult.expression(Meta.id), SelectResult.property('name'),) .from(DataSource.database(database)) .where(Expression.property('type').equalTo(Expression.string('hotel'))) .orderBy(Ordering.property('name').ascending()) .limit(Expression.intValue(10));let rs = await(await query.execute()).allResults();for (let result of rs) console.log('Sample', result.toMap()); Copy AberdyfiAchiltibuieAltrinchamAmblesideAnnanArdècheArmaghAvignon Copy Indexing[#](https://ionic.io/docs/couchbase-lite/usage#indexing "Direct link to heading") ------------------------------------------------------------------------------------------ Creating indexes can speed up the performance of queries. While indexes make queries faster, they also make writes slightly slower, and the Couchbase Lite database file slightly larger. As such, it is best to only create indexes when you need to optimize a specific case for better query performance. The following example creates a new index for the `type` and `name` properties. { "_id": "hotel123", "type": "hotel", "name": "Apple Droid"} Copy database.createIndex( 'TypeNameIndex', IndexBuilder.valueIndex( ValueIndexItem.property('type'), ValueIndexItem.property('name'), ),); Copy If there are multiple expressions, the first one will be the primary key, the second the secondary key, etc. Note: Every index has to be updated whenever a document is updated, so too many indexes can hurt performance. Thus, good performance depends on designing and creating the _right_ indexes to go along with your queries. Full-Text Search[#](https://ionic.io/docs/couchbase-lite/usage#full-text-search "Direct link to heading") ---------------------------------------------------------------------------------------------------------- To run a full-text search (FTS) query, you must have created a full-text index on the expression being matched. Unlike regular queries, the index is not optional. The following example inserts documents and creates an FTS index on the `name` property. database.createIndex( 'nameFTSIndex', IndexBuilder.fullTextIndex(FullTextIndexItem.property('name')).ignoreAccents( false, ),); Copy Multiple properties to index can be specified in the index creation method. With the index created, an FTS query on the property that is being indexed can be constructed and ran. The full-text search criteria is defined as a `FullTextExpression`. The left-hand side is the full-text index to use and the right-hand side is the pattern to match. let whereClause = FullTextExpression.index('nameFTSIndex').match('buy');let ftsQuery = QueryBuilder.select(SelectResult.expression(Meta.id)) .from(DataSource.database(database)) .where(whereClause);let ftsQueryResult = await(await ftsQuery.execute()).allResults();for (let result of ftsQueryResult) console.log(String.format('document properties %s', result.getString(0))); Copy In the example above, the pattern to match is a word, the full-text search query matches all documents that contain the word "buy" in the value of the `doc.name` property. Full-text search is supported in the following languages: danish, dutch, english, finnish, french, german, hungarian, italian, norwegian, portuguese, romanian, russian, spanish, swedish and turkish. The pattern to match can also be in the following forms: * _prefix queries:_ the query expression used to search for a term prefix is the prefix itself with a "\*" character appended to it. For example: "'lin*'"-- Query for all documents containing a term with the prefix "lin". This will match-- all documents that contain "linux", but also those that contain terms "linear",--"linker", "linguistic" and so on. Copy * _overriding the property name that is being indexed:_ Normally, a token or token prefix query is matched against the document property specified as the left-hand side of the `match` operator. This may be overridden by specifying a property name followed by a ":" character before a basic term query. There may be space between the ":" and the term to query for, but not between the property name and the ":" character. For example: 'title:linux problems'-- Query the database for documents for which the term "linux" appears in-- the document title, and the term "problems" appears in either the title-- or body of the document. Copy * _phrase queries:_ a phrase query is a query that retrieves all documents that contain a nominated set of terms or term prefixes in a specified order with no intervening tokens. Phrase queries are specified by enclosing a space separated sequence of terms or term prefixes in double quotes ("). For example: "'"linux applications"'"-- Query for all documents that contain the phrase "linux applications". Copy * _NEAR queries:_ A NEAR query is a query that returns documents that contain a two or more nominated terms or phrases within a specified proximity of each other (by default with 10 or less intervening terms). A NEAR query is specified by putting the keyword "NEAR" between two phrase, token or token prefix queries. To specify a proximity other than the default, an operator of the form "NEAR/" may be used, where is the maximum number of intervening terms allowed. For example: "'database NEAR/2 "replication"'"-- Search for a document that contains the phrase "replication" and the term-- "database" with not more than 2 terms separating the two. Copy * _AND, OR & NOT query operators:_ The enhanced query syntax supports the AND, OR and NOT binary set operators. Each of the two operands to an operator may be a basic FTS query, or the result of another AND, OR or NOT set operation. Operators must be entered using capital letters. Otherwise, they are interpreted as basic term queries instead of set operators. For example: 'couchbase AND database'-- Return the set of documents that contain the term "couchbase", and the-- term "database". This query will return the document with docid 3 only. Copy When using the enhanced query syntax, parenthesis may be used to specify the precedence of the various operators. For example: '("couchbase database" OR "sqlite library") AND linux'-- Query for the set of documents that contains the term "linux", and at least-- one of the phrases "couchbase database" and "sqlite library". Copy ### Ordering results[#](https://ionic.io/docs/couchbase-lite/usage#ordering-results "Direct link to heading") It’s very common to sort full-text results in descending order of relevance. This can be a very difficult heuristic to define, but Couchbase Lite comes with a ranking function you can use. In the `OrderBy` array, use a string of the form `Rank(X)`, where `X` is the property or expression being searched, to represent the ranking of the result. Replication[#](https://ionic.io/docs/couchbase-lite/usage#replication "Direct link to heading") ------------------------------------------------------------------------------------------------ Couchbase Mobile 2.0 uses a new replication protocol based on WebSockets. ### Compatibility[#](https://ionic.io/docs/couchbase-lite/usage#compatibility "Direct link to heading") The new protocol is **incompatible** with CouchDB-based databases. And since Couchbase Lite 2 only supports the new protocol, you will need to run a version of Sync Gateway that supports it. To use this protocol with Couchbase Lite 2.0, the replication URL should specify WebSockets as the URL scheme (see the "Starting a Replication" section below). Mobile clients using Couchbase Lite 1.x can continue to use **http** as the URL scheme. Sync Gateway 2.0 will automatically use the 1.x replication protocol when a Couchbase Lite 1.x client connects through http://localhost:4984/db and the 2.0 replication protocol when a Couchbase Lite 2.0 client connects through ws://localhost:4984/db. ### Starting Sync Gateway[#](https://ionic.io/docs/couchbase-lite/usage#starting-sync-gateway "Direct link to heading") [Download Sync Gateway](https://www.couchbase.com/downloads) and start it from the command line with the configuration file created above. ~/Downloads/couchbase-sync-gateway/bin/sync_gateway Copy For platform specific installation instructions, refer to the Sync Gateway [installation guide](https://developer.couchbase.com/documentation/mobile/current/installation/sync-gateway/index.html) . ### Starting a Replication[#](https://ionic.io/docs/couchbase-lite/usage#starting-a-replication "Direct link to heading") Replication can be bidirectional, this means you can start a `push`/`pull` replication with a single instance. The replication’s parameters can be specified through the [`ReplicatorConfiguration`](http://docs.couchbase.com/mobile/2.0/couchbase-lite-java/db022/index.html?com/couchbase/lite/ReplicatorConfiguration.html) object; for example, if you wish to start a `push` only or `pull` only replication. The following example creates a `pull` replication with Sync Gateway. class MyClass { database: Database; replicator: Replicator; startReplication() { let endpoint = new URLEndpoint('ws://10.0.2.2:4984/db'); let config = new ReplicatorConfiguration(this.database, endpoint); config.setReplicatorType(ReplicatorConfiguration.ReplicatorType.PULL); this.replicator = new Replicator(config); return this.replicator.start(); }} Copy A replication is an asynchronous operation. To keep a reference to the `replicator` object, you can set it as an instance property. To verify that documents have been replicated, you can: * Monitor the Sync Gateway sequence number returned by the database endpoint (`GET /{db}/`). The sequence number increments for every change that happens on the Sync Gateway database. * Query a document by ID on the Sync Gateway REST API (`GET /{db}/{id}`). * Query a document from the Query Workbench on the Couchbase Server Console. Couchbase Lite 2.0 uses WebSockets as the communication protocol to transmit data. Some load balancers are not configured for WebSocket connections by default (NGINX for example); so it might be necessary to explicitly enable them in the load balancer’s configuration (see [Load Balancers](https://developer.couchbase.com/documentation/mobile/current/guides/sync-gateway/nginx/index.html) ). By default, the WebSocket protocol uses compression to optimize for speed and bandwidth utilization. The level of compression is set on Sync Gateway and can be tuned in the configuration file (`replicator_compression`). #### Replication Ordering[#](https://ionic.io/docs/couchbase-lite/usage#replication-ordering "Direct link to heading") To optimize for speed, the replication protocol doesn’t guarantee that documents will be received in a particular order. So we don’t recommend to rely on that when using the replication or database change listeners for example. ### Troubleshooting[#](https://ionic.io/docs/couchbase-lite/usage#troubleshooting "Direct link to heading") As always, when there is a problem with replication, logging is your friend. The following example increases the log output for activity related to replication with Sync Gateway. `Database.setLogLevel(LogDomain.REPLICATOR, LogLevel.VERBOSE);` ### Replication Status[#](https://ionic.io/docs/couchbase-lite/usage#replication-status "Direct link to heading") The `replication.Status.Activity` property can be used to check the status of a replication. For example, when the replication is actively transferring data and when it has stopped. replication.addChangeListener(change => { if (change.activityLevel == Replicator.ActivityLevel.STOPPED) console.log('Replication stopped');}); Copy The following table lists the different activity levels in the API and the meaning of each one. | State | Meaning | | --- | --- | | `STOPPED` | The replication is finished or hit a fatal error. | | `OFFLINE` | The replicator is offline as the remote host is unreachable. | | `CONNECTING` | The replicator is connecting to the remote host. | | `IDLE` | The replication caught up with all the changes available from the server. The `IDLE` state is only used in continuous replications. | | `BUSY` | The replication is actively transferring data. | ### Handling Network Errors[#](https://ionic.io/docs/couchbase-lite/usage#handling-network-errors "Direct link to heading") If an error occurs, the replication status will be updated with an `Error` which follows the standard HTTP error codes. The following example monitors the replication for errors and logs the error code to the console. replication.addChangeListener(change => { let error = change.error; if (error != null) console.log('Error code::', error.getCode());});replication.start(); Copy When a permanent error occurs (i.e., `404`: not found, `401`: unauthorized), the replicator (continuous or one-shot) will stop permanently. If the error is temporary (i.e., waiting for the network to recover), a continuous replication will retry to connect indefinitely and if the replication is one-shot it will retry for a limited number of times. The following error codes are considered temporary by the Couchbase Lite replicator and thus will trigger a connection retry. * `408`: Request Timeout * `429`: Too Many Requests * `500`: Internal Server Error * `502`: Bad Gateway * `503`: Service Unavailable * `504`: Gateway Timeout * `1001`: DNS resolution error ### Custom Headers[#](https://ionic.io/docs/couchbase-lite/usage#custom-headers "Direct link to heading") Custom headers can be set on the configuration object. And the replicator will send those header(s) in every request. As an example, this feature can be useful to pass additional credentials when there is an authentication or authorization step being done by a proxy server (between Couchbase Lite and Sync Gateway). let config = new ReplicatorConfiguration(database, endpoint);config.setHeaders({ CustomHeaderName: 'Value',}); Copy Handling Conflicts[#](https://ionic.io/docs/couchbase-lite/usage#handling-conflicts "Direct link to heading") -------------------------------------------------------------------------------------------------------------- In Couchbase Lite 2.0, document conflicts are automatically resolved. This functionality aims to simplify the default behavior of conflict handling and save disk space (conflicting revisions will no longer be stored in the database). There are 2 different `save` method signatures to specify how to handle a possible conflict: * `save(document: MutableDocument)`: when concurrent writes to an individual record occur, the conflict is automatically resolved and only one non-conflicting document update is stored in the database. The Last-Write-Win (LWW) algorithm is used to pick the winning revision. * `save(document: MutableDocument, concurrencyControl: ConcurrencyControl)`: attempts to save the document with a concurrency control. The concurrency control parameter has two possible values: - `lastWriteWins`: The last operation wins if there is a conflict. - `failOnConflict`: The operation will fail if there is a conflict. Similarly to the save operation, the delete operation also has two method signatures to specify how to handle a possible conflict: * `delete(document: Document)`: The last write will win if there is a conflict. * `delete(document: Document, concurrencyControl: ConcurrencyControl)`: attemps to delete the document with a concurrency control. The concurrency control parameter has two possible values: - `lastWriteWins`: The last operation wins if there is a conflict. - `failOnConflict`: The operation will fail if there is a conflict. Database Replicas[#](https://ionic.io/docs/couchbase-lite/usage#database-replicas "Direct link to heading") ------------------------------------------------------------------------------------------------------------ Database replicas is available in the **Ionic Native** only ([](https://www.couchbase.com/downloads) [https://www.couchbase.com/downloads](https://www.couchbase.com/downloads) ). Starting in Couchbase Lite 2.0, replication between two local databases is now supported. It allows a Couchbase Lite replicator to store data on secondary storage. It would be especially useful in scenarios where a user’s device is damaged and the data needs to be moved to a different device. Note that the code below won’t compile if you’re running the **Community Plugin** of Couchbase Lite. * [Database](https://ionic.io/docs/couchbase-lite/usage#database) * [New Database](https://ionic.io/docs/couchbase-lite/usage#new-database) * [Loading a pre-built Database](https://ionic.io/docs/couchbase-lite/usage#loading-a-pre-built-database) * [Document](https://ionic.io/docs/couchbase-lite/usage#document) * [Initializers](https://ionic.io/docs/couchbase-lite/usage#initializers) * [Typed Accessors](https://ionic.io/docs/couchbase-lite/usage#typed-accessors) * [Batch Operations](https://ionic.io/docs/couchbase-lite/usage#batch-operations) * [Blobs](https://ionic.io/docs/couchbase-lite/usage#blobs) * [Query](https://ionic.io/docs/couchbase-lite/usage#query) * [SELECT statement](https://ionic.io/docs/couchbase-lite/usage#select-statement) * [WHERE Statement](https://ionic.io/docs/couchbase-lite/usage#where-statement) * [JOIN Statement](https://ionic.io/docs/couchbase-lite/usage#join-statement) * [GROUP BY statement](https://ionic.io/docs/couchbase-lite/usage#group-by-statement) * [ORDER BY statement](https://ionic.io/docs/couchbase-lite/usage#order-by-statement) * [Indexing](https://ionic.io/docs/couchbase-lite/usage#indexing) * [Full-Text Search](https://ionic.io/docs/couchbase-lite/usage#full-text-search) * [Ordering results](https://ionic.io/docs/couchbase-lite/usage#ordering-results) * [Replication](https://ionic.io/docs/couchbase-lite/usage#replication) * [Compatibility](https://ionic.io/docs/couchbase-lite/usage#compatibility) * [Starting Sync Gateway](https://ionic.io/docs/couchbase-lite/usage#starting-sync-gateway) * [Starting a Replication](https://ionic.io/docs/couchbase-lite/usage#starting-a-replication) * [Troubleshooting](https://ionic.io/docs/couchbase-lite/usage#troubleshooting) * [Replication Status](https://ionic.io/docs/couchbase-lite/usage#replication-status) * [Handling Network Errors](https://ionic.io/docs/couchbase-lite/usage#handling-network-errors) * [Custom Headers](https://ionic.io/docs/couchbase-lite/usage#custom-headers) * [Handling Conflicts](https://ionic.io/docs/couchbase-lite/usage#handling-conflicts) * [Database Replicas](https://ionic.io/docs/couchbase-lite/usage#database-replicas) --- # Secure Storage - Key Value API - Secure Storage [Skip to main content](https://ionic.io/docs/secure-storage/key-value#__docusaurus_skipToContent_fallback) On this page While Ionic Secure Storage provides a powerful SQLite-backed data store, it also has support for key/value functionality for simpler use cases or when data will fit in memory and querying can be done in JavaScript. Key/value support is provided by the `KeyValueStorage` utility class which provides a generic storage API, abstracting away storage engine details and providing a simple API with low overhead. Support for encryption is available when running on iOS and Android only. Installation[​](https://ionic.io/docs/secure-storage/key-value#installation "Direct link to Installation") ----------------------------------------------------------------------------------------------------------- npm install @ionic-enterprise/secure-storage Usage[​](https://ionic.io/docs/secure-storage/key-value#usage "Direct link to Usage") -------------------------------------------------------------------------------------- ### With React, Vue, Vanilla JavaScript[​](https://ionic.io/docs/secure-storage/key-value#with-react-vue-vanilla-javascript "Direct link to With React, Vue, Vanilla JavaScript") import { KeyValueStorage } from '@ionic-enterprise/secure-storage';const storage = new KeyValueStorage();await storage.create('key');await storage.set('name', 'Mr. Ionitron'); ### With Angular[​](https://ionic.io/docs/secure-storage/key-value#with-angular "Direct link to With Angular") First, edit your NgModule declaration in `src/app/app.module.ts` or in the module for the page you'll use the storage library in, and add `KeyValueStorage` as a provider: import { KeyValueStorage } from '@ionic-enterprise/secure-storage/ngx';@NgModule({ declarations: [ ... ], providers: [ ..., KeyValueStorage ], imports: [ ... ], // ...})export class AppModule { } Next, register `KeyValueStorage` in your component and provide an encryption key (view recommendations for [obtaining and securing an encryption key here](https://ionic.io/docs/secure-storage/encryption-key-management-with-identity-vault) ) and initialize the storage engine by calling `create('YOUR_ENCRYPTION_KEY_HERE')`. Once encryption has been enabled, all saved data will automatically be encrypted. import { Component, OnInit } from '@angular/core'; import { KeyValueStorage } from '@ionic-enterprise/secure-storage/ngx'; @Component({ ... }) export class MyPage implements OnInit { constructor(private storage: KeyValueStorage) { } async ngOnInit() { await this.storage.create('key'); } async setIt() { await this.storage.set('name', 'Mr. Ionitron'); } async getIt() { const name = await this.storage.get('name'); console.log(name); } } Should you ever lose or forget the key used in `create()` you can destroy the `KeyValueStorage` so you can start clean via the `destroyStorage()` function: ...// Angularawait this.storage.destroyStorage();// React, Vue, Vanillaawait storage.destroyStorage();... Contents -------- * [Installation](https://ionic.io/docs/secure-storage/key-value#installation) * [Usage](https://ionic.io/docs/secure-storage/key-value#usage) * [With React, Vue, Vanilla JavaScript](https://ionic.io/docs/secure-storage/key-value#with-react-vue-vanilla-javascript) * [With Angular](https://ionic.io/docs/secure-storage/key-value#with-angular) --- # Create a Tab-based App | Ionic Secure Solutions Starter [Skip to main content](https://ionic.io/docs/enterprise-starter/create#) With a bit of background on the solutions we will be using from the Ionic Platform for Enterprise, we will start by creating a tab-based application. Step-by-step instructions[#](https://ionic.io/docs/enterprise-starter/create#step-by-step-instructions "Direct link to heading") --------------------------------------------------------------------------------------------------------------------------------- ##### note The below instructions utilize the Ionic extension for Visual Studio Code. If you have not installed the Ionic extension already, you can do so [here](https://marketplace.visualstudio.com/items?itemName=ionic.ionic) . Follow these steps along with the video above: 1. Open Visual Studio Code (VSCode) and click on the [Ionic extension](https://marketplace.visualstudio.com/items?itemName=ionic.ionic) . * This will prompt you to create an empty folder within your file system to house the new app. ![](https://ionic.io/docs/enterprise-starter/assets/images/create-app-folder-9b3715e84592f5ac4cee6748bcde1c8c.png) 2. Choose a location for your application, then create and name the folder. ![](https://ionic.io/docs/enterprise-starter/assets/images/choose-app-folder-location-614ad2eea171c60917134506d7b02c40.png) ![](https://ionic.io/docs/enterprise-starter/assets/images/name-app-folder-66b04f7753cbe015bbab51e94a043f6d.png) 3. With the folder created, you can open up the Ionic extension in VSCode once more. It will prompt you to create an Angular, React, or Vue application using one of the starter templates. * In this demo we will choose the `tabs` starter under the `New Angular Project` section. ![](https://ionic.io/docs/enterprise-starter/assets/images/choose-app-template-d3219c79bd85acdcbef4e833af8fe29b.png) 4. After choosing your app template, you will then give the app a name and confirm. ![](https://ionic.io/docs/enterprise-starter/assets/images/name-the-app-b6e46d9fdeac67a415b246174324b2b9.png) 5. Once confirming the name of the app, the Ionic VSCode extension will take over to create your tab-based application! ![](https://ionic.io/docs/enterprise-starter/assets/images/app-creation-cli-49a59a2573912f63ee480073cc474065.png) 6. After the app is created, you can immediately run in on the web by clicking the `Web` option underneath the `Run` section. * The result will be a fresh new tabs-based application running in your browser. ![](https://ionic.io/docs/enterprise-starter/assets/images/fresh-tabs-app-ec671e068bc3630df0e47b6e368f4baf.png) Connect to Version Control[#](https://ionic.io/docs/enterprise-starter/create#connect-to-version-control "Direct link to heading") ----------------------------------------------------------------------------------------------------------------------------------- Now that we have an app created, it is important we manage the source code. In any Enterprise, this is common practice and you are likely familiar with the options at your disposal. Throughout the tutorial we will make reference to our version control, such as in the next step and when we reach the deployment step in our app development process. We utilize GitHub in this specific example. Before moving on to the next step, quickly connect your app's source code to your version control provider of choice. Next up[#](https://ionic.io/docs/enterprise-starter/create#next-up "Direct link to heading") --------------------------------------------------------------------------------------------- With the project created and connected to version control, now it is time to register your enterprise key. [Edit this page](https://github.com/ionic-team/ionic-enterprise-starter/tree/main/website/docs/create.md) * [Step-by-step instructions](https://ionic.io/docs/enterprise-starter/create#step-by-step-instructions) * [Connect to Version Control](https://ionic.io/docs/enterprise-starter/create#connect-to-version-control) * [Next up](https://ionic.io/docs/enterprise-starter/create#next-up) --- # Register Enterprise Key | Ionic Secure Solutions Starter [Skip to main content](https://ionic.io/docs/enterprise-starter/enterprise-key#) Previously, you went ahead and registered for an Enterprise product key which is now available in the [Ionic Hub](https://dashboard.ionicframework.com/) . We can work to assign that key to your newly created app. Import your App[#](https://ionic.io/docs/enterprise-starter/enterprise-key#import-your-app "Direct link to heading") --------------------------------------------------------------------------------------------------------------------- First, go to the `Apps` section of Ionic Hub and choose `Import existing app`. ![](https://ionic.io/docs/enterprise-starter/assets/images/import-existing-app-5582f05e4d3f681a3ab56cae71b369fb.png) This will walk you through connecting your newly created app via your app's git host. So, give the app a name, connect to your git host, and select your app's repository. Assign the Native Plugin Key[#](https://ionic.io/docs/enterprise-starter/enterprise-key#assign-the-native-plugin-key "Direct link to heading") ----------------------------------------------------------------------------------------------------------------------------------------------- Once your app exists within Ionic Hub, you can go back to the `Native Plugin Keys` section of the Ionic Hub. Under the `App` column of your key, you can select the `Assign to app` button. A popover will appear where you can choose your app that you just added to the hub! Connect Key and App[#](https://ionic.io/docs/enterprise-starter/enterprise-key#connect-key-and-app "Direct link to heading") ----------------------------------------------------------------------------------------------------------------------------- There are a few ways you can register your key with your app. One way is through the command line. The instructions for this process can be found [here](https://ionic.io/docs/supported-plugins/setup#install-tooling) . However, in this tutorial we'll approach it slightly differently. For starters, go back to VSCode where you have your app open. In the root folder of the app, create a new file called `.npmrc`. Inside of this new file you can add the following: @ionic-enterprise:registry=https://registry.ionicframework.com///registry.ionicframework.com/:_authToken=${ENT_NATIVE_KEY} Copy The `ENT_NATIVE_KEY` part represents the Enterprise Native Key in variable format that will be swapped in dynamically, and can be named however you'd like. Configure Local Development Environment[#](https://ionic.io/docs/enterprise-starter/enterprise-key#configure-local-development-environment "Direct link to heading") --------------------------------------------------------------------------------------------------------------------------------------------------------------------- With the app looking for a key, your computer's environment needs to fulfill that need. So, we will add what the app is looking for ... ### Mac[#](https://ionic.io/docs/enterprise-starter/enterprise-key#mac "Direct link to heading") Add the native key to a `.bashrc`, `.bash_profile`, or `.zshrc` file: export ENT_NATIVE_KEY="key_a17927..." Copy ### Windows[#](https://ionic.io/docs/enterprise-starter/enterprise-key#windows "Direct link to heading") Add the native key as an Environment Variable. Navigate to `System Properties -> Advanced -> Environment Variables`. Under "User variables for \[login name\]", add a new Variable (ENT\_NATIVE\_KEY) and Value (\[the native key\]). This is all done in an effort to keep your Enterprise Native Key truly private. This is also a useful setup when building an open-source app that may utilize an Enterprise Native Key as well. Later, to we'll need to revisit this Environment Variable concept when setting up app builds within [Appflow](https://ionic.io/appflow) . Next up[#](https://ionic.io/docs/enterprise-starter/enterprise-key#next-up "Direct link to heading") ----------------------------------------------------------------------------------------------------- Now that we have our key safely talking to the app, let's put it to use with [Auth Connect](https://ionic.io/products/auth-connect) ! [Edit this page](https://github.com/ionic-team/ionic-enterprise-starter/tree/main/website/docs/enterprise-key.md) * [Import your App](https://ionic.io/docs/enterprise-starter/enterprise-key#import-your-app) * [Assign the Native Plugin Key](https://ionic.io/docs/enterprise-starter/enterprise-key#assign-the-native-plugin-key) * [Connect Key and App](https://ionic.io/docs/enterprise-starter/enterprise-key#connect-key-and-app) * [Configure Local Development Environment](https://ionic.io/docs/enterprise-starter/enterprise-key#configure-local-development-environment) * [Mac](https://ionic.io/docs/enterprise-starter/enterprise-key#mac) * [Windows](https://ionic.io/docs/enterprise-starter/enterprise-key#windows) * [Next up](https://ionic.io/docs/enterprise-starter/enterprise-key#next-up) --- # Authentication Service Updates | Ionic Secure Solutions Starter [Skip to main content](https://ionic.io/docs/enterprise-starter/auth-service-updates#) Now that the application allows a user to login through a third-party authentication service and have their session data securely stored with added encryption, some final touches can be put on the `AuthenticationService` to round out it's functionality. Reconfigure Constructor[#](https://ionic.io/docs/enterprise-starter/auth-service-updates#reconfigure-constructor "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------------------------- With the `SessionVaultService` implemented, additional updates are required within the `AuthenticationService`. For starters, the `constructor()` needs to pass configuration updates to it's parent now that session vault is serving as the `tokenStorageProvider`. This means the `SessionVaultService` needs to be injected: src/app/services/authentication.service.ts ...import { SessionVaultService } from './session-vault.service'; ...export class AuthenticationService extends IonicAuth { constructor( private router: Router, private sessionVault: SessionVaultService ) { super({ ...(Capacitor.isNativePlatform() ? nativeAuthOptions : webAuthOptions), tokenStorageProvider: sessionVault.getVault(), }); }} Copy Override Super Class Logout[#](https://ionic.io/docs/enterprise-starter/auth-service-updates#override-super-class-logout "Direct link to heading") --------------------------------------------------------------------------------------------------------------------------------------------------- To ensure the user's data remains secured, it will also need to be deleted when the user logs out. Thus, the `AuthenticationService`'s super class' `logout()` function can be overridden with custom logic to also clear the `vault`: src/app/services/authentication.service.ts async logout() { await this.sessionVault.clear(); return await super.logout();} Copy Amend onLoginSuccess and onLogout[#](https://ionic.io/docs/enterprise-starter/auth-service-updates#amend-onloginsuccess-and-onlogout "Direct link to heading") --------------------------------------------------------------------------------------------------------------------------------------------------------------- With the session vault helper functions, we can now successfully update the vault's configuration when the user logs in and logs out. `onLoginSuccess` can now set the value within the session vault, update the unlock mode, and then do it's navigation: src/app/services/authentication.service.ts async onLoginSuccess(response) { await this.sessionVault.setValue('session', response); await this.sessionVault.initializeUnlockMode(); await this.router.navigate(['/']);} Copy Finally, with `onLogout`, we can tell the app where to go after the user logs out, as well as update the vault's configs to match the current state of the application. In our case, we will take them right back to the original `LoginPage`: src/app/services/authentication.service.ts async onLogout() { await this.sessionVault.setUnlockMode('NeverLock'); return await this.router.navigate(['login']);} Copy Next Up[#](https://ionic.io/docs/enterprise-starter/auth-service-updates#next-up "Direct link to heading") ----------------------------------------------------------------------------------------------------------- We have created a fully functioning enterprise-grade application! It is time to deploy the application using Ionic's mobile CI/CD platform, Appflow. [Edit this page](https://github.com/ionic-team/ionic-enterprise-starter/tree/main/website/docs/auth-service-updates.md) * [Reconfigure Constructor](https://ionic.io/docs/enterprise-starter/auth-service-updates#reconfigure-constructor) * [Override Super Class Logout](https://ionic.io/docs/enterprise-starter/auth-service-updates#override-super-class-logout) * [Amend onLoginSuccess and onLogout](https://ionic.io/docs/enterprise-starter/auth-service-updates#amend-onloginsuccess-and-onlogout) * [Next Up](https://ionic.io/docs/enterprise-starter/auth-service-updates#next-up) --- # Building Your First Ionic Enterprise Application | Ionic Secure Solutions Starter [Skip to main content](https://ionic.io/docs/enterprise-starter#) The purpose of this guide is to walk through a step-by-step process of building your very first enterprise-grade application using the Ionic Platform. In no time, you will have created an app with our security and storage solutions baked in. Then can then continue on flesh out your with what matters most - your unique business features! Register your Product Key[#](https://ionic.io/docs/enterprise-starter#register-your-product-key "Direct link to heading") -------------------------------------------------------------------------------------------------------------------------- For this guide to work, you will need to have a Native Plugin Key. If you do not have a key already, you can quickly acquire one through a [free 14-day trial](https://dashboard.ionicframework.com/personal/apps?native_trial=1&utm_medium=referral&utm_source=is3_docs&utm_campaign=is3_native_trial) ! With that settled you will have access to: * [Auth Connect](https://ionic.io/docs/auth-connect) : Add Single Sign-on using a variety of services including Auth0, AWS Cognito, Azure AD B2C, or any OpenId Connect provider. * [Identity Vault](https://ionic.io/docs/identity-vault) : Secure user identity and session tokens through encryption at-rest, unlocked only by biometric identity (FaceID/TouchID). * [Secure Storage](https://ionic.io/docs/secure-storage) : Add high-performance, secure data storage. Full SQL query support through SQLite and key/value support for simpler use cases. What will you build?[#](https://ionic.io/docs/enterprise-starter#what-will-you-build "Direct link to heading") --------------------------------------------------------------------------------------------------------------- Your completed application will integrate all three solutions together. You will have untilized the entire Ionic Enterprise stack, including a great cross-platform experience powered by Ionic Framework and Capacitor, mobile CI/CD with Appflow, authentication powered by Auth Connect and Identity Vault, and data storage powered by Secure Storage. TL;DR[#](https://ionic.io/docs/enterprise-starter#tldr "Direct link to heading") --------------------------------------------------------------------------------- If you would like to jump ahead and get the completed code for your own investigation before you get started, you can grab it from [GitHub](https://github.com/ionic-team/ionic-enterprise-starter) . [Edit this page](https://github.com/ionic-team/ionic-enterprise-starter/tree/main/website/docs/overview.md) * [Register your Product Key](https://ionic.io/docs/enterprise-starter#register-your-product-key) * [What will you build?](https://ionic.io/docs/enterprise-starter#what-will-you-build) * [TL;DR](https://ionic.io/docs/enterprise-starter#tldr) --- # AWS Amplify - Supported Plugins [Skip to main content](https://ionic.io/docs/supported-plugins/aws-amplify#) Ionic integrates with AWS Amplify to give web developers a comprehensive library for creating and integrating backend resources into their apps quickly. Among the many features are authentication, analytics, push notifications, AI and ML cloud services, and storage. Installation[​](https://ionic.io/docs/supported-plugins/aws-amplify#installation "Direct link to heading") ----------------------------------------------------------------------------------------------------------- AWS Amplify is an entirely web-based SDK, so it works with either Cordova or Capacitor seamlessly. First, install the Amplify SDK into your project: npm install aws-amplify Copy Building an app with a web framework? Amplify has framework-specific packages available that offer UI components tailored for integration with your application. Check out [Angular](https://aws-amplify.github.io/docs/js/angular) , [React](https://aws-amplify.github.io/docs/js/react) , and [Vue](https://aws-amplify.github.io/docs/js/vue) . Continue on by following the [Ionic apps with AWS Amplify guide](https://aws-amplify.github.io/docs/js/tutorials/building-ionic-4-apps/) or the [Amplify JavaScript](https://aws-amplify.github.io/docs/js/start?platform=purejs) documentation. Tutorial: Todo List App[​](https://ionic.io/docs/supported-plugins/aws-amplify#tutorial-todo-list-app "Direct link to heading") -------------------------------------------------------------------------------------------------------------------------------- In [this tutorial](https://aws-amplify.github.io/docs/js/tutorials/building-ionic-4-apps/) , you'll utilize AWS services such as Amazon Cognito, Amazon DynamoDB, and AWS Lambda to build a Todo list app. * [Installation](https://ionic.io/docs/supported-plugins/aws-amplify#installation) * [Tutorial: Todo List App](https://ionic.io/docs/supported-plugins/aws-amplify#tutorial-todo-list-app) --- # Secure Storage - Encryption Key Management with Identity Vault - Secure Storage [Skip to main content](https://ionic.io/docs/secure-storage/encryption-key-management-with-identity-vault#__docusaurus_skipToContent_fallback) On this page Encryption key management is critical when building secure apps, as encryption is only as good as the management of the encryption key. Managing encryption keys client-side is an incredibly complicated and risky task, as apps will need to persist and use an encryption key _client-side_ to enable secure offline apps. Historically, secure client-side key management was impossible. However, thanks to advances in mobile device hardware and APIs, there _is_ a way to securely manage sensitive values such as encryption keys on the client, and the companion Ionic [Identity Vault](https://ionic.io/docs/identity-vault) product was built to correctly and securely implement those capabilities. Managing Encryption Keys with Identity Vault[​](https://ionic.io/docs/secure-storage/encryption-key-management-with-identity-vault#managing-encryption-keys-with-identity-vault "Direct link to Managing Encryption Keys with Identity Vault") ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- [Ionic Identity Vault](https://ionic.io/products/identity-vault) is a powerful solution that provides a cross-platform layer on top of modern mobile security hardware and biometric authentication. Sensitive values, such as encryption keys or auth tokens, can be stored securely on-device or at rest in specialty hardware developed by Apple and vendors in the Android ecosystem. When used in tandem with Ionic Identity Vault, developers can safely store and management their encryption key on device, and enable biometric authentication to secure sensitive data against theft, loss, or jailbreaking. In practice, once the app user authenticates, the app obtains an encryption key following one of several strategies. One strategy is to auto-generate a unique encryption key on demand, tied to the authenticated user. Another is to retrieve it from a server backend through an API call. Next, store the encryption key securely using Identity Vault. Finally, configure Secure Storage with the encryption key to encrypt all data. Installation[​](https://ionic.io/docs/secure-storage/encryption-key-management-with-identity-vault#installation "Direct link to Installation") ----------------------------------------------------------------------------------------------------------------------------------------------- To get started, follow the [Identity Vault](https://ionic.io/docs/identity-vault) installation instructions. Obtain an Encryption Key[​](https://ionic.io/docs/secure-storage/encryption-key-management-with-identity-vault#obtain-an-encryption-key "Direct link to Obtain an Encryption Key") ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- There are several approaches to obtain an encryption key. It's recommended to use a Service that encapsulates all key retrieval logic. ### Autogenerated[​](https://ionic.io/docs/secure-storage/encryption-key-management-with-identity-vault#autogenerated "Direct link to Autogenerated") Auto-generate a unique encryption key on demand, tied to the authenticated user. Note that the key is not retrievable if it is lost. #### Angular[​](https://ionic.io/docs/secure-storage/encryption-key-management-with-identity-vault#angular "Direct link to Angular") import { Injectable } from '@angular/core';@Injectable({ providedIn: 'root',})export class KeyService { // Generate an encryption key on the fly unique to the current app user // Reference: https://stackoverflow.com/a/2117523/180424 get(): string { // generate a UUID v4 return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => { const r = Math.random() * 16 | 0; const v = c == 'x' ? r : (r & 0x3 | 0x8); return v.toString(16); }); }} #### React, Vue, Vanilla TypeScript[​](https://ionic.io/docs/secure-storage/encryption-key-management-with-identity-vault#react-vue-vanilla-typescript "Direct link to React, Vue, Vanilla TypeScript") With other frameworks, you may opt to create a simple utility function that you store in a `key-utils.ts` (or similar) module. export const generateKey = (): string => 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => { const r = Math.random() * 16 | 0; const v = c === 'x' ? r : (r & 0x3 | 0x8); return v.toString(16); }); ### Retrieve from a Server[​](https://ionic.io/docs/secure-storage/encryption-key-management-with-identity-vault#retrieve-from-a-server "Direct link to Retrieve from a Server") Retrieve the key from a server backend using an API call and your tooling of choice. The key may be retrievable depending on the backend configuration. Store the Key in Identity Vault[​](https://ionic.io/docs/secure-storage/encryption-key-management-with-identity-vault#store-the-key-in-identity-vault "Direct link to Store the Key in Identity Vault") -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Secure the encryption key on-device using Ionic Identity Vault. It's recommended to create a Service that encapsulates all key storage logic. For a vault that stores keys rather than authentication information, it is often most appropriate to use a `SecureStorage` vault. A minimal implementation contains a method to initialize the vault and a method to get the key, generating it if need be. For complete details on creating vault services and properly integrating them into your application, please refer to the [Identity Vault documentation](https://ionic.io/docs/identity-vault) . ### Angular[​](https://ionic.io/docs/secure-storage/encryption-key-management-with-identity-vault#angular-1 "Direct link to Angular") import { Injectable, inject } from '@angular/core';import { Capacitor } from '@capacitor/core';import { KeyService } from './key.service';@Injectable({ providedIn: 'root'})export class KeyVaultService { private vault: Vault | BrowserVault; private keyService = inject(KeyService); constructor() { this.vault = Capacitor.isNativePlatform() ? new Vault() : new BrowserVault(); } async initialize(): Promise { await this.vault.initialize({ key: 'io.ionic.csdemosecurestoragekeys', type: VaultType.SecureStorage, deviceSecurityType: DeviceSecurityType.None, unlockVaultOnLoad: false, }); async getEncryptionKey(): Promise { let key = await this.vault.getValue('encryption-key'); if (!key) { key = await this.keyService.get(); await this.valut.setValue('encryption-key', key); } return key; }} ### React, Vue, Vanilla TypeScript[​](https://ionic.io/docs/secure-storage/encryption-key-management-with-identity-vault#react-vue-vanilla-typescript-1 "Direct link to React, Vue, Vanilla TypeScript") For React, Vue, or Vanilla TypeScript applications similar utility functions would be created and used. For example: import { Injectable, inject } from '@angular/core';import { Capacitor } from '@capacitor/core';import { generateKey } from './key-utils';const vault: Vault | BrowserVault = Capacitor.isNativePlatform() ? new Vault() : new BrowserVault();export const initialize = async () Promise => { await vault.initialize({ key: 'io.ionic.csdemosecurestoragekeys', type: VaultType.SecureStorage, deviceSecurityType: DeviceSecurityType.None, unlockVaultOnLoad: false, });}export const getEncryptionKey = async (): Promise => { let key = await vault.getValue('encryption-key'); if (!key) { key = generateKey(); await valut.setValue('encryption-key', key); } return key;} Configure Ionic Secure Storage with the Encryption Key[​](https://ionic.io/docs/secure-storage/encryption-key-management-with-identity-vault#configure-ionic-secure-storage-with-the-encryption-key "Direct link to Configure Ionic Secure Storage with the Encryption Key") ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Configure Secure Storage with the newly generated encryption key. It's recommended to create a Service that encapsulates all storage logic. Begin by injecting the `KeyVaultService` created above then call an initialization function in the constructor. Within the init function, obtain the encryption key from the `KeyVaultService`, then set it to the `key` property in a call to `sqlite.create()`. Angular[​](https://ionic.io/docs/secure-storage/encryption-key-management-with-identity-vault#angular-2 "Direct link to Angular") ---------------------------------------------------------------------------------------------------------------------------------- import { Injectable } from '@angular/core';import { SQLite, SQLiteObject } from '@ionic-enterprise/secure-storage/ngx';import { KeyVaultService } from './key-vault.service';@Injectable({ providedIn: 'root'})export class StorageService { private _database: SQLiteObject | null = null; constructor(private sqlite: SQLite, private keyVaultService: KeyVaultService) { this.init(); } async init() { const key = await this.keyVaultService.getEncryptionKey(); try { this._database = await this.sqlite.create({ name: "my_database.db", location: "default", key }); // Create database tables, other setup tasks, etc. } catch (e) { console.error('Unable to initialize database', e); } }} ### React, Vue, Vanilla JavaScript[​](https://ionic.io/docs/secure-storage/encryption-key-management-with-identity-vault#react-vue-vanilla-javascript "Direct link to React, Vue, Vanilla JavaScript") It is more natural to use functions rather than classes in these environments. For example: import { getEncryptionKey } from './key-vault';import { SQLite, SQLiteObject } from '@ionic-enterprise/secure-storage';import { Capacitor } from '@capacitor/core';let handle: SQLiteObject | null = null;const openDatabase = async (): Promise => { if (Capacitor.isNativePlatform()) { const key = await getEncryptionKey(); if (key) { return SQLite.create({ name: "my_database.db", location: 'default', key, }); } } return null;};export const getHandle = async (): Promise => { if (!handle) { handle = await openDatabase(); } return handle;}; Now that Secure Storage has been configured with an encryption key, all data will be encrypted at-rest. Contents -------- * [Managing Encryption Keys with Identity Vault](https://ionic.io/docs/secure-storage/encryption-key-management-with-identity-vault#managing-encryption-keys-with-identity-vault) * [Installation](https://ionic.io/docs/secure-storage/encryption-key-management-with-identity-vault#installation) * [Obtain an Encryption Key](https://ionic.io/docs/secure-storage/encryption-key-management-with-identity-vault#obtain-an-encryption-key) * [Autogenerated](https://ionic.io/docs/secure-storage/encryption-key-management-with-identity-vault#autogenerated) * [Retrieve from a Server](https://ionic.io/docs/secure-storage/encryption-key-management-with-identity-vault#retrieve-from-a-server) * [Store the Key in Identity Vault](https://ionic.io/docs/secure-storage/encryption-key-management-with-identity-vault#store-the-key-in-identity-vault) * [Angular](https://ionic.io/docs/secure-storage/encryption-key-management-with-identity-vault#angular-1) * [React, Vue, Vanilla TypeScript](https://ionic.io/docs/secure-storage/encryption-key-management-with-identity-vault#react-vue-vanilla-typescript-1) * [Configure Ionic Secure Storage with the Encryption Key](https://ionic.io/docs/secure-storage/encryption-key-management-with-identity-vault#configure-ionic-secure-storage-with-the-encryption-key) * [Angular](https://ionic.io/docs/secure-storage/encryption-key-management-with-identity-vault#angular-2) * [React, Vue, Vanilla JavaScript](https://ionic.io/docs/secure-storage/encryption-key-management-with-identity-vault#react-vue-vanilla-javascript) --- # Gating the App | Ionic Secure Solutions Starter [Skip to main content](https://ionic.io/docs/enterprise-starter/guard#) Our authentication process in great and all, but it does us no good if users can navigate anywhere in the app without logging in. We change that with an authentication guard around the `tabs` route. Create the Guard[#](https://ionic.io/docs/enterprise-starter/guard#create-the-guard "Direct link to heading") -------------------------------------------------------------------------------------------------------------- Once again we can run a command to create the appropriate file in the project structure: ionic g guard guards/auth Copy You will be prompted to choose your gaurd's interface. In this case we will go with `CanActivate`, which ultimately allows you to decided when routes can be activated. Additional information on the other structures can be found [here](https://angular.io/api/router#structures) . ![](https://ionic.io/docs/enterprise-starter/assets/images/generate-guard-50e54e1cf67795d34164bfa804a2cc5d.png) After choosing our structure, the file is created with the function already in place: src/app/guards/auth.guard.ts import { Injectable } from '@angular/core';import { ActivatedRouteSnapshot, CanActivate, RouterStateSnapshot, UrlTree } from '@angular/router';import { Observable } from 'rxjs'; @Injectable({ providedIn: 'root',})export class AuthGuard implements CanActivate { canActivate( route: ActivatedRouteSnapshot, state: RouterStateSnapshot ): Observable | Promise | boolean | UrlTree { return true; }} Copy For our purposes, we will condense the `canActivate()` return type down to just a `Promise` of a `boolean` value. Next, the `AuthenticationService` is injected in order to give access to the predefined `isAuthenticated()` function. Finally, we will update the activation logic to check to see the user is authenticated or not. If they are, `true` is returned and the user will get access to the main part of the app. If they are not authenticated, logic is added to handle navigating the user back to the `LoginPage` using the `NavController`. This will end up looking as follows: src/app/guards/auth.guard.ts ...import { NavController } from '@ionic/angular';import { AuthenticationService } from '../services/authentication.service'; ...export class AuthGuard implements CanActivate { constructor( private authService: AuthenticationService, private navCtrl: NavController ) {} async canActivate( route: ActivatedRouteSnapshot, state: RouterStateSnapshot ): Promise { return await this.checkAuth(); } private async checkAuth() { const authed = await this.authService.isAuthenticated(); return authed || this.routeToLogin(); } private routeToLogin(): boolean { this.navCtrl.navigateRoot('/login'); return false; }} Copy Using the Guard[#](https://ionic.io/docs/enterprise-starter/guard#using-the-guard "Direct link to heading") ------------------------------------------------------------------------------------------------------------ With the `AuthGuard` created, it can now be utilized in protecting the `tabs` route. This is done through updating the `canActivate` property within the initial route for `tabs`: src/app/tabs/tabs-routing.module.ts ...import { AuthGuard } from '../guards/auth.guard'; const routes: Routes = [ { path: '', component: TabsPage, canActivate: [AuthGuard], children: [ ... ], },];... Copy Now you'll notice that the app routing pushes you to `LoginPage` right away. This is because we never logged in with a user yet. Next up[#](https://ionic.io/docs/enterprise-starter/guard#next-up "Direct link to heading") -------------------------------------------------------------------------------------------- With your application being properly gated, we can build on to the security measures by implementing secure storage of its data. [Edit this page](https://github.com/ionic-team/ionic-enterprise-starter/tree/main/website/docs/guard.md) * [Create the Guard](https://ionic.io/docs/enterprise-starter/guard#create-the-guard) * [Using the Guard](https://ionic.io/docs/enterprise-starter/guard#using-the-guard) * [Next up](https://ionic.io/docs/enterprise-starter/guard#next-up) --- # Installation - Secure Storage [Skip to main content](https://ionic.io/docs/secure-storage/install#__docusaurus_skipToContent_fallback) On this page Follow these steps to install Secure Storage into your app. **Don't have a Secure Storage subscription?** [Try it free now](http://dashboard.ionicframework.com/personal/apps?native_trial=1) . Installation[​](https://ionic.io/docs/secure-storage/install#installation "Direct link to Installation") --------------------------------------------------------------------------------------------------------- If you have not already setup Ionic Enterprise in your app, [follow the one-time setup steps](https://ionic.io/docs/premier-plugins/setup) . Next, install the plugin: * Capacitor * Cordova npm install @ionic-enterprise/secure-storagenpx cap sync ionic cordova plugin add @ionic-enterprise/secure-storage > NOTE: npm 7+ is recommended. For previous versions, install `@ionic-native/core` as a [dependency](https://www.npmjs.com/package/@ionic-native/core) > . Angular Usage[​](https://ionic.io/docs/secure-storage/install#angular-usage "Direct link to Angular Usage") ------------------------------------------------------------------------------------------------------------ In Angular, start by defining the `SQLite` class as provider in one of your component modules. We recommend your `AppModule` for usage across your app: import { SQLite } from '@ionic-enterprise/secure-storage/ngx';@NgModule({ // ... snip ... providers: [SQLite], bootstrap: [AppComponent],})export class AppModule {} Next, import `@ionic-enterprise/secure-storage/ngx` into your file and inject it into your constructor: import { SQLite, SQLiteObject } from '@ionic-enterprise/secure-storage/ngx';class MyComponent { constructor(private sqlite: SQLite) {}} Initializing the database can be done immediately in the constructor: private database: SQLiteObject;constructor(private sqlite: SQLite) { this.initializeDatabase();}private async initializeDatabase() { // Create or open a table try { const db = await this.sqlite.create({ name: "mydb", location: "default", // Key/Password used to encrypt the database // Strongly recommended to use Identity Vault to manage this key: "password" }); this.database = db; // Create our initial schema await db.executeSql('CREATE TABLE IF NOT EXISTS software(name, company, type, version)', []) } catch (e) { console.error('Unable to initialize database', e); }} **Note:** starting with version `@ionic-enterprise.secure-storage@2.3.0` the distribution of this plugin changed in a way that is non-breaking for up to date applications. Applications using older versions of Angular and TypeScript may have problems, however. If your application uses an version of TypeScript older than `4.x` you need to change the import path to `@ionic-enterprise/secure-storage/dist/ngx` until such time as you can upgrade the rest of your project. In such a case, it is suggested that you upgrade the rest of your dependencies as soon as possible. React Usage[​](https://ionic.io/docs/secure-storage/install#react-usage "Direct link to React Usage") ------------------------------------------------------------------------------------------------------ Begin by importing Secure Storage into one of your component source files then create a state variable for the database: import { SQLite, SQLiteObject, SQLiteTransaction } from '@ionic-enterprise/secure-storage';import { useEffect, useState } from 'react';const App: React.FC = () => { const [db, setDb] = useState(null);} Next, initialize the database immediately and create the database tables: useEffect(() => { async function createDb() { try { const newDb = await SQLite.create({ name: 'mydb', location: 'default', // Key/Password used to encrypt the database // Strongly recommended to use Identity Vault to manage this key: "password" }); setDb(newDb); // create tables await newDb.executeSql('CREATE TABLE IF NOT EXISTS software(name, company, type, version)', []) } catch (e) { console.error('Unable to create database', e); } } createDb();}, []); Vue Usage[​](https://ionic.io/docs/secure-storage/install#vue-usage "Direct link to Vue Usage") ------------------------------------------------------------------------------------------------ Begin by importing Secure Storage into one of your components: import { SQLite, SQLiteObject, SQLiteTransaction } from '@ionic-enterprise/secure-storage'; Next, create a ref object for the database instance, then initialize the database immediately: export default defineComponent({ name: 'App', components: { IonApp, IonRouterOutlet }, setup() { const db = ref(); async function createDb() { try { const newDb = await SQLite.create({ name: 'mydb', location: 'default', // Key/Password used to encrypt the database // Strongly recommended to use Identity Vault to manage this key: "password" }); db.value = newDb; console.log('Created database!', newDb); // create tables await db.executeSql('CREATE TABLE IF NOT EXISTS software(name, company, type, version)', []) } catch (e) { console.error('Unable to create database', e); } } createDb(); }}); Basic SQL operations[​](https://ionic.io/docs/secure-storage/install#basic-sql-operations "Direct link to Basic SQL operations") --------------------------------------------------------------------------------------------------------------------------------- Insert data into a database table: this.database.transaction((tx) => { tx.executeSql("INSERT INTO software (name, company, type, version) VALUES (?,?,?,?)", [ "secure-storage", "ionic", "native", "2.0"], (tx, result) => { console.log("insertId: " + result.insertId); // New Id number console.log("rowsAffected: " + result.rowsAffected); // 1 });}); Read data from a database table: this.database.transaction(tx => { tx.executeSql('SELECT * from software', [], (tx, result) => { // Rows is an array of results. Use zero-based indexing to access // each element in the result set: item(0), item(1), etc. for (let i = 0; i < result.rows.length; i++) { // { name: "secure-storage", company: "ionic", type: "native", version: "2.0" } console.log(result.rows.item(i)); // ionic console.log(result.rows.item(i).company); } });}); Update data: this.database.transaction(tx => { tx.executeSql( 'UPDATE software SET version = ? WHERE company = ?', ['2.2', 'ionic'], (tx, result) => { console.log('Rows affected: ' + result.rowsAffected); // 1 }, );}); Delete data: this.database.transaction(tx => { tx.executeSql( 'DELETE FROM software WHERE company = ?', ['ionic'], (tx, result) => { console.log('Rows affected: ' + result.rowsAffected); // 1 }, );}); Close the database: await this.database.close(); Delete the database (provide the same configuration details used when creating it): await this.sqlite.deleteDatabase({ name: 'images.db', location: 'default', key: 'password',}); Transactions[​](https://ionic.io/docs/secure-storage/install#transactions "Direct link to Transactions") --------------------------------------------------------------------------------------------------------- Transactions are strongly recommended for performance reasons, especially when using encryption, and are also critical for building atomic operations that only commit to the database if all statements execute correctly. ### Single-statement Transactions[​](https://ionic.io/docs/secure-storage/install#single-statement-transactions "Direct link to Single-statement Transactions") Transactions can be performed one statement at a time using `SQLiteTransaction.executeSql`: this.database.transaction(tx => { tx.executeSql('CREATE TABLE IF NOT EXISTS software (name, company)'); tx.executeSql('INSERT INTO software VALUES (?,?)', ['offline', 'ionic']); tx.executeSql('INSERT INTO software VALUES (?,?)', ['auth-connect', 'ionic']);}); Or can be performed in a batch `SQLiteObject.sqlBatch`: this.database.sqlBatch([ 'CREATE TABLE IF NOT EXISTS software (name, company)', ['INSERT INTO software VALUES (?,?)', ['offline', 'ionic']], ['INSERT INTO software VALUES (?,?)', ['auth-connect', 'ionic']],]); Contents -------- * [Angular Usage](https://ionic.io/docs/secure-storage/install#angular-usage) * [React Usage](https://ionic.io/docs/secure-storage/install#react-usage) * [Vue Usage](https://ionic.io/docs/secure-storage/install#vue-usage) * [Basic SQL operations](https://ionic.io/docs/secure-storage/install#basic-sql-operations) * [Transactions](https://ionic.io/docs/secure-storage/install#transactions) * [Single-statement Transactions](https://ionic.io/docs/secure-storage/install#single-statement-transactions) --- # Reference Apps - Secure Storage [Skip to main content](https://ionic.io/docs/secure-storage/reference-apps#__docusaurus_skipToContent_fallback) On this page ### Ionic Secure Solutions Starter (Angular)[​](https://ionic.io/docs/secure-storage/reference-apps#ionic-secure-solutions-starter-angular "Direct link to Ionic Secure Solutions Starter (Angular)") Ionic Secure Solutions Starter is free starter app for activating [Ionic's Secure Solutions](https://go.ionic.io/secure-solutions) . It comes pre-configured with Ionic [Identity Vault](https://ionic.io/docs/identity-vault) , [Auth Connect](https://ionic.io/docs/auth-connect) , and [Secure Storage](https://ionic.io/docs/secure-storage/) . * [View code on GitHub](https://github.com/ionic-team/ionic-enterprise-starter) ### Security Trifecta[​](https://ionic.io/docs/secure-storage/reference-apps#security-trifecta "Direct link to Security Trifecta") The Security Trifecta application demonstrates the use of Ionic's Secure Storage solution to provide an example of an offline-first implementation with backend sync that can be used as the foundation for full featured implementation. This application uses Ionic's Auth Connect solution to provide authentication and Ionic's Identity Vault solution to manage the authentication session as well as manage the encryption key for the Secure Storage database. Versions exist for each of the following frameworks: * [Non-Ionic, Vuetify](https://github.com/ionic-enterprise/security-trifecta-vuetify) * [Ionic Angular](https://github.com/ionic-enterprise/security-trifecta-angular) * [Ionic Vue](https://github.com/ionic-enterprise/security-trifecta-vue) ### Ionifits (Angular)[​](https://ionic.io/docs/secure-storage/reference-apps#ionifits-angular "Direct link to Ionifits (Angular)") Ionifits is an example implementation of a Human Resources app (the name is a play on Zenefits, by which it's inspired). It utilizes the complete Ionic enterprise stack, including a UI powered by [Ionic Framework](https://ionicframework.com/) , native apps built with [Capacitor](https://capacitorjs.com/) , mobile CI/CD with [Appflow](https://ionic.io/docs/appflow) , authentication powered by [Auth Connect](https://ionic.io/docs/auth-connect) and [Identity Vault](https://ionic.io/docs/identity-vault) , and encrypted data storage powered by [Secure Storage](https://ionic.io/docs/secure-storage/) . * [View code on GitHub](https://github.com/ionic-team/ionifits) * [Try the PWA](https://ionifits.ionicframework.com/) * [Try the iOS app](https://testflight.apple.com/join/87WO2hwS) * [Try the Android app](https://play.google.com/store/apps/details?id=io.ionic.demoapp.ionifits) Specifically, Ionifits uses Secure Storage to encrypt user-entered expenses data. Additionally, it manages the encryption key with Identity Vault using the techniques [described here](https://ionic.io/docs/secure-storage/encryption-key-management-with-identity-vault) . ### Key Value Store (Angular)[​](https://ionic.io/docs/secure-storage/reference-apps#key-value-store-angular "Direct link to Key Value Store (Angular)") This application uses the [`KeyValueStorage`](https://ionic.io/docs/secure-storage/key-value) API to add offline capabilities. It makes API calls and caches the results encrypted using [Secure Storage](https://ionic.io/docs/secure-storage/) . It will display the cached data when offline and to improve performance. * [View code on GitHub](https://github.com/ionic-enterprise/cs-secure-storage-key-value) Contents -------- * [Ionic Secure Solutions Starter (Angular)](https://ionic.io/docs/secure-storage/reference-apps#ionic-secure-solutions-starter-angular) * [Security Trifecta](https://ionic.io/docs/secure-storage/reference-apps#security-trifecta) * [Ionifits (Angular)](https://ionic.io/docs/secure-storage/reference-apps#ionifits-angular) * [Key Value Store (Angular)](https://ionic.io/docs/secure-storage/reference-apps#key-value-store-angular) --- # Capacitor Supported Plugins - Supported Plugins [Skip to main content](https://ionic.io/docs/supported-plugins/capacitor#) Capacitor Supported Plugins are also available, but work a little bit differently than their Cordova counterparts. Because the Ionic team is already in charge of Capacitor's official plugins and their APIs, you can use the Capacitor plugins directly like normal through the [Capacitor Official Plugin API Documentation](https://capacitorjs.com/docs/apis) . Support & Advisory[​](https://ionic.io/docs/supported-plugins/capacitor#support--advisory "Direct link to heading") -------------------------------------------------------------------------------------------------------------------- Capacitor Supported Plugins come with a direct line of communication to an Ionic Customer Success Representative. You can rely on this representative to submit and prioritize additional feature development and bug fixes directly with the Ionic team. You can also add Advisory services to help you utilize these plugins. With Capacitor Supported Plugins, you have dedicated support, SLAs, security patches, advisory, and more available to you. Request Access to Supported Plugins[​](https://ionic.io/docs/supported-plugins/capacitor#request-access-to-supported-plugins "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------------------------------------- --- # Secure Storage - Troubleshooting - Secure Storage [Skip to main content](https://ionic.io/docs/secure-storage/troubleshooting#__docusaurus_skipToContent_fallback) On this page General troubleshooting[​](https://ionic.io/docs/secure-storage/troubleshooting#general-troubleshooting "Direct link to General troubleshooting") -------------------------------------------------------------------------------------------------------------------------------------------------- To verify the plugin is correctly installed, there are some test methods available on the plugin: // Verify that both the JavaScript and native part of this plugin// are installed in your Ionic appawait this.sqlite.echoTest();// Verify basic database access operations including opening a database// Prints "OPEN database: OK"await this.sqlite.selfTest(); Database location or iosDatabaseLocation setting is now mandatory in openDatabase call.[​](https://ionic.io/docs/secure-storage/troubleshooting#database-location-or-iosdatabaselocation-setting-is-now-mandatory-in-opendatabase-call "Direct link to Database location or iosDatabaseLocation setting is now mandatory in openDatabase call.") ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- This message indicates that `location` or `iosDatabaseLocation` was not provided in the options for `create` or `openDatabase`, which is now required. A value of `'default'` is appropriate for most use cases. Unable to open database file[​](https://ionic.io/docs/secure-storage/troubleshooting#unable-to-open-database-file "Direct link to Unable to open database file") ----------------------------------------------------------------------------------------------------------------------------------------------------------------- _Symptom_: `create` or `openDatabase` fails with a message indicating the engine was unable to open the database file or that the database file is not a valid database. _Diagnosis_: The usual culprit here is that an unencrypted database was created first, and then a `key` was specified later (to enable encryption), but by then the original database already exists but can't be read since it's not encrypted. _Solution_: The solution is to change the `name` of the database file whenever switching between a database used with and without encryption. Additionally, uninstalling the app will delete the database. App is rejected for storing data in iCloud[​](https://ionic.io/docs/secure-storage/troubleshooting#app-is-rejected-for-storing-data-in-icloud "Direct link to App is rejected for storing data in iCloud") ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- The `location` option in `create` can be used to specify where the database file is stored on device. The value of `default` will store the database file in a non-iCloud backed up location. This is recommended for most apps, though iCloud backup could be legitimate for some use cases but that is app-specific. Contents -------- * [General troubleshooting](https://ionic.io/docs/secure-storage/troubleshooting#general-troubleshooting) * [Database location or iosDatabaseLocation setting is now mandatory in openDatabase call.](https://ionic.io/docs/secure-storage/troubleshooting#database-location-or-iosdatabaselocation-setting-is-now-mandatory-in-opendatabase-call) * [Unable to open database file](https://ionic.io/docs/secure-storage/troubleshooting#unable-to-open-database-file) * [App is rejected for storing data in iCloud](https://ionic.io/docs/secure-storage/troubleshooting#app-is-rejected-for-storing-data-in-icloud) --- # Securing Your App's Data | Ionic Secure Solutions Starter [Skip to main content](https://ionic.io/docs/enterprise-starter/secure-storage#) In any Enterprise application, users are bound to perform transactions to store data. This could inlcude authentication information, app settings, data your SaaS is providing, etc. Thus, it is crucial that this information is stored securely on whichever platform the user is operating on. [Ionic Secure Storage](https://ionic.io/products/secure-storage) provides this utility. Ionic Secure Storage is a cross-platform local database system for high performance, secure data storage on iOS and Android. It provides full SQL query and relational data support through [SQLite](https://www.sqlite.org/index.html) , as well as key/value support for simpler use cases when used with the [Ionic Storage](https://github.com/ionic-team/ionic-storage) utility library. Full encryption support (using 256-bit AES) is provided out of the box for security sensitive applications. Installing Secure Storage[#](https://ionic.io/docs/enterprise-starter/secure-storage#installing-secure-storage "Direct link to heading") ----------------------------------------------------------------------------------------------------------------------------------------- Just as Auth Connect was installed, we will perform a similar command to get Secure Storage installed and sync'ed with the native app properties: npm install @ionic-enterprise/secure-storagenpx cap sync Copy Key Value Support[#](https://ionic.io/docs/enterprise-starter/secure-storage#key-value-support "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------- While Ionic Secure Storage provides a powerful SQLite-backed data store, it also has support for key/value functionality for simpler use cases or when data will fit in memory and querying can be done in JavaScript. Key/value support is provided by the companion [`@ionic/storage`](https://github.com/ionic-team/ionic-storage) utility which provides a generic storage API that works across multiple platforms, abstracting away storage engine details and providing a simple API with low overhead. Support for encryption and SQLite is available when running on iOS and Android and using the Ionic Secure Storage driver for `@ionic/storage`. We will touch on that in greater detail soon. In order to use key/value storage in our app as well, we first need to install like Angular specific library: npm install @ionic/storage-angular Copy Creating a Storage Service[#](https://ionic.io/docs/enterprise-starter/secure-storage#creating-a-storage-service "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------------------------- After making Secure Storage available to the application, including key/value support, we will setup a service to handle our storage logic. First, we generate the service: ionic g service services/storage Copy In the newly created service, we first initial the `storage` object and specify the order in which we prefer to use the storage drivers. Next, we will add logic to support storage natively on iOS and Android, as well as support for storage on the web and simple use cases. src/app/services/storage.service.ts import { Injectable } from '@angular/core';import { Capacitor } from '@capacitor/core';import IonicSecureStorageDriver from '@ionic-enterprise/secure-storage/driver';import { SQLite, SQLiteObject } from '@ionic-enterprise/secure-storage/ngx';import { Drivers } from '@ionic/storage';import { Storage } from '@ionic/storage-angular'; @Injectable({ providedIn: 'root',})export class StorageService { private storage: Storage; private database: SQLiteObject; constructor(private ngStorage: Storage, private sqlite: SQLite) { this.storage = new Storage({ driverOrder: [Drivers.SecureStorage, Drivers.IndexedDB, Drivers.LocalStorage], }); this.init(); } private async init() { // Initialize Ionic Storage for web and basic native support await this.ngStorage.defineDriver(IonicSecureStorageDriver); this.storage = await this.ngStorage.create(); if (Capacitor.isNativePlatform()) { // Create or open a table try { const db = await this.sqlite.create({ name: 'enterprisestarter.db', // The name of your database location: 'default', // Key/Password used to encrypt the database // Strongly recommended to use Identity Vault to manage this key: 'password', }); this.database = db; // Create our initial schema await db.executeSql( '', // Example: 'CREATE TABLE IF NOT EXISTS software(name, company, type version)' [] ); } catch (e) { console.error('Unable to initialize database', e); } } }} Copy Next up[#](https://ionic.io/docs/enterprise-starter/secure-storage#next-up "Direct link to heading") ----------------------------------------------------------------------------------------------------- To ensure your app's data is as secure as possible, it is best to also use encryption. We will now go ahead and add an extra layer of protection for your users. [Edit this page](https://github.com/ionic-team/ionic-enterprise-starter/tree/main/website/docs/secure-storage.md) * [Installing Secure Storage](https://ionic.io/docs/enterprise-starter/secure-storage#installing-secure-storage) * [Key Value Support](https://ionic.io/docs/enterprise-starter/secure-storage#key-value-support) * [Creating a Storage Service](https://ionic.io/docs/enterprise-starter/secure-storage#creating-a-storage-service) * [Next up](https://ionic.io/docs/enterprise-starter/secure-storage#next-up) --- # Single sign-on with Auth Connect | Ionic Secure Solutions Starter [Skip to main content](https://ionic.io/docs/enterprise-starter/auth-connect#) Auth Connect makes it easy to add single sign-on and secure authentication to your app. The hard work of setting up the infrastructure to login, logout, and utilize token refresh for every platform using OpenID Connect is all done for you! When paired with Identity Vault, the authentication and storage of logged-in credentials becomes completely secure. We will soon talk about configuring Identity Vault into your application, but first we have to dive into just the authentication process. Auth Connect supports many popular auth providers, such as Auth0, AWS Cognito, Azure AD, and more! Auth0 will be our auth provider of choice for this demonstration. Install Auth Connect[#](https://ionic.io/docs/enterprise-starter/auth-connect#install-auth-connect "Direct link to heading") ----------------------------------------------------------------------------------------------------------------------------- First, you need to have Auth Connect installed. This will use the Enterprise Native Key you added to your app in the last step. To do this you can issue the following command: npm install @ionic-enterprise/auth Copy Let's now ensure we have a web build at our disposal using: ionic build --prod Copy Next, you will add iOS and Android native platform projects to your app via the following: npx cap add iosnpx cap add android Copy For each, it may have you run a related `Capacitor` install first. If so, follow those prompts, then re-run your desired command. With iOS and Android projects added you can copy the web app build and Capacitor configuration file into the native platform projects, as well as update the native plugins and dependencies using the following command: npx cap sync Copy More information on these commands can be found by visiting the [Ionic CLI docs](https://ionicframework.com/docs/cli/) and the [Capacitor CLI docs](https://capacitorjs.com/docs/cli) . Update Auth Scheme[#](https://ionic.io/docs/enterprise-starter/auth-connect#update-auth-scheme "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------- Once the above is settled, the `Android Manifest` in your project needs a tweak. You will need to add the following intents next to the other intents in the main activity node: android/app/src/main/AndroidManifest.xml Copy iOS will need a slight adjustment too. Go ahead and add and/or update the `CFBundleURLTypes` node in `Info.plist` with the following: ios/App/App/Info.plist CFBundleURLTypes CFBundleURLSchemes $AUTH_URL_SCHEME Copy `$AUTH_URL_SCHEME` can then be replaced by the bundle id of your app in both projects. If needed, you can find more information on this process in the [Auth Connect Installation Guide](https://ionic.io/docs/auth-connect/install#installation) . Create an App on Auth0[#](https://ionic.io/docs/enterprise-starter/auth-connect#create-an-app-on-auth0 "Direct link to heading") --------------------------------------------------------------------------------------------------------------------------------- Alright, now it is time to get our auth provider set up to be used within our app. Head on over to [auth0.com](https://auth0.com/) and create an account if you don not have one already. Once you are logged in, you can head to their Applications section where you can choose to `Create Application`. Give the app a name and choose the `Native` application type. ![](https://ionic.io/docs/enterprise-starter/assets/images/auth0-configs-f2cc95dcb2205eef19a65cb73e5d4614.png) Next, you'll navigate to the `Settings` section and fill out the **_Allowed Callback URLs_** and **_Allowed Logout URLs_**. The **_Allowed Callback URLs_** are used after the user signs into Auth0 and needs to tell Auth Connect which page to redirect to in your app. The **_Allowed Logout URLs_** are therefore used after the user signs out of Auth0 and needs to tell Auth Connect where to go next. Typically, the formula used for the **_Allowed Callback URLs_** is "uniqueId://page". "appName://callback" is a more concrete example. The same forumula is used for the **_Allowed Logout URLs_** as well. A more specific example would be "appName://login". Other configurations can work as well, so do not feel like those are the only options. Those examples are purely a recommendation. Additionally, we need to create a user that can eventually log in to our app. Head on over to the `Authentication` section in Auth0 and click into `Databases`. You can then either update the default DB with your user or create an entirely separate DB just for your new app using the `Create DB Connection` button. If you do create a new DB, be sure to add it as a connection to your new app! Our example will utilize a new user added to a specific DB newly generated and connected just for this given app. With Auth0 set up, we can bring the configuration properties over to our app. Setup Auth Configs in the App[#](https://ionic.io/docs/enterprise-starter/auth-connect#setup-auth-configs-in-the-app "Direct link to heading") ----------------------------------------------------------------------------------------------------------------------------------------------- To utilize our Auth0 configs, we need an Authentication Service and an update to Angular's environment files. To generate a new Authentication service we can run the following: ionic g service services/authentication Copy The newly created `AuthenticationService` class should be extended to utilize `IonicAuth` which handles much of the authentication logic behind the scenes. This new service will utilize our configs we will setup in the `environment.ts` file: src/app/services/authentication.service.ts import { IonicAuth } from '@ionic-enterprise/auth';import { authOptions } from '../../environments/environment'; export class AuthenticationService extends IonicAuth { constructor() { super(authOptions); }} Copy The `authOptions` inside of `environments.ts` will take a form similar to the following: src/environments/environment.ts import { IonicAuthOptions } from '@ionic-enterprise/auth'; export const authOptions: IonicAuthOptions = { authConfig: 'FILL_IN', platform: 'FILL_IN', clientID: 'FILL_IN', discoveryUrl: 'FILL_IN', redirectUri: 'FILL_IN', scope: 'FILL_IN', logoutUrl: 'FILL_IN', iosWebView: 'FILL_IN',}; Copy However, the configuration that is used inside of `AuthenticationService` needs to be slightly different depending on the run-time platform. So we can make a few adjustments: src/environments/environment.ts import { IonicAuthOptions } from "@ionic-enterprise/auth"; const authOptions = { authConfig: "auth0" as "auth0", clientID: "YOUR_AUTH0_CLIENT_ID", discoveryUrl: "https://YOUR_AUTH0_DOMAIN/.well-known/openid-configuration", scope: "openid offline_access email picture profile", audience: "",}; export const nativeAuthOptions: IonicAuthOptions = { ...authOptions, redirectUri: "myEnterpriseApp://callback", logoutUrl: "myEnterpriseApp://login", platform: "capacitor", iosWebView: "private",}; export const webAuthOptions: IonicAuthOptions = { ...authOptions, redirectUri: "http://app.enterprise.com/callback", logoutUrl: "http://app.enterprise.com/login", platform: "web", implicitLogin: "CURRENT",}; ... Copy The above is purely for demonstration purposes and should be modified to meet your specific setup configuration. However, it is a good representation of reusing the properties that are the same across platforms, as well as giving unique values to those that are not. Given our run-time dependent options, we can make the change to `AuthenticationService` to call the right ones utilizing Capacitor: src/app/services/authentication.service.ts import { IonicAuth } from '@ionic-enterprise/auth';import { nativeAuthOptions, webAuthOptions } from '../../environments/environment';import { Capacitor } from '@capacitor/core'; export class AuthenticationService extends IonicAuth { constructor() { super(Capacitor.isNativePlatform() ? nativeAuthOptions : webAuthOptions); }} Copy Next up[#](https://ionic.io/docs/enterprise-starter/auth-connect#next-up "Direct link to heading") --------------------------------------------------------------------------------------------------- With authentication configs setup, we're ready to create our `LoginPage`. [Edit this page](https://github.com/ionic-team/ionic-enterprise-starter/tree/main/website/docs/auth-connect.md) * [Install Auth Connect](https://ionic.io/docs/enterprise-starter/auth-connect#install-auth-connect) * [Update Auth Scheme](https://ionic.io/docs/enterprise-starter/auth-connect#update-auth-scheme) * [Create an App on Auth0](https://ionic.io/docs/enterprise-starter/auth-connect#create-an-app-on-auth0) * [Setup Auth Configs in the App](https://ionic.io/docs/enterprise-starter/auth-connect#setup-auth-configs-in-the-app) * [Next up](https://ionic.io/docs/enterprise-starter/auth-connect#next-up) --- # Add a Login Page | Ionic Secure Solutions Starter [Skip to main content](https://ionic.io/docs/enterprise-starter/login#) After the tabs-based foundation is created, we can start our journey by creating a login page. This login page will also be responsive so it will be presentable both on desktop and mobile viewports. Eventually, we will implement an authentication guard around the main application, so a user must be logged-in to see the rest of the application. Generate a Login Page[#](https://ionic.io/docs/enterprise-starter/login#generate-a-login-page "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------ From the Terminal pane of VSCode we can create our login page by executing the following command: ionic g page pages/login Copy Now we have pages directory, inside the main src app directory, which houses all of our pages. All of the necessary files pertaining to the login page have been created within the login directory within the pages directory. ![](https://ionic.io/docs/enterprise-starter/assets/images/login-page-directory-ec26e3c7f7e6bcc9f463742e2d7d64d2.png) Create Responsive Layout[#](https://ionic.io/docs/enterprise-starter/login#create-responsive-layout "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------------ Having a responsive layout of the login page will ensure that users have an easy experience when it comes to accessing the app, regardless of the platform they are actively on. This is done by using a grid-type structure where the columns stack when the screensize hits a certain breakpoint. This would look as follows: src/app/pages/login.page.html
Ionic logo Welcome to Ionic Secure Solutions Starter Sign in
Copy Since the `/login` route isn't where your app's router navigates to from the beginning, you'll have to navigate to it manually to start in order to verify your changes. Once there, we can see that given the combination of some [styling](https://github.com/ionic-team/ionic-enterprise-starter/blob/main/src/app/pages/login/login.page.scss) and [logic](https://github.com/ionic-team/ionic-enterprise-starter/blob/main/src/app/pages/login/login.page.ts) , the login page will look great whether the user is on the web app or the native app! ![](https://ionic.io/docs/enterprise-starter/assets/images/responsive-login-a75843d9f97b2da080b01bf51da7aede.png) Plumb up the Login button[#](https://ionic.io/docs/enterprise-starter/login#plumb-up-the-login-button "Direct link to heading") -------------------------------------------------------------------------------------------------------------------------------- With the start of our `AuthenticationService`, we can put the "plumbing" in place to get the sign-in button to work: src/app/pages/login/login.page.ts ...import { LoadingController } from '@ionic/angular';import { AuthenticationService } from '../../services/authentication.service'; ...export class LoginPage implements OnInit { public errorMessage: string; constructor( private authService: AuthenticationService, private loadingController: LoadingController ) {} async ngOnInit() { // If coming back after logging into Auth0, // and using CURRENT Implicit (web) Login if (window.location.hash) { const loadingIndicator = await this.showLoadingIndictator(); try { await this.authService.handleLoginCallback(window.location.href); } catch (e) { this.errorMessage = e.message; } finally { loadingIndicator.dismiss(); } } } async login() { // Display loading indicator while Auth Connect login window is open const loadingIndicator = await this.showLoadingIndictator(); try { await this.authService.login(); } catch (e) { console.error(e.message); } finally { loadingIndicator.dismiss(); } } private async showLoadingIndictator() { const loadingIndicator = await this.loadingController.create({ message: 'Opening login window...', }); await loadingIndicator.present(); return loadingIndicator; }} Copy You will notice that we do not have an explicit `login()` function defined within the `AuthenticationService`, yet we are still making that call. This is because by extending `IonicAuth`, we get access to that function without any additional work. For additional safety measures we have added a `try/catch`, ensuring any errors that occur along the login flow are caught. A loading indicator is shown to assist in the user understanding of exactly what is happening. Rounding out the login flow, we can update the `ngOnInit()` to include instructions for when our app user gets pushed back to the app from the implicit web login flow. When they successfully authenticate, the callback parameters are passed on the URL after a hash (#). Thus, we can look for this hash and tell our `AuthenticationService` what we want to do next. In the next section, we'll show this using the `onLoginSuccess()` function. Update Authentication Service[#](https://ionic.io/docs/enterprise-starter/login#update-authentication-service "Direct link to heading") ---------------------------------------------------------------------------------------------------------------------------------------- When the user successfully authenticates with the auth provider, we need to navigate them to the appropriate landing spot within the application. To do this, we will update the `AuthenticationService` to include routing logic within the `onLoginSuccess()` function, which is inherited through the parent class and be implemented. Since we will be routing the user elsewhere, the constructor needs to be updated to inject the `Angular Router`: src/app/services/authentication.service.ts ...import { Router } from '@angular/router'; ...export class AuthenticationService extends IonicAuth { constructor(private router: Router) { super(Capacitor.isNativePlatform() ? nativeAuthOptions : webAuthOptions); }} Copy With the `Router` injected, the `onLoginSuccess()` function can be implemented to push the successfully logged in user to the main route of the app. In this case, we'll push them to `'/'` which redirects to the `tabs` routing workflow: src/app/services/authentication.service.ts async onLoginSuccess() { await this.router.navigate(['/']);} Copy Next up[#](https://ionic.io/docs/enterprise-starter/login#next-up "Direct link to heading") -------------------------------------------------------------------------------------------- The above layout and styling of the `LoginPage` are purely just an example. The options are really endless. Have some fun with it, bring your brand to life, and welcome your users with a simple, but effective login process. Next, we will tackle creating the pages of our application! [Edit this page](https://github.com/ionic-team/ionic-enterprise-starter/tree/main/website/docs/login.md) * [Generate a Login Page](https://ionic.io/docs/enterprise-starter/login#generate-a-login-page) * [Create Responsive Layout](https://ionic.io/docs/enterprise-starter/login#create-responsive-layout) * [Plumb up the Login button](https://ionic.io/docs/enterprise-starter/login#plumb-up-the-login-button) * [Update Authentication Service](https://ionic.io/docs/enterprise-starter/login#update-authentication-service) * [Next up](https://ionic.io/docs/enterprise-starter/login#next-up) --- # Secure Storage - Web Support - Secure Storage [Skip to main content](https://ionic.io/docs/secure-storage/web-support#__docusaurus_skipToContent_fallback) On this page Ionic Secure Storage provides a powerful SQLite-backed data store, but SQLite is not available in a standard browser environment, so apps that must run on iOS, Android, and the web, have to take a slightly different approach to enable web support. In this case, web support is provided by the `KeyValueStorage` class which provides a generic storage API that works across multiple platforms, abstracting away storage engine details and providing a simple API with low overhead. One trade-off is this requires apps to use a key/value data storage architecture instead of a SQL based relational data storage architecture for cross-platform support, which is an acceptable compromise for many apps. Optionally, apps may elect to use the SQL engine when running natively on iOS and Android, but fall back to using the key/value API when running on the web. Installation and Usage[​](https://ionic.io/docs/secure-storage/web-support#installation-and-usage "Direct link to Installation and Usage") ------------------------------------------------------------------------------------------------------------------------------------------- View instructions on [the Key/Value page](https://ionic.io/docs/secure-storage/key-value) . Contents -------- * [Installation and Usage](https://ionic.io/docs/secure-storage/web-support#installation-and-usage) --- # Creating the Session Vault | Ionic Secure Solutions Starter [Skip to main content](https://ionic.io/docs/enterprise-starter/session-vault#) The purpose of the `KeyVaultService` is purely to utilize `SecureStorage` to house the encryption key. Reason-being, the encryption key is often needed prior to the user unlocking the vault. The `SessionVaultService`, on the other hand, can be safely secured behind the vault lock. Define Key Vault Configuration[#](https://ionic.io/docs/enterprise-starter/session-vault#define-key-vault-configuration "Direct link to heading") -------------------------------------------------------------------------------------------------------------------------------------------------- Again, we first need to define a configuration for the vault. The `key` for vault will be slightly different than the `KeyVaultService` used. The other properties provide additional configuration for how this particular vault may behave: src/app/services/session-vault.service.ts ... const vaultConfig: IdentityVaultConfig = { key: 'io.ionic.enterprisestarter', type: VaultType.SecureStorage, lockAfterBackgrounded: 2000, shouldClearVaultAfterTooManyFailedAttempts: true, customPasscodeInvalidUnlockAttempts: 2, unlockVaultOnLoad: false,}; @Injectable({ providedIn: 'root' })export class SessionVaultService { ...} Copy You will notice that the `SessionVaultService` also starts out with the type of `SecureStorage`. This is due to the fact that we do not want the initial configuration to fail if the user's device does not have security set up. Initialize the Vault[#](https://ionic.io/docs/enterprise-starter/session-vault#initialize-the-vault "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------------ We still need to initialize the `SessionVaultService` when the application starts up. This can be done in the `AppModule` via Angular's `APP_INITIALIZER` depencency injection token: src/app/app.module.ts import { APP_INITIALIZER, NgModule } from '@angular/core';... const appInitFactory = (sessionVault: SessionVaultService): (() => Promise) => () => sessionVault.init(); @NgModule({ declarations: [AppComponent], // ... providers: [ ... { provide: APP_INITIALIZER, useFactory: appInitFactory, deps: [SessionVaultService], multi: true, }, ], bootstrap: [AppComponent],})export class AppModule {} Copy Since the `APP_INITIALIZER` is a `Promise` and needs to call a public function within the `SessionVaultService`, a separate `init()` function was created. This will tranform the `SessionVaultService` initialization to look as follows: src/app/services/session-vault.service.ts export class SessionVaultService { private vault: Vault | BrowserVault; private lockedSubject: Subject; constructor(private vaultFactory: VaultFactoryService) { this.init(); } public async init() { this.vault = this.vaultFactory.create(vaultConfig); this.lockedSubject = new Subject(); this.vault.onLock(() => this.lockedSubject.next(true)); this.vault.onUnlock(() => this.lockedSubject.next(false)); }} Copy With that, the session vault is in place and properly initialized when the app boots up! Update Session Vault's Unlock Mode[#](https://ionic.io/docs/enterprise-starter/session-vault#update-session-vaults-unlock-mode "Direct link to heading") --------------------------------------------------------------------------------------------------------------------------------------------------------- As previously mentioned, we started the `SessionVaultService` out by using the `SecureStorage` `type` property. However, what we need to do is update both the `type` and `deviceSecurityType` after the user successfully logs in. This is to ensure we are adding as much security to the vault as we can. This involves calling an `initializeUnlockMode` function upon successful login and modify the vault's config. src/app/services/session-vault.service.ts ... export type UnlockMode = 'Device' | 'SessionPIN' | 'NeverLock' | 'ForceLogin'; ... export class SessionVaultService { ... public async initializeUnlockMode() { if (Capacitor.isNativePlatform()) { if (await Device.isSystemPasscodeSet()) { await this.setUnlockMode('Device'); } else { await this.setUnlockMode('SessionPIN'); } } } public setUnlockMode(unlockMode: UnlockMode): Promise { let type: VaultType; let deviceSecurityType: DeviceSecurityType; switch (unlockMode) { case 'Device': type = VaultType.DeviceSecurity; deviceSecurityType = DeviceSecurityType.Both; break; case 'SessionPIN': type = VaultType.CustomPasscode; deviceSecurityType = DeviceSecurityType.None; break; case 'ForceLogin': type = VaultType.InMemory; deviceSecurityType = DeviceSecurityType.None; break; case 'NeverLock': type = VaultType.SecureStorage; deviceSecurityType = DeviceSecurityType.None; break; default: type = VaultType.SecureStorage; deviceSecurityType = DeviceSecurityType.None; } return this.vault.updateConfig({ ...this.vault.config, type, deviceSecurityType, }); }} Copy Define Helper Vault Functions[#](https://ionic.io/docs/enterprise-starter/session-vault#define-helper-vault-functions "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------------------------------ The `SessionVaultService` will be used to store the logged in user's data and will require helper functions to perform tasks throughout the application. As such, we will update the `SessionVaultService` to include those functions we will need throughout further development and use of the application: src/app/services/session-vault.service.ts ... public get locked() { return this.lockedSubject.asObservable();} public getVault() { return this.vault;} public async hasSession() { return !(await this.vault.isEmpty());} public async clear() { return this.vault.clear();} public async lock() { return this.vault.lock();} public async unlock() { return this.vault.unlock();} public async canUnlock(): Promise { return (await this.hasSession()) && (await this.vault.isLocked());} getValue(key: string): Promise { return this.vault.getValue(key);} setValue(key: string, value: any): Promise { return this.vault.setValue(key, value);} ... Copy You can see that these additional functions will assist in checking for a session vault's existance, returning the state of the vault's lock, locking/unlocking the vault, clearing the vault, and getting/setting values within the session vault. Next Up[#](https://ionic.io/docs/enterprise-starter/session-vault#next-up "Direct link to heading") ---------------------------------------------------------------------------------------------------- Our enterprise app is progressing nicely. With the session vault fully configured we make some updates to the `AuthenticationService`. [Edit this page](https://github.com/ionic-team/ionic-enterprise-starter/tree/main/website/docs/session-vault.md) * [Define Key Vault Configuration](https://ionic.io/docs/enterprise-starter/session-vault#define-key-vault-configuration) * [Initialize the Vault](https://ionic.io/docs/enterprise-starter/session-vault#initialize-the-vault) * [Update Session Vault's Unlock Mode](https://ionic.io/docs/enterprise-starter/session-vault#update-session-vaults-unlock-mode) * [Define Helper Vault Functions](https://ionic.io/docs/enterprise-starter/session-vault#define-helper-vault-functions) * [Next Up](https://ionic.io/docs/enterprise-starter/session-vault#next-up) --- # Secure Storage Support Policy - Secure Storage [Skip to main content](https://ionic.io/docs/secure-storage/support-policy#__docusaurus_skipToContent_fallback) On this page This policy is for Secure Storage as maintained by Ionic. Capacitor Core, Capacitor Plugins, or any additional plugins maintained by Ionic are not covered by this support policy. ### Current Support Status[​](https://ionic.io/docs/secure-storage/support-policy#current-support-status "Direct link to Current Support Status") | Version | Status | Released | Active Support Ends | Long-Term Support Ends | | --- | --- | --- | --- | --- | | V2 | Not Supported | March 10, 2021 | February 10, 2023 | February 10, 2024 | | V3 | Active Support | February 10, 2023 | TBD | TBD | ### Support Policy[​](https://ionic.io/docs/secure-storage/support-policy#support-policy "Direct link to Support Policy") Ionic enterprise products are covered by a 3-stage support plan to ensure that all customers have the best experience with Ionic products and are able to receive our excellent standard of care. These steps are outlined as follows: ### Stage 1: Active Support[​](https://ionic.io/docs/secure-storage/support-policy#stage-1-active-support "Direct link to Stage 1: Active Support") During the active support period of a product, the entirety of Ionic’s customer support services are available to teams using this enterprise product. ### Stage 2: Long Term Support[​](https://ionic.io/docs/secure-storage/support-policy#stage-2-long-term-support "Direct link to Stage 2: Long Term Support") Long Term Support is available to all enterprise products after active support has ended. This duration typically lasts for a period of 12 months, unless otherwise specified. During this stage, most elements of Ionic’s customer support services are available, however products in this stage will only receive bug and security fixes, no new feature requests or updates will be accepted. ### Stage 3: Not Supported[​](https://ionic.io/docs/secure-storage/support-policy#stage-3-not-supported "Direct link to Stage 3: Not Supported") After the period of time for Long Term Support has ended, the product will indefinitely enter the Not Supported stage. Products will still be accessible and usable in this stage, however, support for these versions is limited to existing documentation, knowledge base article or community support. Ionic’s customer support services are not available for products in this stage. We recommend that customers update their software to the latest released version available to enjoy the most stable and complete experience. Ionic offers solutions, workarounds, and other fixes to the best of our ability and at our own discretion. There may be times when the only valid solution is to upgrade to the most recent version of a product. For trial users, support is only offered for the most recent release of a product. We recommend scheduling time to upgrade before the Long Term Support period. Once a product reaches the end of Long Term Support, there will be no additional product support or bug fixes, even if your support contract extends beyond that time. As an example, if you are currently using Identity Vault 5, Ionic may release a series of fixes and feature releases: 5.1, 5.2, 5.3, etc. During this time, Identity Vault version 5 is covered under the Active Support stage and all customer support services are available. When Identity Vault 6 is released, Identity Vault 5 will enter Long Term Support for 12 months and will continue to receive critical bug fixes. You will still be able to receive support through our customer support as well during this period as long as your support contract is still active. At the end of the 12 month period, Identity Vault 5 will move from Long Term Support to Not Supported and no additional support will be provided through Ionic customer support. This support policy covers all products currently supported as of the time of publication and beyond. Ionic reserves the right to make changes to this Support Policy. It is intended exclusively for customers who have purchased Ionic Enterprise products and is not applicable to any open source products that Ionic may maintain. The support status of current and legacy versions will be updated to reflect any changes. Contents -------- * [Current Support Status](https://ionic.io/docs/secure-storage/support-policy#current-support-status) * [Support Policy](https://ionic.io/docs/secure-storage/support-policy#support-policy) * [Stage 1: Active Support](https://ionic.io/docs/secure-storage/support-policy#stage-1-active-support) * [Stage 2: Long Term Support](https://ionic.io/docs/secure-storage/support-policy#stage-2-long-term-support) * [Stage 3: Not Supported](https://ionic.io/docs/secure-storage/support-policy#stage-3-not-supported) --- # Demo App - Intune [Skip to main content](https://ionic.io/docs/intune/demo-app#) To see a working demo of Ionic's Intune integration for iOS and Android, explore the follow demo links: * [Angular Intune Demo](https://github.com/ionic-team/demo-intune-angular) repo with support for Capacitor and Cordova. * [React Intune Demo](https://github.com/ionic-team/demo-intune-react) repo with support for Capacitor and Cordova. These examples show how to use brokered authentication, acquiring access tokens, and some of the basic API calls available in the integration. --- # Azure Configuration - Intune [Skip to main content](https://ionic.io/docs/intune/azure#) Much of the work in enabling Intune and Microsoft Authentication support requires configuration in Azure AD and the Microsoft Endpoint Manager. This list of tasks can be shared with your Azure administrator if necessary to help correctly configure the backend to enable Intune and Microsoft Authentication to work correctly. Registering Apps[#](https://ionic.io/docs/intune/azure#registering-apps "Direct link to heading") -------------------------------------------------------------------------------------------------- Your apps need to be registered in Azure in two places: First, it must be registered in Azure AD under `Azure Active Directory` -> `App registrations` -> `Your App` -> `Authentication` -> `Platform configurations`. Additionally, the app must be registered in `Azure Active Directory` -> `Enterprise applications` -> `New Application` To correctly configure the app, you'll need to come ready with the Signature Hash for Android and the package and bundle ids for Android/iOS. Add new configurations for both iOS and Android as shown below (with an Android app for example): ![Android AAD MSAL Dashboard](https://ionic.io/docs/intune/assets/images/android-aad-msal-config-92e04109ceec7187bfacfa71d1e019d9.png) App Registration Configuration[#](https://ionic.io/docs/intune/azure#app-registration-configuration "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------------ This page is also where the necessary Redirect URI and JSON configuration for Android will be found. Make sure to grab these values when the app is registered: ![Android AAD MSAL Config JSON](https://ionic.io/docs/intune/assets/images/android-aad-msal-config-json-60965fc2e308e2dbb70bd1010853babc.png) Enabling Brokered Authentication[#](https://ionic.io/docs/intune/azure#enabling-brokered-authentication "Direct link to heading") ---------------------------------------------------------------------------------------------------------------------------------- Microsoft Authenticator must be enabled as an allowed authentication method in Azure under `Azure AD` -> `Security` -> `Authentication methods` -> `Policies`: ![Enable Brokered](https://ionic.io/docs/intune/assets/images/aad-enable-brokered-e279b38a4edefc31fc8c9d5d115923a7.png) Enable Access to the Microsoft Mobile Application Management API:[#](https://ionic.io/docs/intune/azure#enable-access-to-the-microsoft-mobile-application-management-api "Direct link to heading") --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- In the `API Permissions` section of the app registration in `Azure Active Directory` -> `App registrations` -> `Your app` -> `API permissions` must have access to the `Microsoft Mobile Application Management` API: ![Azure Troubleshooting 5000 ios](https://ionic.io/docs/intune/assets/images/ios-troubleshooting-5000-efe3f1af44ba0494b5f860aed4462751.png) User and Group Management[#](https://ionic.io/docs/intune/azure#user-and-group-management "Direct link to heading") -------------------------------------------------------------------------------------------------------------------- Users and Groups need to have access to the registered in in `Azure Active Directory` -> `Enterprise applications` -> `Your app` -> `Users and Groups` to make sure the correct users and groups are allowed access to the enterprise app. ![Azure Enterprise App](https://ionic.io/docs/intune/assets/images/aad-users-groups-410b373fe01070e46ffd2085feccb286.png) Creating App Protection Policies[#](https://ionic.io/docs/intune/azure#creating-app-protection-policies "Direct link to heading") ---------------------------------------------------------------------------------------------------------------------------------- To enforce Intune app protection policies for your application: 1. Navigate to the Microsoft Endpoint Manager admin center at [endpoint.microsoft.com](https://endpoint.microsoft.com/) 2. Go to **Apps** → **App protection policies** 3. Click **Create policy** and select the appropriate platform (iOS/iPadOS or Android) 4. Complete the policy creation wizard: * On **Step 1**, provide a name and description for your policy * On **Step 2 (Apps)**, click **Add apps** and select **Custom app** * Enter your app's bundle ID (for iOS) or package name (for Android) * On subsequent steps, configure the desired protection settings, data protection, access requirements, and conditional launch settings * On **Step 6 (Assignments)**, assign the policy to the appropriate user groups that will use your application 5. Review your settings and click **Create** to finalize the policy These policies will be applied to your app when users with assigned policies sign in to your Intune-enabled application. * [Registering Apps](https://ionic.io/docs/intune/azure#registering-apps) * [App Registration Configuration](https://ionic.io/docs/intune/azure#app-registration-configuration) * [Enabling Brokered Authentication](https://ionic.io/docs/intune/azure#enabling-brokered-authentication) * [Enable Access to the Microsoft Mobile Application Management API:](https://ionic.io/docs/intune/azure#enable-access-to-the-microsoft-mobile-application-management-api) * [User and Group Management](https://ionic.io/docs/intune/azure#user-and-group-management) * [Creating App Protection Policies](https://ionic.io/docs/intune/azure#creating-app-protection-policies) --- # Checkbox - Accessibility Guide [Skip to main content](https://ionic.io/docs/accessibility/ion-checkbox#) Ionic Framework version 7 introduces a simplification that will mean you can replace `ion-label` and use a `label` property instead. This change also improves how a screen reader will announce the component making the label part of the form control. Here are some examples of replacing Ionic v6 for the newer v7 style: --- # Installation - Intune [Skip to main content](https://ionic.io/docs/intune/installation#) Ionic's Intune integration supports [Capacitor](https://capacitorjs.com/) (strongly recommended), or Cordova. Capacitor[#](https://ionic.io/docs/intune/installation#capacitor "Direct link to heading") ------------------------------------------------------------------------------------------- To install the Intune plugin, your app must be using Capacitor 7.0.0 or above. You must also have [an active Ionic Enterprise install key](https://ionic.io/docs/supported-plugins/setup) with access to Intune. Once you have a key and your key has been associated with your app, install the main plugin package: In your app, run: npm install @ionic-enterprise/intune Copy Then make sure to sync your platforms per the [Capacitor development workflow](https://capacitorjs.com/docs/basics/workflow) . When finished, follow the steps to complete the native installation and configuration for [iOS](https://ionic.io/docs/intune/ios-installation) and/or [Android](https://ionic.io/docs/intune/android-installation) . Cordova[#](https://ionic.io/docs/intune/installation#cordova "Direct link to heading") --------------------------------------------------------------------------------------- Follow the [Cordova Installation](https://ionic.io/docs/intune/cordova) guide. * [Capacitor](https://ionic.io/docs/intune/installation#capacitor) * [Cordova](https://ionic.io/docs/intune/installation#cordova) --- # SDK Versions - Intune [Skip to main content](https://ionic.io/docs/intune/sdk-versions#) This plugin uses these SDKs: * Microsoft intune iOS SDK ([changelog](https://github.com/msintuneappsdk/ms-intune-app-sdk-ios/releases) ) * Microsoft intune Android SDK ([changelog](https://github.com/msintuneappsdk/ms-intune-app-sdk-android/releases) ) * MSAL iOS SDK: ([changelog](https://github.com/AzureAD/microsoft-authentication-library-for-objc/releases) ) * MSAL Android SDK: ([changelog](https://github.com/AzureAD/microsoft-authentication-library-for-android/releases) ) The following table shows SDK versions vs plugin version. | Plugin Version | iOS SDK Version | Android SDK Version | iOS MSAL Version | Android MSAL Version | | --- | --- | --- | --- | --- | | 7.x | 20.3.0 | 11.0.0 | 1.7.0 | 5.10.0 | | 6.x | 20.3.0 | 11.0.0 | 1.7.0 | 5.10.0 | | 5.x | 19.3.1 | 10.2.1 | 1.3.2 | 5.3.0 | | 4.x | 17.6.3 | 9.7.0 | 1.2.13 | 4.6.3 | | 3.x | 17.1.1 | 9.1.1 | 1.2.5 | 1.2.5 | | 2.x | 15.3.0 | 8.3.0 | 1.2.0 | 1.2.5 | --- # Brokered Auth - Intune [Skip to main content](https://ionic.io/docs/intune/brokered-auth#) Itune supports Brokered Auth through the Microsoft Authentication Library (MSAL), enabling users to authenticate with Microsoft Authenticator or the Intune Company Portal app. Enabling Brokered Auth in Azure AD[#](https://ionic.io/docs/intune/brokered-auth#enabling-brokered-auth-in-azure-ad "Direct link to heading") ---------------------------------------------------------------------------------------------------------------------------------------------- Enabling Brokered authentication starts in Azure in the Azure AD dashboard, and must be specifically turned on as an authentication option. To find this page in Azure, navigate to Azure AD -> Security -> Authentication methods -> Policies. ![Enable Brokered](https://ionic.io/docs/intune/assets/images/aad-enable-brokered-e279b38a4edefc31fc8c9d5d115923a7.png) Android[#](https://ionic.io/docs/intune/brokered-auth#android "Direct link to heading") ---------------------------------------------------------------------------------------- Brokered auth must be enabled locally in your MSAL config (located in `android/res/raw/auth_config.json` created in [this](https://ionic.io/docs/intune/android-installation#creating-configuration-json-file) step). Add this line: "broker_redirect_uri_registered": true Copy Ensure the correct `` have been added to the `AndroidManifest.xml` by following the Android Installation [instructions](https://ionic.io/docs/intune/android-installation) . iOS[#](https://ionic.io/docs/intune/brokered-auth#ios "Direct link to heading") -------------------------------------------------------------------------------- No further configuration is required to enable Brokered Auth. * [Enabling Brokered Auth in Azure AD](https://ionic.io/docs/intune/brokered-auth#enabling-brokered-auth-in-azure-ad) * [Android](https://ionic.io/docs/intune/brokered-auth#android) * [iOS](https://ionic.io/docs/intune/brokered-auth#ios) --- # Secure Storage - Secure Storage [Skip to main content](https://ionic.io/docs/secure-storage#__docusaurus_skipToContent_fallback) On this page Ionic Secure Storage is a cross-platform local database system for high performance, secure data storage on iOS and Android. It provides full SQL query and relational data support through [SQLite](https://www.sqlite.org/index.html) , as well as key/value support for simpler use cases. Full encryption support (using 256-bit AES) is provided out of the box for security sensitive applications. **Don't have a Secure Storage subscription?** [Try it free now](http://dashboard.ionicframework.com/personal/apps?native_trial=1) . While the Ionic Secure Storage SQL API is only available on iOS and Android, support for web storage is available when using the [key/value API](https://ionic.io/docs/secure-storage/key-value) , which will fall back to a web-friendly storage mechanism when running in a non-native browser environment. Secure Storage is built and supported by the Ionic team, and includes ongoing maintenance, security patches, and new features. Why Secure Storage?[​](https://ionic.io/docs/secure-storage#why-secure-storage "Direct link to Why Secure Storage?") --------------------------------------------------------------------------------------------------------------------- Most apps need to store data on the device, but there are a lot of choices for data storage. Secure Storage is a fast and easy way to incorporate secure, reliable, high performance data access in your app. Secure Storage's fully managed solution offers the following benefits: **Quick and easy deployment**: Save days or weeks of development time with a pre-built storage solution. With zero configuration, it's ready to deploy in minutes. Once deployed, leave maintenance and stability concerns to Ionic’s team of mobile security professionals and get back to focusing on your app's core features. **On-device data encryption**: Sensitive data is protected and kept securely on the device with 256-bit AES full database encryption. The powerful operating system-level security follows Apple and Google’s best practices. When paired with [Identity Vault](https://ionic.io/docs/identity-vault) , secure and access data using the app user's biometrics (fingerprint scan and facial recognition). **Offline-ready**: Since Secure Storage is capable of storing large amounts of data, your mobile apps always work and are always responsive – regardless of network connection.Data is stored on the local filesystem – outside the browser environment – and can be managed independently of the Ionic Secure Storage solution. How It Works[​](https://ionic.io/docs/secure-storage#how-it-works "Direct link to How It Works") ------------------------------------------------------------------------------------------------- SQLite is the most popular storage engine for mobile apps, by far, so it's a key part of the Secure Storage solution. Since it's a single file on the filesystem, it's easy to work with and move around (you can edit the database file using [DB Browser for SQLite](https://sqlitebrowser.org/) , for example). SQLite also offers transaction protection. Its serializable transactions are atomic, consistent, isolated, and durable (ACID). Thus, all changes within a single transaction in Secure Storage either occur completely or not at all, even if the act of writing the change out to the disk is interrupted by a program crash, an operating system crash, or a power failure. When you create (or initialize) the SQLite database, you specify the encryption key using the `key` parameter. With that set, all newly created data is encrypted automatically using 256-bit AES encryption. const db = await this.sqlite.create({ name: "mydb", location: "default", // Key/Password used to encrypt the database // Strongly recommended to use Identity Vault to manage this key: "password"});// Data inserted into software table is automatically encryptedthis.database.transaction((tx) => { tx.executeSql("INSERT INTO software (name, company, type, version) VALUES (?,?,?,?)", [ "secure-storage", "ionic", "native", "2.0"], (tx, result) => { });}); Note: Encryption Key Management[​](https://ionic.io/docs/secure-storage#note-encryption-key-management "Direct link to Note: Encryption Key Management") --------------------------------------------------------------------------------------------------------------------------------------------------------- Before you use Secure Storage, you need to figure out how you will manage your encryption key. Typically, managing encryption keys on the client can be incredibly challenging to get right. Thankfully, by using [Identity Vault](https://ionic.io/docs/identity-vault) in tandem with Ionic Secure Storage, teams can securely manage encryption keys to support online _and_ offline use cases using the full security features available on modern mobile devices and operating systems. If you choose to roll your own method of key management, be aware that, just like rolling your own encryption, there are many pitfalls to client-side key management that may defeat your encryption efforts. Some of those pitfalls include lack of integration with secure enclave device hardware, incorrect management of biometric credentials resulting in users accessing sensitive values from other users, and data exposure if a device is jailbroken or lost/stolen. Because of these challenges we strongly recommend against rolling your own key management system and recommend using Identity Vault instead. Reference Apps[​](https://ionic.io/docs/secure-storage#reference-apps "Direct link to Reference Apps") ------------------------------------------------------------------------------------------------------- While implementing Secure Storage, refer to [these reference apps](https://ionic.io/docs/secure-storage/reference-apps) for examples showcasing data encryption. Contents -------- * [Why Secure Storage?](https://ionic.io/docs/secure-storage#why-secure-storage) * [How It Works](https://ionic.io/docs/secure-storage#how-it-works) * [Note: Encryption Key Management](https://ionic.io/docs/secure-storage#note-encryption-key-management) * [Reference Apps](https://ionic.io/docs/secure-storage#reference-apps) --- # Encrypting Your App's Data | Ionic Secure Solutions Starter [Skip to main content](https://ionic.io/docs/enterprise-starter/identity-vault#) Ionic Secure Storage creates the ultimate protection when paired with [Ionic Identity Vault](https://ionic.io/products/identity-vault) . Identity Vault is an all-in-one frontend identity management system that combines security best practices and the latest in biometric authentication options for Ionic apps running on iOS and Android. The Vault manages secure user identity and session tokens, ensuring sensitive data is encrypted at rest, stored only in secure locations on the device, and unlocked only with biometric identity (TouchID/FaceID). Always-on Session Management safeguards data even when not using your app, with background screen protection for sensitive data and apps, and automatic logout based on inactivity time. Installing Identity Vault[#](https://ionic.io/docs/enterprise-starter/identity-vault#installing-identity-vault "Direct link to heading") ----------------------------------------------------------------------------------------------------------------------------------------- Identity Vault is added to your app in the same fashion as Auth Connect and Secure Storage: npm install @ionic-enterprise/identity-vaultnpx cap sync Copy Given our usage of Capacitor with this example as well, we will also need to update the iOS project's `Info.plist` file. The addition of the required FaceID Usage Description will look as follows: ios/App/App/Info.plist ...NSFaceIDUsageDescriptionUse Face ID to authenticate yourself and login... Copy For Android SDK 30+, this is configured in the build.gradle file for Capacitor. Capacitor 2 and above is supported. If using Capacitor 3, ensure Capacitor dependencies are >=3.0.2. Creating Key and Vault Services[#](https://ionic.io/docs/enterprise-starter/identity-vault#creating-key-and-vault-services "Direct link to heading") ----------------------------------------------------------------------------------------------------------------------------------------------------- Similarly to using Auth Connect and Secure Storage, we can create a few services that define multiple vaults, assist in creating each vault, and provide storage keys: ionic g service services/vault-factoryionic g service services/key-vaultionic g service services/session-vaultionic g service services/key Copy The purpose of the newly created `VaultFactoryService` is to accept `IdentityVaultConfig` options with a `create()` function and return either a `Vault` or `BrowserVault` object. Since we will have multiple vaults in our app, this avoids code duplication and simplifies the process: src/app/services/vault-factory.service.ts ...import { Capacitor } from '@capacitor/core';import { BrowserVault, IdentityVaultConfig, Vault,} from '@ionic-enterprise/identity-vault'; ...export class VaultFactoryService { constructor() {} create(config: IdentityVaultConfig): Vault | BrowserVault { return Capacitor.isNativePlatform() ? new Vault(config) : new BrowserVault(config); }} Copy Note that we are using the `BrowserVault` class when the application is running on the web. The `BrowserVault` allows us to continue to use our normal web-based development workflow. Again, `Capacitor` was used to here to determine which type of device the app is running on and configure the vault appropriately. With the `VaultFactoryService` create and the other services generated, we can step through creating the individual parts of each. Getting an Encryption Key[#](https://ionic.io/docs/enterprise-starter/identity-vault#getting-an-encryption-key "Direct link to heading") ----------------------------------------------------------------------------------------------------------------------------------------- You will notice in the section to follow that one of the vault's helper functions, `getDatabaseKey()`, uses the `KeyService`. The purpose of the `getDatabaseKey()` function is to retrieve an encryption key from on-device storage. If the key was previously stored in the vault, return it. Otherwise, use the `KeyService` to obtain a new encryption key and save it into the vault using the `setValue()` function: src/app/services/key-vault.service.ts public async getDatabaseKey(): Promise { let dbKey = await this.vault.getValue(this.encryptionKey); if (!dbKey) { dbKey = await this.keyService.get(); this.set(this.encryptionKey, dbKey); } return dbKey;} Copy The `get()` function within the `KeyService` will look as follows: src/app/services/key.service.ts import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root',})export class KeyService { // Generate an encryption key on the fly unique to the current app user // Reference: https://stackoverflow.com/a/2117523/180424 async get(): Promise { // generate a UUID v4 return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => { const r = Math.random() * 16 || 0; const v = c === 'x' ? r : (r && 0x3) || 0x8; return v.toString(16); }); }} Copy ##### note The above shows the approach of auto-generating a unique encryption key on demand, tied to the authenticated user. However, another approach could be to retrieve the key from a server through an API call. ### Define Key Vault Configuration[#](https://ionic.io/docs/enterprise-starter/identity-vault#define-key-vault-configuration "Direct link to heading") First things first, we need to define a configuration for the vault. The `key` gives the vault a name. The other properties provide a default behavior for our vault. The configuration shown below is not all inclusive, [there are additional properties](https://ionic.io/docs/identity-vault/interfaces/identityvaultconfig) that can be used. Further, the vault can also be dynamically through app usage if that suits your app's needs: src/app/services/key-vault.service.ts ... const vaultConfig: IdentityVaultConfig = { key: 'io.ionic.enterprisestarterkeys', type: VaultType.SecureStorage, deviceSecurityType: DeviceSecurityType.None, unlockVaultOnLoad: false,}; @Injectable({ providedIn: 'root' })export class KeyVaultService { ...} Copy ### Define Data Storage Key[#](https://ionic.io/docs/enterprise-starter/identity-vault#define-data-storage-key "Direct link to heading") Next, we define a key for storing data. All data within the vault is stored as a key-value pair and you can store multiple key-value pairs within a single vault if need be: src/app/services/key-vault.service.ts ... const databaseKey = 'database-key'; ...export class VaultService { ...} Copy ### Create the Key Vault[#](https://ionic.io/docs/enterprise-starter/identity-vault#create-the-key-vault "Direct link to heading") With the vault config defined, and a storage key that will be used to identity the data we need to grab from the vault, we can create the remainder of the key vault. The all encompassing result will look as follows: src/app/services/key-vault.service.ts ...const vaultConfig: IdentityVaultConfig = { key: 'io.ionic.enterprisestarterkeys', type: VaultType.SecureStorage, deviceSecurityType: DeviceSecurityType.None, unlockVaultOnLoad: false,}; const databaseKey = 'database-key';@Injectable({ providedIn: 'root',})export class KeyVaultService { private vault: Vault | BrowserVault; constructor( private keyService: KeyService, private vaultFactory: VaultFactoryService ) { this.vault = this.vaultFactory.create(vaultConfig); } public async getDatabaseKey(): Promise { let dbKey = await this.vault.getValue(databaseKey); if (!dbKey) { dbKey = await this.keyService.get(); this.vault.setValue(databaseKey, dbKey); } return dbKey; }} Copy Secure Storage with Encryption[#](https://ionic.io/docs/enterprise-starter/identity-vault#secure-storage-with-encryption "Direct link to heading") --------------------------------------------------------------------------------------------------------------------------------------------------- Bringing encryption full-circle, we can now utilize the `KeyVaultService` to upgrade the app's storage with an appropriately encrypted database key: src/app/services/storage.service.ts ...export class StorageService { private storage: Storage; private database: SQLiteObject; constructor( private ngStorage: Storage, private sqlite: SQLite, private keyVault: KeyVaultService ) { this.storage = new Storage({ driverOrder: [ Drivers.SecureStorage, Drivers.IndexedDB, Drivers.LocalStorage, ], }); this.init(); } private async init() { // Obtain encryption key const dbKey = await this.keyVault.getDatabaseKey(); // Initialize Ionic Storage for web and basic native support await this.ngStorage.defineDriver(IonicSecureStorageDriver); await this.ngStorage.setEncryptionKey(dbKey); this.storage = await this.ngStorage.create(); if (Capacitor.isNativePlatform()) { // Create or open a table try { const db = await this.sqlite.create({ name: 'enterprisestarter.db', location: 'default', // Key/Password used to encrypt the database // Strongly recommended to use Identity Vault to manage this key: dbKey, }); this.database = db; // Create our initial schema await db.executeSql( '', // Example: 'CREATE TABLE IF NOT EXISTS software(name, company, type, version)' [] ); } catch (e) { console.error('Unable to initialize database', e); } } }} Copy This shows how with Secure Storage and Identity Vault used in tandem developers can safely store and manage their encryption key on device, and enable biometric authentication to secure sensitive data against theft, loss, or jailbreaking. Next Up[#](https://ionic.io/docs/enterprise-starter/identity-vault#next-up "Direct link to heading") ----------------------------------------------------------------------------------------------------- With the `KeyVaultService` created, we can flesh out the `SessionVaultService` we generated previously. [Edit this page](https://github.com/ionic-team/ionic-enterprise-starter/tree/main/website/docs/identity-vault.md) * [Installing Identity Vault](https://ionic.io/docs/enterprise-starter/identity-vault#installing-identity-vault) * [Creating Key and Vault Services](https://ionic.io/docs/enterprise-starter/identity-vault#creating-key-and-vault-services) * [Getting an Encryption Key](https://ionic.io/docs/enterprise-starter/identity-vault#getting-an-encryption-key) * [Define Key Vault Configuration](https://ionic.io/docs/enterprise-starter/identity-vault#define-key-vault-configuration) * [Define Data Storage Key](https://ionic.io/docs/enterprise-starter/identity-vault#define-data-storage-key) * [Create the Key Vault](https://ionic.io/docs/enterprise-starter/identity-vault#create-the-key-vault) * [Secure Storage with Encryption](https://ionic.io/docs/enterprise-starter/identity-vault#secure-storage-with-encryption) * [Next Up](https://ionic.io/docs/enterprise-starter/identity-vault#next-up) --- # Cordova Installation - Intune [Skip to main content](https://ionic.io/docs/intune/cordova#) For teams using Cordova instead of [Capacitor](https://capacitorjs.com/) , follow the below instructions to install and configure the plugin. Note: We strongly recommend teams transition to [Capacitor](https://capacitorjs.com/) for the best experience with this and other Ionic native solutions. Important[#](https://ionic.io/docs/intune/cordova#important "Direct link to heading") -------------------------------------------------------------------------------------- Intune is a configuration-heavy service, and it is not feasible to create a Cordova plugin that automatically configures your app. Because of this, you _must_ check in your platforms folders to your code repository to avoid losing configuration changes. Do _not_ blow away your platforms folders (i.e. with `cordova platform rm`) unless you are ready to reconstruct the following configuration. Double check your `.gitignore` to make sure `platforms/` is not ignored. Install the Plugin[#](https://ionic.io/docs/intune/cordova#install-the-plugin "Direct link to heading") -------------------------------------------------------------------------------------------------------- Version 7.x of the plugin requires: * Cordova 13+ for Android * Cordova iOS 7+ * iOS deployment target of 14+ * Xcode 15+ ionic cordova plugin add @ionic-enterprise/intune --variable INTUNE_CLIENT_ID=AZURE_CLIENT_ID --variable INTUNE_ADAL_AUTHORITY=AZURE_ADAL_AUTHORITY --variable INTUNE_REDIRECT_URI_IOS=AZURE_AD_IOS_REDIRECT_URI --variable INTUNE_SIGNATURE_HASH=ANDROID_SIGNATURE_HASH Copy iOS[#](https://ionic.io/docs/intune/cordova#ios "Direct link to heading") -------------------------------------------------------------------------- No additional configuration necessary. The plugin will set the iOS deployment target to 14.0.0. Android[#](https://ionic.io/docs/intune/cordova#android "Direct link to heading") ---------------------------------------------------------------------------------- Ionic's Intune integration requires `cordova-android@13` or higher: cordova platform add android@13 Copy Then, follow the [Creating Configuration JSON File](https://ionic.io/docs/intune/android-installation#creating-configuration-json-file) instructions to create `auth_config.json` in a `raw` Android resources folder to finish installation. * [Important](https://ionic.io/docs/intune/cordova#important) * [Install the Plugin](https://ionic.io/docs/intune/cordova#install-the-plugin) * [iOS](https://ionic.io/docs/intune/cordova#ios) * [Android](https://ionic.io/docs/intune/cordova#android) --- # Intune - Intune [Skip to main content](https://ionic.io/docs/intune#) Ionic's Intune support makes it easy to add Intune MAM and Microsoft authentication features into your Ionic/Capacitor app, such as Intune security policies and brokered auth with Microsoft Authenticator and/or the Intune Company Portal app. **Interested in Intune support?** [Get in touch](https://ionic.io/contact/sales) . Intune support is built and supported by the Ionic's native mobile experts and includes ongoing updates and maintenance, including new API features, patches, updates, and compatibility upgrades for new iOS & Android releases. Why use Ionic's Intune support?[#](https://ionic.io/docs/intune#why-use-ionics-intune-support "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------ Microsoft Intune is a complex product, and integrating the native Intune App SDKs for iOS and Android along with authentication is very challenging and time consuming. With Ionic's Intune support, developers can get up and running with Intune integration in their app with considerably less work and native development experience required. Ionic's Intune support is practically drop-in ready for iOS and Android, with minimal native configuration required. The majority of the configuration required involves setting up the Azure AD and Intune policies in Azure that are unique to your organization. Intune App SDK vs App Wrapping Tool[#](https://ionic.io/docs/intune#intune-app-sdk-vs-app-wrapping-tool "Direct link to heading") ---------------------------------------------------------------------------------------------------------------------------------- Ionic's Intune support uses the Intune App SDK and is meant for apps that will build Intune functionality directly into their app at development time. It is _not_ meant for apps using the Intune App Wrapping tool which provides basic Intune support for apps that are already built. By using Ionic's Intune integration and the Intune App SDK, apps will have access to much more Intune functionality and Microsoft authentication and API access token support. * [Why use Ionic's Intune support?](https://ionic.io/docs/intune#why-use-ionics-intune-support) * [Intune App SDK vs App Wrapping Tool](https://ionic.io/docs/intune#intune-app-sdk-vs-app-wrapping-tool) --- # Setup App Tabs | Ionic Secure Solutions Starter [Skip to main content](https://ionic.io/docs/enterprise-starter/tabs#) ~_Insert Video of creatings tab pages_~ When the app was generated using the VSCode extension and the `tabs` starter template, a few default tabs were created. This came with some default routing configuration as well. In our app, we are going to have a Home Page, Search Page, and Account Page. Now, we can either rename what we already have. Or, we can create new pages, update the tabs routing, and delete what we don't need from the default setup. Create New Tabs[#](https://ionic.io/docs/enterprise-starter/tabs#create-new-tabs "Direct link to heading") ----------------------------------------------------------------------------------------------------------- In this example, let's create the new pages and update the default setup. To start we will issue a few commands to get the new pages generated: ionic g page pages/homeionic g page pages/searchionic g page pages/account Copy We can then update the `app-routing.module.ts` file routes array: src/app/app-routing.module.ts ...const routes: Routes = [ { path: 'tabs', loadChildren: () => import('./tabs/tabs.module').then((m) => m.TabsPageModule), }, { path: 'login', loadChildren: () => import('./pages/login/login.module').then((m) => m.LoginPageModule), }, { path: '', redirectTo: 'tabs', pathMatch: 'full' },];... Copy The above change sets us up nicely to eventually put a routing guard within the `tabs` path. Also, it ensures that when we already have a user logged in, we go directly to the first tab rather than going to the `/login` path, only to be redirected. The updates to the `tabs-routing.module.ts` file routes array will look as follows: src/app/tabs/tabs-routing.module.ts ...const routes: Routes = [ { path: '', component: TabsPage, children: [ { path: 'home', loadChildren: () => import('../pages/home/home.module').then((m) => m.HomePageModule), }, { path: 'search', loadChildren: () => import('../pages/search/search.module').then( (m) => m.SearchPageModule ), }, { path: 'account', loadChildren: () => import('../pages/account/account.module').then( (m) => m.AccountPageModule ), }, { path: '', redirectTo: '/tabs/home', pathMatch: 'full', }, ], },];... Copy Finally, we can update the `html` for the `tabs` to match these changes: src/app/tabs/tabs.page.html Home Search Account Copy With those changes made, the default tab folders/files that were generated in the beginning can be deleted. Configure Account Page[#](https://ionic.io/docs/enterprise-starter/tabs#configure-account-page "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------- The `AccountPage` is what will show the logged in user's information, as well as house the ability to log out. We can quickly add some logic to initialize the `user` object via the `AuthenticationService`: src/app/pages/account/account.page.ts import { Component, OnInit } from '@angular/core';import { AuthenticationService } from 'src/app/services/authentication.service'; @Component({ selector: 'app-account', templateUrl: './account.page.html', styleUrls: ['./account.page.scss'],})export class AccountPage implements OnInit { public user: any; constructor(private authService: AuthenticationService) {} async ngOnInit() { this.user = await this.authService.getIdToken(); }} Copy The `user`, on initialization of the `AccountPage`, will be populated with the details supplied through the `getIdToken()` function inherited in the `AuthenticationService` via the `IonicAuth` class. The `user` object will look something similar to the following: { "nickname": "user", "name": "Ion Enterprise", "picture": "https://s.gravatar.com/avatar/909f40778b1e201d1c1a7b1a5bf6f8b9?s=480&r=pg&d=https%3A%2F%2Fcdn.auth0.com%2Favatars%2Fus.png", "updated_at": "2022-05-04T14:13:39.987Z", "email": "user@enterprise.com", "email_verified": false, ...} Copy Rounding out the `AccountPage` logic, a `logout()` function can be added. This ultimately pushes the user back to the `LoginPage` upon click of a button: src/app/pages/account/account.page.ts async logout() { await this.authService.logout();} Copy Update Authentication Service[#](https://ionic.io/docs/enterprise-starter/tabs#update-authentication-service "Direct link to heading") --------------------------------------------------------------------------------------------------------------------------------------- With the `AccountPage` logic updated, the `AuthenticationService` needs to be amended: src/app/services/authentication.service.ts ...import { Router } from '@angular/router'; ...export class AuthenticationService extends IonicAuth { constructor(private router: Router) { super(Capacitor.isNativePlatform() ? nativeAuthOptions : webAuthOptions); } ... async onLogout() { return await this.router.navigate(['login']); }} Copy With the `onLogout()` function in place, we now have the ability to handle what should occur once the user has logged-out from Auth0. Account Page Layout[#](https://ionic.io/docs/enterprise-starter/tabs#account-page-layout "Direct link to heading") ------------------------------------------------------------------------------------------------------------------- Now, we will jump into the newly created `AccountPage` and quickly churn up a layout, with some minor styling, that will accommodate our needs: src/app/pages/account/account.page.html Account Account {{ user.name}} {{ user.email }} Copy src/app/pages/account/account.page.scss ion-card { margin-left: auto; margin-right: auto; max-width: 600px;} ion-avatar { margin: auto;} Copy With the `user` object populated on initialization of the `AccountPage`, we will be able to see logged-in user's info as well as have a functional button to have them log out: ![](https://ionic.io/docs/enterprise-starter/assets/images/account-page-f4f4e7ab05a372a71b881bb6f9bbd5d7.png) Next up[#](https://ionic.io/docs/enterprise-starter/tabs#next-up "Direct link to heading") ------------------------------------------------------------------------------------------- Given the current implementation of the `LoginPage` and `AccountPage` within our main `tabs`, we can now look to create a `guard` around the main app. Let's make the first of the security improvements! [Edit this page](https://github.com/ionic-team/ionic-enterprise-starter/tree/main/website/docs/tabs.md) * [Create New Tabs](https://ionic.io/docs/enterprise-starter/tabs#create-new-tabs) * [Configure Account Page](https://ionic.io/docs/enterprise-starter/tabs#configure-account-page) * [Update Authentication Service](https://ionic.io/docs/enterprise-starter/tabs#update-authentication-service) * [Account Page Layout](https://ionic.io/docs/enterprise-starter/tabs#account-page-layout) * [Next up](https://ionic.io/docs/enterprise-starter/tabs#next-up) --- # Apple Payment Pass - Supported Plugins [Skip to main content](https://ionic.io/docs/supported-plugins/apple-payment-pass#) This plugin provides support for adding credit/debit cards to Apple Wallet. It also can check if the credit/debit card exists in Wallet. ##### Important Note Adding payment passes requires a special entitlement issued by Apple. Your app must include this entitlement before you can use this class. For more information on requesting this entitlement, see the Card Issuers section at [https://developer.apple.com/apple-pay/](https://developer.apple.com/apple-pay/) . Installation[​](https://ionic.io/docs/supported-plugins/apple-payment-pass#installation "Direct link to heading") ------------------------------------------------------------------------------------------------------------------ If you have not already setup Ionic Enterprise in your app, [follow the one-time setup steps](https://ionic.io/docs/supported-plugins/setup) . Next, install the plugin: * Capacitor * Cordova npm install @ionic-enterprise/apple-payment-passnpx cap sync Copy ionic cordova plugin add @ionic-enterprise/apple-payment-pass Copy Usage[​](https://ionic.io/docs/supported-plugins/apple-payment-pass#usage "Direct link to heading") ---------------------------------------------------------------------------------------------------- ### Angular[​](https://ionic.io/docs/supported-plugins/apple-payment-pass#angular "Direct link to heading") ...import { Platform } from '@ionic/angular';import { ApplePaymentPass, RequestTemplate } from '@ionic-enterprise/apple-payment-pass/ngx';...class MyService { constructor(private platform: Platform, private paypass: ApplePaymentPass) { } addCardToWallet() { try { const response = await this.paypass.addPaymentPass({ userId: 1, appleWalletData: { certificates: [ RequestTemplate.CERTIFICATE_0, RequestTemplate.CERTIFICATE_1, ], nonce: RequestTemplate.NONCE, nonceSignature: RequestTemplate.NONCE_SIGNATURE }, }); } catch (e) { if (e.type === "ServerError") { console.error(`Server Responded with status: ${e.statusCode} and body ${e.body}`); } }} Copy ### ES2015+/Typescript[​](https://ionic.io/docs/supported-plugins/apple-payment-pass#es2015typescript "Direct link to heading") ...import { ApplePaymentPass, RequestTemplate } from '@ionic-enterprise/apple-payment-pass';...try { const response = await ApplePaymentPass.addPaymentPass({ userId: 1, appleWalletData: { certificates: [ RequestTemplate.CERTIFICATE_0, RequestTemplate.CERTIFICATE_1, ], nonce: RequestTemplate.NONCE, nonceSignature: RequestTemplate.NONCE_SIGNATURE }, });} catch (e) { if (e.type === "ServerError") { console.error(`Server Responded with status: ${e.statusCode} and body ${e.body}`); }} Copy ### Vanilla JS[​](https://ionic.io/docs/supported-plugins/apple-payment-pass#vanilla-js "Direct link to heading") ApplePaymentPass.addPaymentPass({ userId: 1, appleWalletData: { certificates: [ ApplePaymentPass.template.CERTIFICATE_0, ApplePaymentPass.template.CERTIFICATE_1, ], nonce: ApplePaymentPass.template.NONCE, nonceSignature: ApplePaymentPass.template.NONCE_SIGNATURE },}).then( (cardStatus) => { console.log("Success Adding Card: ", cardStatus); }) .catch( (e) => { if (e.type === "ServerError") { console.error(`Server Responded with status: ${e.statusCode} and body ${e.body}`); } }); Copy ### Card Addition[​](https://ionic.io/docs/supported-plugins/apple-payment-pass#card-addition "Direct link to heading") Call with the configuration data needed to instantiate a new PKAddPaymentPassViewController object and complete the HTTP request to do the handshake with your server. This method provides the data needed to create a request to add your payment pass (credit/debit card). const card = { cardholderName: 'Test User', primaryAccountSuffix: '1234', localizedDescription: 'Description of payment card', paymentNetwork: 'VISA' } const options = { headers: { 'Authorization': 'Bearer xxxxxx', 'Content-Type': 'application/json' }, url: 'https://my.api.com/v1/cards', method: 'POST', // This is a hybrid template with the data you need prefilled // and the ApplePaymentPass.CONSTANTS will be filled in during the handshake. body: { userId: 1, appleWalletData: { certificates: [ ApplePaymentPass.CERTIFICATE_0, ApplePaymentPass.CERTIFICATE_1, ], nonce: ApplePaymentPass.NONCE, nonceSignature: ApplePaymentPass.NONCE_SIGNATURE }, }, card: card, }; const passData = await ApplePaymentPass.addPaymentPass(options); Copy ### API Response[​](https://ionic.io/docs/supported-plugins/apple-payment-pass#api-response "Direct link to heading") The response from your API is expected to be valid JSON with 3 fields in the body ([activationData](https://developer.apple.com/documentation/passkit/pkaddpaymentpassrequest/1615914-activationdata) , [encyptedPassData](https://developer.apple.com/documentation/passkit/pkaddpaymentpassrequest/1615926-encryptedpassdata) , [ephemeralPublicKey](https://developer.apple.com/documentation/passkit/pkaddpaymentpassrequest/1615952-ephemeralpublickey) ). These are the fields expected by the [PKAddPaymentPassRequest](https://developer.apple.com/documentation/passkit/pkaddpaymentpassrequest) that iOS requires be used to add the card to the wallet. // expected response{ "activationData": "xxxx", "encryptedPassData": "xxxx", "ephemeralPublicKey": "xxxx",} Copy Index[​](https://ionic.io/docs/supported-plugins/apple-payment-pass#index "Direct link to heading") ---------------------------------------------------------------------------------------------------- ### Enumerations[​](https://ionic.io/docs/supported-plugins/apple-payment-pass#enumerations "Direct link to heading") * [RequestTemplate](https://ionic.io/docs/supported-plugins/apple-payment-pass#requesttemplate) ### Classes[​](https://ionic.io/docs/supported-plugins/apple-payment-pass#classes "Direct link to heading") * [ApplePaymentPass](https://ionic.io/docs/supported-plugins/apple-payment-pass#applepaymentpass) ### Interfaces[​](https://ionic.io/docs/supported-plugins/apple-payment-pass#interfaces "Direct link to heading") * [AddPassOptions](https://ionic.io/docs/supported-plugins/apple-payment-pass#addpassoptions) * [AddPassResponse](https://ionic.io/docs/supported-plugins/apple-payment-pass#addpassresponse) * [CardData](https://ionic.io/docs/supported-plugins/apple-payment-pass#carddata) * [DelegateError](https://ionic.io/docs/supported-plugins/apple-payment-pass#delegateerror) * [Headers](https://ionic.io/docs/supported-plugins/apple-payment-pass#headers) * [ServerError](https://ionic.io/docs/supported-plugins/apple-payment-pass#servererror) ### Type aliases[​](https://ionic.io/docs/supported-plugins/apple-payment-pass#type-aliases "Direct link to heading") * [ActivationState](https://ionic.io/docs/supported-plugins/apple-payment-pass#activationstate) * * * Enumerations[​](https://ionic.io/docs/supported-plugins/apple-payment-pass#enumerations-1 "Direct link to heading") -------------------------------------------------------------------------------------------------------------------- ### RequestTemplate[​](https://ionic.io/docs/supported-plugins/apple-payment-pass#requesttemplate "Direct link to heading") **RequestTemplate**: Constants used to define the shape of the body used during the request to the server ### CERTIFICATE\_0[​](https://ionic.io/docs/supported-plugins/apple-payment-pass#certificate_0 "Direct link to heading") **CERTIFICATE\_0**: = "$certificates.0" Constant used in the body template that represents the first item in the certificates array returned by the PKAddPaymentPassViewController. * * * ### CERTIFICATE\_1[​](https://ionic.io/docs/supported-plugins/apple-payment-pass#certificate_1 "Direct link to heading") **CERTIFICATE\_1**: = "$certificates.1" Constant used in the body template that represents the second item in the certificates array returned by the PKAddPaymentPassViewController. * * * ### NONCE[​](https://ionic.io/docs/supported-plugins/apple-payment-pass#nonce "Direct link to heading") **NONCE**: = "$nonceString" Constant used in the body template that represents the nonce returned by the PKAddPaymentPassViewController. * * * ### NONCE\_SIGNATURE[​](https://ionic.io/docs/supported-plugins/apple-payment-pass#nonce_signature "Direct link to heading") **NONCE\_SIGNATURE**: = "$nonceSignature" Constant used in the body template that represents the nonceSignature returned by the PKAddPaymentPassViewController. * * * * * * Classes[​](https://ionic.io/docs/supported-plugins/apple-payment-pass#classes-1 "Direct link to heading") ---------------------------------------------------------------------------------------------------------- ### ApplePaymentPass[​](https://ionic.io/docs/supported-plugins/apple-payment-pass#applepaymentpass "Direct link to heading") **ApplePaymentPass**: This plugin provides support for adding credit/debit cards to Apple Wallet. It also can check if the credit/debit card exists in Wallet. ### template[​](https://ionic.io/docs/supported-plugins/apple-payment-pass#template "Direct link to heading") **● template**: _[RequestTemplate](https://ionic.io/docs/supported-plugins/apple-payment-pass#requesttemplate) _ = RequestTemplate * * * ### addPaymentPass[​](https://ionic.io/docs/supported-plugins/apple-payment-pass#addpaymentpass "Direct link to heading") ▸ **addPaymentPass**(options: _[AddPassOptions](https://ionic.io/docs/supported-plugins/apple-payment-pass#addpassoptions) _): `Promise`<[AddPassResponse](https://ionic.io/docs/supported-plugins/apple-payment-pass#addpassresponse) \> This function accepts both the card data and information required to make the http request to the server in order to use PKAddPaymentPassViewController object to add a payment pass to the apple wallet. _**throws**_: \* [ServerError](https://ionic.io/docs/supported-plugins/apple-payment-pass#servererror) [DelegateError](https://ionic.io/docs/supported-plugins/apple-payment-pass#delegateerror) **Parameters:** | Name | Type | Description | | --- | --- | --- | | options | [AddPassOptions](https://ionic.io/docs/supported-plugins/apple-payment-pass#addpassoptions) | The [AddPassOptions](https://ionic.io/docs/supported-plugins/apple-payment-pass#addpassoptions)
object to configure the PKAddPaymentPassViewController and setup the call to the server. | **Returns:** `Promise`<[AddPassResponse](https://ionic.io/docs/supported-plugins/apple-payment-pass#addpassresponse) \> * An object with the pass information * * * ### available[​](https://ionic.io/docs/supported-plugins/apple-payment-pass#available "Direct link to heading") ▸ **available**(): `Promise`<`boolean`\> A function to determine if the current device supports adding a payment pass **Returns:** `Promise`<`boolean`\> whether or not a pay pass can be added * * * ### availableProvider[​](https://ionic.io/docs/supported-plugins/apple-payment-pass#availableprovider "Direct link to heading") ▸ **availableProvider**(options: _`object`_): `Promise`<`boolean`\> A function to determine if the card has already been provisioned for the device. **Parameters:** **options: `object`** An object with the primary account identifier for the card. | Name | Type | | --- | --- | | primaryAccountIdentifier | `string` | **Returns:** `Promise`<`boolean`\> whether or not a pay can be added, throws an error if the card is already added * * * * * * Interfaces[​](https://ionic.io/docs/supported-plugins/apple-payment-pass#interfaces-1 "Direct link to heading") ---------------------------------------------------------------------------------------------------------------- ### AddPassOptions[​](https://ionic.io/docs/supported-plugins/apple-payment-pass#addpassoptions "Direct link to heading") **AddPassOptions**: The options interface to pass to the [addPaymentPass](https://ionic.io/docs/supported-plugins/apple-payment-pass#applepaymentpass.addpaymentpass) function. ### body[​](https://ionic.io/docs/supported-plugins/apple-payment-pass#body "Direct link to heading") **● body**: _`any`_ A templated request body to send to your server. include any additional fields and use the constansts [CERTIFICATE\_0](https://ionic.io/docs/supported-plugins/apple-payment-pass#requesttemplate.certificate_0) , [CERTIFICATE\_1](https://ionic.io/docs/supported-plugins/apple-payment-pass#requesttemplate.certificate_1) , [NONCE](https://ionic.io/docs/supported-plugins/apple-payment-pass#requesttemplate.nonce) , [NONCE\_SIGNATURE](https://ionic.io/docs/supported-plugins/apple-payment-pass#requesttemplate.nonce_signature) _**usage**_: const body = { userId: 1, cardId: 'xxxxx', appleWalletData: { certs: [ RequestTemplate.CERTIFICATE_0, RequestTemplate.CERTIFICATE_1 ], nonce: RequestTemplate.NONCE, nonceSignature: RequestTemplate.NONCE_SIGNATURE, }} Copy * * * ### card[​](https://ionic.io/docs/supported-plugins/apple-payment-pass#card "Direct link to heading") **● card**: _[CardData](https://ionic.io/docs/supported-plugins/apple-payment-pass#carddata) _ The card data * * * ### headers[​](https://ionic.io/docs/supported-plugins/apple-payment-pass#headers "Direct link to heading") **● headers**: _[Headers](https://ionic.io/docs/supported-plugins/apple-payment-pass#headers) _ An object with the headers required for the server request. * * * ### method[​](https://ionic.io/docs/supported-plugins/apple-payment-pass#method "Direct link to heading") **● method**: _`string`_ The HTTP method to use ex. `POST` * * * ### url[​](https://ionic.io/docs/supported-plugins/apple-payment-pass#url "Direct link to heading") **● url**: _`string`_ The url to hit ex. `https://my.api.com/v1/add/applepay/card` * * * * * * ### AddPassResponse[​](https://ionic.io/docs/supported-plugins/apple-payment-pass#addpassresponse "Direct link to heading") **AddPassResponse**: The response from adding the pass with the pass data ### activationState[​](https://ionic.io/docs/supported-plugins/apple-payment-pass#activationstate "Direct link to heading") **● activationState**: _[ActivationState](https://ionic.io/docs/supported-plugins/apple-payment-pass#activationstate) _ The activation state of the card * * * ### deviceAccountIdentifier[​](https://ionic.io/docs/supported-plugins/apple-payment-pass#deviceaccountidentifier "Direct link to heading") **● deviceAccountIdentifier**: _`string`_ The device account identifier. * * * ### deviceAccountNumberSuffix[​](https://ionic.io/docs/supported-plugins/apple-payment-pass#deviceaccountnumbersuffix "Direct link to heading") **● deviceAccountNumberSuffix**: _`string`_ The device account number suffix * * * ### deviceName[​](https://ionic.io/docs/supported-plugins/apple-payment-pass#devicename "Direct link to heading") **● deviceName**: _`string`_ The device name. * * * ### primaryAccountIdentifier[​](https://ionic.io/docs/supported-plugins/apple-payment-pass#primaryaccountidentifier "Direct link to heading") **● primaryAccountIdentifier**: _`string`_ The primary account identifier * * * ### primaryAccountNumberSuffix[​](https://ionic.io/docs/supported-plugins/apple-payment-pass#primaryaccountnumbersuffix "Direct link to heading") **● primaryAccountNumberSuffix**: _`string`_ The primary account number suffix * * * * * * ### CardData[​](https://ionic.io/docs/supported-plugins/apple-payment-pass#carddata "Direct link to heading") **CardData**: The card data for the PKAddPaymentPassViewController ### `` cardholderName[​](https://ionic.io/docs/supported-plugins/apple-payment-pass#optional-cardholdername "Direct link to heading") **● cardholderName**: _`undefined` | `string`_ The cardholder name * * * ### `` localizedDescription[​](https://ionic.io/docs/supported-plugins/apple-payment-pass#optional-localizeddescription "Direct link to heading") **● localizedDescription**: _`undefined` | `string`_ A short description of the card. * * * ### `` paymentNetwork[​](https://ionic.io/docs/supported-plugins/apple-payment-pass#optional-paymentnetwork "Direct link to heading") **● paymentNetwork**: _`undefined` | `string`_ Filters the networks shown in the introduction view to this single network. ex.`VISA \| MASTERCARD` * * * ### `` primaryAccountIdentifier[​](https://ionic.io/docs/supported-plugins/apple-payment-pass#optional-primaryaccountidentifier "Direct link to heading") **● primaryAccountIdentifier**: _`undefined` | `string`_ Filters the device and attached devices that already have this card provisioned. No filter is applied if the parameter is omitted * * * ### `` primaryAccountSuffix[​](https://ionic.io/docs/supported-plugins/apple-payment-pass#optional-primaryaccountsuffix "Direct link to heading") **● primaryAccountSuffix**: _`undefined` | `string`_ Last 4/5 digits of PAN. The last four or five digits of the PAN. Presented to the user with dots prepended to indicate that it is a suffix. * * * * * * ### DelegateError[​](https://ionic.io/docs/supported-plugins/apple-payment-pass#delegateerror "Direct link to heading") **DelegateError**: Error thrown by [addPaymentPass](https://ionic.io/docs/supported-plugins/apple-payment-pass#applepaymentpass.addpaymentpass) when the PKAddPaymentPassViewController fails to add the card to the wallet ### body[​](https://ionic.io/docs/supported-plugins/apple-payment-pass#body-1 "Direct link to heading") **● body**: _`object`_ The error message #### Type declaration[​](https://ionic.io/docs/supported-plugins/apple-payment-pass#type-declaration "Direct link to heading") message: `string` * * * ### statusCode[​](https://ionic.io/docs/supported-plugins/apple-payment-pass#statuscode "Direct link to heading") **● statusCode**: _`number`_ The error code * * * ### type[​](https://ionic.io/docs/supported-plugins/apple-payment-pass#type "Direct link to heading") **● type**: _"DelegateError"_ The type of the error * * * * * * ### Headers[​](https://ionic.io/docs/supported-plugins/apple-payment-pass#headers-1 "Direct link to heading") **Headers**: An object with the headers required for the server request. _**usage**_: const headers = {'Authorization': 'Bearer xxxxx','Content-Type': 'application/json',...} Copy * * * ### ServerError[​](https://ionic.io/docs/supported-plugins/apple-payment-pass#servererror "Direct link to heading") **ServerError**: Error thrown by [addPaymentPass](https://ionic.io/docs/supported-plugins/apple-payment-pass#applepaymentpass.addpaymentpass) when server responds with a HTTP status code >= 400 ### body[​](https://ionic.io/docs/supported-plugins/apple-payment-pass#body-2 "Direct link to heading") **● body**: _`any`_ The body return by the server * * * ### statusCode[​](https://ionic.io/docs/supported-plugins/apple-payment-pass#statuscode-1 "Direct link to heading") **● statusCode**: _`number`_ The status code returned from the server * * * ### type[​](https://ionic.io/docs/supported-plugins/apple-payment-pass#type-1 "Direct link to heading") **● type**: _"ServerError"_ The type of the error * * * * * * Type aliases[​](https://ionic.io/docs/supported-plugins/apple-payment-pass#type-aliases-1 "Direct link to heading") -------------------------------------------------------------------------------------------------------------------- ### ActivationState[​](https://ionic.io/docs/supported-plugins/apple-payment-pass#activationstate-1 "Direct link to heading") **Ƭ ActivationState**: _"activated" | "activating" | "suspended" | "deactivated" | "requires-activation" | "unknown"_ The activation state of the provisioned card * * * Change Log[​](https://ionic.io/docs/supported-plugins/apple-payment-pass#change-log "Direct link to heading") -------------------------------------------------------------------------------------------------------------- ### \[1.1.0\] (2020-07-28)[​](https://ionic.io/docs/supported-plugins/apple-payment-pass#110-2020-07-28 "Direct link to heading") ### Features[​](https://ionic.io/docs/supported-plugins/apple-payment-pass#features "Direct link to heading") * support for Angular Ivy ### \[1.0.2\] (2019-04-27)[​](https://ionic.io/docs/supported-plugins/apple-payment-pass#102-2019-04-27 "Direct link to heading") ### Bug Fixes[​](https://ionic.io/docs/supported-plugins/apple-payment-pass#bug-fixes "Direct link to heading") * Fixed issue where cordova plugin id was being incorrectly set by release script. ### \[1.0.0\] (2019-04-27)[​](https://ionic.io/docs/supported-plugins/apple-payment-pass#100-2019-04-27 "Direct link to heading") ### Bug Fixes[​](https://ionic.io/docs/supported-plugins/apple-payment-pass#bug-fixes-1 "Direct link to heading") * **iOS:** Fix issues where nonce string could be incorrectly replaced and errors from server weren't properly handled ### Features[​](https://ionic.io/docs/supported-plugins/apple-payment-pass#features-1 "Direct link to heading") * Added typed imports for [Angular](https://ionic.io/docs/supported-plugins/apple-payment-pass#angular) , [ES2015+/Typescript](https://ionic.io/docs/supported-plugins/apple-payment-pass#es2015-typescript) , and [Vanilla JS](https://ionic.io/docs/supported-plugins/apple-payment-pass#vanilla-js) , closes \[#es2015\] ### BREAKING CHANGES[​](https://ionic.io/docs/supported-plugins/apple-payment-pass#breaking-changes "Direct link to heading") * Changed package name from `@ionic-enterprise/apple-wallet` to `@ionic-enterprise/apple-payment-pass` and the main class from `AppleWallet` to `ApplePaymentPass`. See updated [usage docs](https://ionic.io/docs/supported-plugins/apple-payment-pass#usage) . * [Usage](https://ionic.io/docs/supported-plugins/apple-payment-pass#usage) * [Angular](https://ionic.io/docs/supported-plugins/apple-payment-pass#angular) * [ES2015+/Typescript](https://ionic.io/docs/supported-plugins/apple-payment-pass#es2015typescript) * [Vanilla JS](https://ionic.io/docs/supported-plugins/apple-payment-pass#vanilla-js) * [Card Addition](https://ionic.io/docs/supported-plugins/apple-payment-pass#card-addition) * [API Response](https://ionic.io/docs/supported-plugins/apple-payment-pass#api-response) * [Index](https://ionic.io/docs/supported-plugins/apple-payment-pass#index) * [Enumerations](https://ionic.io/docs/supported-plugins/apple-payment-pass#enumerations) * [Classes](https://ionic.io/docs/supported-plugins/apple-payment-pass#classes) * [Interfaces](https://ionic.io/docs/supported-plugins/apple-payment-pass#interfaces) * [Type aliases](https://ionic.io/docs/supported-plugins/apple-payment-pass#type-aliases) * [Enumerations](https://ionic.io/docs/supported-plugins/apple-payment-pass#enumerations-1) * [RequestTemplate](https://ionic.io/docs/supported-plugins/apple-payment-pass#requesttemplate) * [CERTIFICATE\_0](https://ionic.io/docs/supported-plugins/apple-payment-pass#certificate_0) * [CERTIFICATE\_1](https://ionic.io/docs/supported-plugins/apple-payment-pass#certificate_1) * [NONCE](https://ionic.io/docs/supported-plugins/apple-payment-pass#nonce) * [NONCE\_SIGNATURE](https://ionic.io/docs/supported-plugins/apple-payment-pass#nonce_signature) * [Classes](https://ionic.io/docs/supported-plugins/apple-payment-pass#classes-1) * [ApplePaymentPass](https://ionic.io/docs/supported-plugins/apple-payment-pass#applepaymentpass) * [template](https://ionic.io/docs/supported-plugins/apple-payment-pass#template) * [addPaymentPass](https://ionic.io/docs/supported-plugins/apple-payment-pass#addpaymentpass) * [available](https://ionic.io/docs/supported-plugins/apple-payment-pass#available) * [availableProvider](https://ionic.io/docs/supported-plugins/apple-payment-pass#availableprovider) * [Interfaces](https://ionic.io/docs/supported-plugins/apple-payment-pass#interfaces-1) * [AddPassOptions](https://ionic.io/docs/supported-plugins/apple-payment-pass#addpassoptions) * [body](https://ionic.io/docs/supported-plugins/apple-payment-pass#body) * [card](https://ionic.io/docs/supported-plugins/apple-payment-pass#card) * [headers](https://ionic.io/docs/supported-plugins/apple-payment-pass#headers) * [method](https://ionic.io/docs/supported-plugins/apple-payment-pass#method) * [url](https://ionic.io/docs/supported-plugins/apple-payment-pass#url) * [AddPassResponse](https://ionic.io/docs/supported-plugins/apple-payment-pass#addpassresponse) * [activationState](https://ionic.io/docs/supported-plugins/apple-payment-pass#activationstate) * [deviceAccountIdentifier](https://ionic.io/docs/supported-plugins/apple-payment-pass#deviceaccountidentifier) * [deviceAccountNumberSuffix](https://ionic.io/docs/supported-plugins/apple-payment-pass#deviceaccountnumbersuffix) * [deviceName](https://ionic.io/docs/supported-plugins/apple-payment-pass#devicename) * [primaryAccountIdentifier](https://ionic.io/docs/supported-plugins/apple-payment-pass#primaryaccountidentifier) * [primaryAccountNumberSuffix](https://ionic.io/docs/supported-plugins/apple-payment-pass#primaryaccountnumbersuffix) * [CardData](https://ionic.io/docs/supported-plugins/apple-payment-pass#carddata) * [`` cardholderName](https://ionic.io/docs/supported-plugins/apple-payment-pass#optional-cardholdername) * [`` localizedDescription](https://ionic.io/docs/supported-plugins/apple-payment-pass#optional-localizeddescription) * [`` paymentNetwork](https://ionic.io/docs/supported-plugins/apple-payment-pass#optional-paymentnetwork) * [`` primaryAccountIdentifier](https://ionic.io/docs/supported-plugins/apple-payment-pass#optional-primaryaccountidentifier) * [`` primaryAccountSuffix](https://ionic.io/docs/supported-plugins/apple-payment-pass#optional-primaryaccountsuffix) * [DelegateError](https://ionic.io/docs/supported-plugins/apple-payment-pass#delegateerror) * [body](https://ionic.io/docs/supported-plugins/apple-payment-pass#body-1) * [statusCode](https://ionic.io/docs/supported-plugins/apple-payment-pass#statuscode) * [type](https://ionic.io/docs/supported-plugins/apple-payment-pass#type) * [Headers](https://ionic.io/docs/supported-plugins/apple-payment-pass#headers-1) * [ServerError](https://ionic.io/docs/supported-plugins/apple-payment-pass#servererror) * [body](https://ionic.io/docs/supported-plugins/apple-payment-pass#body-2) * [statusCode](https://ionic.io/docs/supported-plugins/apple-payment-pass#statuscode-1) * [type](https://ionic.io/docs/supported-plugins/apple-payment-pass#type-1) * [Type aliases](https://ionic.io/docs/supported-plugins/apple-payment-pass#type-aliases-1) * [ActivationState](https://ionic.io/docs/supported-plugins/apple-payment-pass#activationstate-1) * [Change Log](https://ionic.io/docs/supported-plugins/apple-payment-pass#change-log) * [1.1.0 (2020-07-28)](https://ionic.io/docs/supported-plugins/apple-payment-pass#110-2020-07-28) * [Features](https://ionic.io/docs/supported-plugins/apple-payment-pass#features) * [1.0.2 (2019-04-27)](https://ionic.io/docs/supported-plugins/apple-payment-pass#102-2019-04-27) * [Bug Fixes](https://ionic.io/docs/supported-plugins/apple-payment-pass#bug-fixes) * [1.0.0 (2019-04-27)](https://ionic.io/docs/supported-plugins/apple-payment-pass#100-2019-04-27) * [Bug Fixes](https://ionic.io/docs/supported-plugins/apple-payment-pass#bug-fixes-1) * [Features](https://ionic.io/docs/supported-plugins/apple-payment-pass#features-1) * [BREAKING CHANGES](https://ionic.io/docs/supported-plugins/apple-payment-pass#breaking-changes) --- # Apple Payment Pass - Supported Plugins [Skip to main content](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#) This plugin provides support for adding credit/debit cards to Apple Wallet. It also can check if the credit/debit card exists in Wallet. ##### Important Note Adding payment passes requires a special entitlement issued by Apple. Your app must include this entitlement before you can use this class. For more information on requesting this entitlement, see the Card Issuers section at [https://developer.apple.com/apple-pay/](https://developer.apple.com/apple-pay/) . Usage[​](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#usage "Direct link to heading") ----------------------------------------------------------------------------------------------------------------------------- ### Angular[​](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#angular "Direct link to heading") ...import { Platform } from '@ionic/angular';import { ApplePaymentPass, RequestTemplate } from '@ionic-enterprise/apple-payment-pass/ngx';...class MyService { constructor(private platform: Platform, private paypass: ApplePaymentPass) { } addCardToWallet() { try { const response = await this.paypass.addPaymentPass({ userId: 1, appleWalletData: { certificates: [ RequestTemplate.CERTIFICATE_0, RequestTemplate.CERTIFICATE_1, ], nonce: RequestTemplate.NONCE, nonceSignature: RequestTemplate.NONCE_SIGNATURE }, }); } catch (e) { if (e.type === "ServerError") { console.error(`Server Responded with status: ${e.statusCode} and body ${e.body}`); } }} Copy ### ES2015+/Typescript[​](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#es2015typescript "Direct link to heading") ...import { ApplePaymentPass, RequestTemplate } from '@ionic-enterprise/apple-payment-pass';...try { const response = await ApplePaymentPass.addPaymentPass({ userId: 1, appleWalletData: { certificates: [ RequestTemplate.CERTIFICATE_0, RequestTemplate.CERTIFICATE_1, ], nonce: RequestTemplate.NONCE, nonceSignature: RequestTemplate.NONCE_SIGNATURE }, });} catch (e) { if (e.type === "ServerError") { console.error(`Server Responded with status: ${e.statusCode} and body ${e.body}`); }} Copy ### Vanilla JS[​](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#vanilla-js "Direct link to heading") ApplePaymentPass.addPaymentPass({ userId: 1, appleWalletData: { certificates: [ ApplePaymentPass.template.CERTIFICATE_0, ApplePaymentPass.template.CERTIFICATE_1, ], nonce: ApplePaymentPass.template.NONCE, nonceSignature: ApplePaymentPass.template.NONCE_SIGNATURE },}).then( (cardStatus) => { console.log("Success Adding Card: ", cardStatus); }) .catch( (e) => { if (e.type === "ServerError") { console.error(`Server Responded with status: ${e.statusCode} and body ${e.body}`); } }); Copy ### Card Addition[​](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#card-addition "Direct link to heading") Call with the configuration data needed to instantiate a new PKAddPaymentPassViewController object and complete the HTTP request to do the handshake with your server. This method provides the data needed to create a request to add your payment pass (credit/debit card). const card = { cardholderName: 'Test User', primaryAccountSuffix: '1234', localizedDescription: 'Description of payment card', paymentNetwork: 'VISA' } const options = { headers: { 'Authorization': 'Bearer xxxxxx', 'Content-Type': 'application/json' }, url: 'https://my.api.com/v1/cards', method: 'POST', // This is a hybrid template with the data you need prefilled // and the ApplePaymentPass.CONSTANTS will be filled in during the handshake. body: { userId: 1, appleWalletData: { certificates: [ ApplePaymentPass.CERTIFICATE_0, ApplePaymentPass.CERTIFICATE_1, ], nonce: ApplePaymentPass.NONCE, nonceSignature: ApplePaymentPass.NONCE_SIGNATURE }, }, card: card, }; const passData = await ApplePaymentPass.addPaymentPass(options); Copy Index[​](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#index "Direct link to heading") ----------------------------------------------------------------------------------------------------------------------------- ### Enumerations[​](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#enumerations "Direct link to heading") * [RequestTemplate](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#requesttemplate) ### Classes[​](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#classes "Direct link to heading") * [ApplePaymentPass](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#applepaymentpass) ### Interfaces[​](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#interfaces "Direct link to heading") * [AddPassOptions](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#addpassoptions) * [AddPassResponse](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#addpassresponse) * [CardData](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#carddata) * [DelegateError](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#delegateerror) * [Headers](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#headers) * [ServerError](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#servererror) ### Type aliases[​](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#type-aliases "Direct link to heading") * [ActivationState](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#activationstate) * * * Enumerations[​](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#enumerations-1 "Direct link to heading") --------------------------------------------------------------------------------------------------------------------------------------------- ### RequestTemplate[​](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#requesttemplate "Direct link to heading") **RequestTemplate**: Constants used to define the shape of the body used during the request to the server ### CERTIFICATE\_0[​](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#certificate_0 "Direct link to heading") **CERTIFICATE\_0**: = "$certificates.0" Constant used in the body template that represents the first item in the certificates array returned by the PKAddPaymentPassViewController. * * * ### CERTIFICATE\_1[​](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#certificate_1 "Direct link to heading") **CERTIFICATE\_1**: = "$certificates.1" Constant used in the body template that represents the second item in the certificates array returned by the PKAddPaymentPassViewController. * * * ### NONCE[​](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#nonce "Direct link to heading") **NONCE**: = "$nonceString" Constant used in the body template that represents the nonce returned by the PKAddPaymentPassViewController. * * * ### NONCE\_SIGNATURE[​](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#nonce_signature "Direct link to heading") **NONCE\_SIGNATURE**: = "$nonceSignature" Constant used in the body template that represents the nonceSignature returned by the PKAddPaymentPassViewController. * * * * * * Classes[​](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#classes-1 "Direct link to heading") ----------------------------------------------------------------------------------------------------------------------------------- ### ApplePaymentPass[​](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#applepaymentpass "Direct link to heading") **ApplePaymentPass**: This plugin provides support for adding credit/debit cards to Apple Wallet. It also can check if the credit/debit card exists in Wallet. ### template[​](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#template "Direct link to heading") **● template**: _[RequestTemplate](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#requesttemplate) _ = RequestTemplate * * * ### addPaymentPass[​](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#addpaymentpass "Direct link to heading") ▸ **addPaymentPass**(options: _[AddPassOptions](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#addpassoptions) _): `Promise`<[AddPassResponse](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#addpassresponse) \> This function accepts both the card data and information required to make the http request to the server in order to use PKAddPaymentPassViewController object to add a payment pass to the apple wallet. _**throws**_: \* [ServerError](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#servererror) [DelegateError](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#delegateerror) **Parameters:** | Name | Type | Description | | --- | --- | --- | | options | [AddPassOptions](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#addpassoptions) | The [AddPassOptions](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#addpassoptions)
object to configure the PKAddPaymentPassViewController and setup the call to the server. | **Returns:** `Promise`<[AddPassResponse](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#addpassresponse) \> * An object with the pass information * * * ### available[​](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#available "Direct link to heading") ▸ **available**(): `Promise`<`boolean`\> A function to determine if the current device supports adding a payment pass **Returns:** `Promise`<`boolean`\> whether or not a pay pass can be added * * * ### availableProvider[​](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#availableprovider "Direct link to heading") ▸ **availableProvider**(options: _`object`_): `Promise`<`boolean`\> A function to determine if the card has already been provisioned for the device. **Parameters:** **options: `object`** An object with the primary account identifier for the card. | Name | Type | | --- | --- | | primaryAccountIdentifier | `string` | **Returns:** `Promise`<`boolean`\> whether or not a pay can be added, throws an error if the card is already added * * * * * * Interfaces[​](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#interfaces-1 "Direct link to heading") ----------------------------------------------------------------------------------------------------------------------------------------- ### AddPassOptions[​](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#addpassoptions "Direct link to heading") **AddPassOptions**: The options interface to pass to the [addPaymentPass](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#applepaymentpass.addpaymentpass) function. ### body[​](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#body "Direct link to heading") **● body**: _`any`_ A templated request body to send to your server. include any additional fields and use the constansts [CERTIFICATE\_0](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#requesttemplate.certificate_0) , [CERTIFICATE\_1](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#requesttemplate.certificate_1) , [NONCE](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#requesttemplate.nonce) , [NONCE\_SIGNATURE](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#requesttemplate.nonce_signature) _**usage**_: const body = { userId: 1, cardId: 'xxxxx', appleWalletData: { certs: [ RequestTemplate.CERTIFICATE_0, RequestTemplate.CERTIFICATE_1 ], nonce: RequestTemplate.NONCE, nonceSignature: RequestTemplate.NONCE_SIGNATURE, }} Copy * * * ### card[​](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#card "Direct link to heading") **● card**: _[CardData](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#carddata) _ The card data * * * ### headers[​](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#headers "Direct link to heading") **● headers**: _[Headers](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#headers) _ An object with the headers required for the server request. * * * ### method[​](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#method "Direct link to heading") **● method**: _`string`_ The HTTP method to use ex. `POST` * * * ### url[​](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#url "Direct link to heading") **● url**: _`string`_ The url to hit ex. `https://my.api.com/v1/add/applepay/card` * * * * * * ### AddPassResponse[​](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#addpassresponse "Direct link to heading") **AddPassResponse**: The response from adding the pass with the pass data ### activationState[​](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#activationstate "Direct link to heading") **● activationState**: _[ActivationState](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#activationstate) _ The activation state of the card * * * ### deviceAccountIdentifier[​](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#deviceaccountidentifier "Direct link to heading") **● deviceAccountIdentifier**: _`string`_ The device account identifier. * * * ### deviceAccountNumberSuffix[​](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#deviceaccountnumbersuffix "Direct link to heading") **● deviceAccountNumberSuffix**: _`string`_ The device account number suffix * * * ### deviceName[​](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#devicename "Direct link to heading") **● deviceName**: _`string`_ The device name. * * * ### primaryAccountIdentifier[​](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#primaryaccountidentifier "Direct link to heading") **● primaryAccountIdentifier**: _`string`_ The primary account identifier * * * ### primaryAccountNumberSuffix[​](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#primaryaccountnumbersuffix "Direct link to heading") **● primaryAccountNumberSuffix**: _`string`_ The primary account number suffix * * * * * * ### CardData[​](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#carddata "Direct link to heading") **CardData**: The card data for the PKAddPaymentPassViewController ### `` cardholderName[​](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#optional-cardholdername "Direct link to heading") **● cardholderName**: _`undefined` | `string`_ The cardholder name * * * ### `` localizedDescription[​](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#optional-localizeddescription "Direct link to heading") **● localizedDescription**: _`undefined` | `string`_ A short description of the card. * * * ### `` paymentNetwork[​](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#optional-paymentnetwork "Direct link to heading") **● paymentNetwork**: _`undefined` | `string`_ Filters the networks shown in the introduction view to this single network. ex.`VISA \| MASTERCARD` * * * ### `` primaryAccountIdentifier[​](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#optional-primaryaccountidentifier "Direct link to heading") **● primaryAccountIdentifier**: _`undefined` | `string`_ Filters the device and attached devices that already have this card provisioned. No filter is applied if the parameter is omitted * * * ### `` primaryAccountSuffix[​](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#optional-primaryaccountsuffix "Direct link to heading") **● primaryAccountSuffix**: _`undefined` | `string`_ Last 4/5 digits of PAN. The last four or five digits of the PAN. Presented to the user with dots prepended to indicate that it is a suffix. * * * * * * ### DelegateError[​](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#delegateerror "Direct link to heading") **DelegateError**: Error thrown by [addPaymentPass](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#applepaymentpass.addpaymentpass) when the PKAddPaymentPassViewController fails to add the card to the wallet ### body[​](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#body-1 "Direct link to heading") **● body**: _`object`_ The error message #### Type declaration[​](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#type-declaration "Direct link to heading") message: `string` * * * ### statusCode[​](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#statuscode "Direct link to heading") **● statusCode**: _`number`_ The error code * * * ### type[​](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#type "Direct link to heading") **● type**: _"DelegateError"_ The type of the error * * * * * * ### Headers[​](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#headers-1 "Direct link to heading") **Headers**: An object with the headers required for the server request. _**usage**_: const headers = {'Authorization': 'Bearer xxxxx','Content-Type': 'application/json',...} Copy * * * ### ServerError[​](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#servererror "Direct link to heading") **ServerError**: Error thrown by [addPaymentPass](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#applepaymentpass.addpaymentpass) when server responds with a HTTP status code >= 400 ### body[​](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#body-2 "Direct link to heading") **● body**: _`any`_ The body return by the server * * * ### statusCode[​](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#statuscode-1 "Direct link to heading") **● statusCode**: _`number`_ The status code returned from the server * * * ### type[​](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#type-1 "Direct link to heading") **● type**: _"ServerError"_ The type of the error * * * * * * Type aliases[​](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#type-aliases-1 "Direct link to heading") --------------------------------------------------------------------------------------------------------------------------------------------- ### ActivationState[​](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#activationstate-1 "Direct link to heading") **Ƭ ActivationState**: _"activated" | "activating" | "suspended" | "deactivated" | "requires-activation" | "unknown"_ The activation state of the provisioned card * * * Change Log[​](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#change-log "Direct link to heading") --------------------------------------------------------------------------------------------------------------------------------------- ### \[1.0.2\] (2019-04-27)[​](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#102-2019-04-27 "Direct link to heading") ### Bug Fixes[​](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#bug-fixes "Direct link to heading") * Fixed issue where cordova plugin id was being incorrectly set by release script. ### \[1.0.0\] (2019-04-27)[​](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#100-2019-04-27 "Direct link to heading") ### Bug Fixes[​](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#bug-fixes-1 "Direct link to heading") * **iOS:** Fix issues where nonce string could be incorrectly replaced and errors from server weren't properly handled ### Features[​](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#features "Direct link to heading") * Added typed imports for [Angular](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#angular) , [ES2015+/Typescript](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#es2015-typescript) , and [Vanilla JS](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#vanilla-js) , closes \[#es2015\] ### BREAKING CHANGES[​](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#breaking-changes "Direct link to heading") * Changed package name from `@ionic-enterprise/apple-wallet` to `@ionic-enterprise/apple-payment-pass` and the main class from `AppleWallet` to `ApplePaymentPass`. See updated [usage docs](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#usage) . * [Usage](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#usage) * [Angular](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#angular) * [ES2015+/Typescript](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#es2015typescript) * [Vanilla JS](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#vanilla-js) * [Card Addition](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#card-addition) * [Index](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#index) * [Enumerations](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#enumerations) * [Classes](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#classes) * [Interfaces](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#interfaces) * [Type aliases](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#type-aliases) * [Enumerations](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#enumerations-1) * [RequestTemplate](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#requesttemplate) * [CERTIFICATE\_0](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#certificate_0) * [CERTIFICATE\_1](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#certificate_1) * [NONCE](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#nonce) * [NONCE\_SIGNATURE](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#nonce_signature) * [Classes](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#classes-1) * [ApplePaymentPass](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#applepaymentpass) * [template](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#template) * [addPaymentPass](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#addpaymentpass) * [available](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#available) * [availableProvider](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#availableprovider) * [Interfaces](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#interfaces-1) * [AddPassOptions](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#addpassoptions) * [body](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#body) * [card](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#card) * [headers](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#headers) * [method](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#method) * [url](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#url) * [AddPassResponse](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#addpassresponse) * [activationState](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#activationstate) * [deviceAccountIdentifier](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#deviceaccountidentifier) * [deviceAccountNumberSuffix](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#deviceaccountnumbersuffix) * [deviceName](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#devicename) * [primaryAccountIdentifier](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#primaryaccountidentifier) * [primaryAccountNumberSuffix](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#primaryaccountnumbersuffix) * [CardData](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#carddata) * [`` cardholderName](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#optional-cardholdername) * [`` localizedDescription](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#optional-localizeddescription) * [`` paymentNetwork](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#optional-paymentnetwork) * [`` primaryAccountIdentifier](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#optional-primaryaccountidentifier) * [`` primaryAccountSuffix](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#optional-primaryaccountsuffix) * [DelegateError](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#delegateerror) * [body](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#body-1) * [statusCode](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#statuscode) * [type](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#type) * [Headers](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#headers-1) * [ServerError](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#servererror) * [body](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#body-2) * [statusCode](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#statuscode-1) * [type](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#type-1) * [Type aliases](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#type-aliases-1) * [ActivationState](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#activationstate-1) * [Change Log](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#change-log) * [1.0.2 (2019-04-27)](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#102-2019-04-27) * [Bug Fixes](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#bug-fixes) * [1.0.0 (2019-04-27)](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#100-2019-04-27) * [Bug Fixes](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#bug-fixes-1) * [Features](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#features) * [BREAKING CHANGES](https://ionic.io/docs/supported-plugins/apple-payment-pass/1.0.X/apple-payment-pass#breaking-changes) --- # Intune Changelog - Intune [Skip to main content](https://ionic.io/docs/intune/changelog#) 7.0.1[#](https://ionic.io/docs/intune/changelog#701 "Direct link to heading") ------------------------------------------------------------------------------ ### Patch Changes[#](https://ionic.io/docs/intune/changelog#patch-changes "Direct link to heading") * Fix declaration of Android intune aar in build.gradle 7.0.0[#](https://ionic.io/docs/intune/changelog#700 "Direct link to heading") ------------------------------------------------------------------------------ ### Major Changes[#](https://ionic.io/docs/intune/changelog#major-changes "Direct link to heading") * Update Intune Android SDK to 11.0.0 and iOS SDK to 20.3.0 * Update MSAL Android to 5.10.0 and iOS to 1.7.0 * Now requires iOS 14+ and Xcode 15+ * Now requires Cordova 13+ for Android and Cordova iOS 7+ * **BREAKING CHANGE**: All methods now require using Object ID (OID) instead of User Principal Name (UPN) for account identification 6.0.0[#](https://ionic.io/docs/intune/changelog#600 "Direct link to heading") ------------------------------------------------------------------------------ ### Major Changes[#](https://ionic.io/docs/intune/changelog#major-changes-1 "Direct link to heading") * Update Intune Android SDK to 11.0.0 and iOS SDK to 20.3.0 * Update MSAL Android to 5.10.0 and iOS to 1.7.0 * Now requires iOS 14+ and Xcode 15+ * Now requires Cordova 13+ for Android and Cordova iOS 6+ * **BREAKING CHANGE**: All methods now require using Object ID (OID) instead of User Principal Name (UPN) for account identification 5.0.0[#](https://ionic.io/docs/intune/changelog#500 "Direct link to heading") ------------------------------------------------------------------------------ ### Major Changes[#](https://ionic.io/docs/intune/changelog#major-changes-2 "Direct link to heading") * 50d92af: Update MSAL Android to 5.3.0 and iOS to 1.3.2. * 50d92af: Update Intune Android to 10.2.1 and iOS to 19.3.1. 4.1.0-next.0[#](https://ionic.io/docs/intune/changelog#410-next0 "Direct link to heading") ------------------------------------------------------------------------------------------- ### Minor Changes[#](https://ionic.io/docs/intune/changelog#minor-changes "Direct link to heading") * Update Intune Android to 10.2.1 and iOS to 19.3.1. * Update MSAL Android to 5.3.0 and iOS to 1.3.2. 4.0.0[#](https://ionic.io/docs/intune/changelog#400 "Direct link to heading") ------------------------------------------------------------------------------ ### Patch Changes[#](https://ionic.io/docs/intune/changelog#patch-changes-1 "Direct link to heading") * 0fcc68e: fix ios bug in objc * 0fcc68e: cordova-ios 6 * 0fcc68e: cordova fixes * 0fcc68e: fix bridge ref * 0fcc68e: add "add-swift-support" corova dep * 0fcc68e: update cordova files * 0fcc68e: fix call reject 3.1.1[#](https://ionic.io/docs/intune/changelog#311 "Direct link to heading") ------------------------------------------------------------------------------ ### Patch Changes[#](https://ionic.io/docs/intune/changelog#patch-changes-2 "Direct link to heading") * a862edc: change dependency scope so library classes can be referenced from app projects 3.1.0[#](https://ionic.io/docs/intune/changelog#310 "Direct link to heading") ------------------------------------------------------------------------------ ### Minor Changes[#](https://ionic.io/docs/intune/changelog#minor-changes-1 "Direct link to heading") * 86f138f: Fix deRegisterAndUnenrollAccount not awaiting * 86f138f: deRegisterAndUnenrollAccount in Android will now await properly * 9cbaf1b: Add forceRefresh property to acquireTokenSilent * abff059: Add logoutOfAccount() for MSAL signout only funcionality 3.1.0-next.3[#](https://ionic.io/docs/intune/changelog#310-next3 "Direct link to heading") ------------------------------------------------------------------------------------------- ### Minor Changes[#](https://ionic.io/docs/intune/changelog#minor-changes-2 "Direct link to heading") * dcb4500: Add logoutOfAccount() for MSAL signout only funcionality 3.1.0-next.2[#](https://ionic.io/docs/intune/changelog#310-next2 "Direct link to heading") ------------------------------------------------------------------------------------------- ### Minor Changes[#](https://ionic.io/docs/intune/changelog#minor-changes-3 "Direct link to heading") * c48fdfa: deRegisterAndUnenrollAccount in Android will now await properly 3.1.0-next.1[#](https://ionic.io/docs/intune/changelog#310-next1 "Direct link to heading") ------------------------------------------------------------------------------------------- ### Minor Changes[#](https://ionic.io/docs/intune/changelog#minor-changes-4 "Direct link to heading") * Fix deRegisterAndUnenrollAccount not awaiting 3.1.0-next.0[#](https://ionic.io/docs/intune/changelog#310-next0 "Direct link to heading") ------------------------------------------------------------------------------------------- ### Minor Changes[#](https://ionic.io/docs/intune/changelog#minor-changes-5 "Direct link to heading") * Add forceRefresh property to acquireTokenSilent 3.0.3[#](https://ionic.io/docs/intune/changelog#303 "Direct link to heading") ------------------------------------------------------------------------------ ### Patch Changes[#](https://ionic.io/docs/intune/changelog#patch-changes-3 "Direct link to heading") * 56b97e3: Fix registerAndEnrollAccount promise resolutions 3.0.3-next.0[#](https://ionic.io/docs/intune/changelog#303-next0 "Direct link to heading") ------------------------------------------------------------------------------------------- ### Patch Changes[#](https://ionic.io/docs/intune/changelog#patch-changes-4 "Direct link to heading") * Fix registerAndEnrollAccount promise resolutions 3.0.2[#](https://ionic.io/docs/intune/changelog#302 "Direct link to heading") ------------------------------------------------------------------------------ ### Patch Changes[#](https://ionic.io/docs/intune/changelog#patch-changes-5 "Direct link to heading") * 8bcfa5c: Fix Promises not rejecting/resolving properly 3.0.2-next.0[#](https://ionic.io/docs/intune/changelog#302-next0 "Direct link to heading") ------------------------------------------------------------------------------------------- ### Patch Changes[#](https://ionic.io/docs/intune/changelog#patch-changes-6 "Direct link to heading") * Fix Promises not rejecting/resolving properly 3.0.1[#](https://ionic.io/docs/intune/changelog#301 "Direct link to heading") ------------------------------------------------------------------------------ ### Patch Changes[#](https://ionic.io/docs/intune/changelog#patch-changes-7 "Direct link to heading") * fix ios frameworks mixed types 3.0.0[#](https://ionic.io/docs/intune/changelog#300 "Direct link to heading") ------------------------------------------------------------------------------ ### Major Changes[#](https://ionic.io/docs/intune/changelog#major-changes-3 "Direct link to heading") * d147341: Update Swift SDK to 17.1.1 and MSAL SDK to 1.2.5 ### Patch Changes[#](https://ionic.io/docs/intune/changelog#patch-changes-8 "Direct link to heading") * 1dfb1ab: Update MSAL SDK on iOS 2.5.1[#](https://ionic.io/docs/intune/changelog#251 "Direct link to heading") ------------------------------------------------------------------------------ ### Patch Changes[#](https://ionic.io/docs/intune/changelog#patch-changes-9 "Direct link to heading") * ab2f5d8: Make dependencies compatible with Capacitor 4 2.5.0[#](https://ionic.io/docs/intune/changelog#250 "Direct link to heading") ------------------------------------------------------------------------------ ### Minor Changes[#](https://ionic.io/docs/intune/changelog#minor-changes-6 "Direct link to heading") * Add `promptType` option to allow always forcing login (See this [issue](https://github.com/AzureAD/microsoft-authentication-library-for-objc/issues/1271#issuecomment-797633677) ). 2.4.5[#](https://ionic.io/docs/intune/changelog#245 "Direct link to heading") ------------------------------------------------------------------------------ ### Patch Changes[#](https://ionic.io/docs/intune/changelog#patch-changes-10 "Direct link to heading") * Fix release 2.4.4[#](https://ionic.io/docs/intune/changelog#244 "Direct link to heading") ------------------------------------------------------------------------------ ### Patch Changes[#](https://ionic.io/docs/intune/changelog#patch-changes-11 "Direct link to heading") * Fixed appconfig serialization for Android 2.4.3[#](https://ionic.io/docs/intune/changelog#243 "Direct link to heading") ------------------------------------------------------------------------------ ### Patch Changes[#](https://ionic.io/docs/intune/changelog#patch-changes-12 "Direct link to heading") * Log users out from MSAL on deregister 2.4.2[#](https://ionic.io/docs/intune/changelog#242 "Direct link to heading") ------------------------------------------------------------------------------ ### Patch Changes[#](https://ionic.io/docs/intune/changelog#patch-changes-13 "Direct link to heading") * Fix for compilation error `Direct local .aar file dependencies are not supported when building an AAR` 2.4.1[#](https://ionic.io/docs/intune/changelog#241 "Direct link to heading") ------------------------------------------------------------------------------ ### Patch Changes[#](https://ionic.io/docs/intune/changelog#patch-changes-14 "Direct link to heading") * Add missing Cordova scripts 2.4.0[#](https://ionic.io/docs/intune/changelog#240 "Direct link to heading") ------------------------------------------------------------------------------ ### Minor Changes[#](https://ionic.io/docs/intune/changelog#minor-changes-7 "Direct link to heading") * 84b6d8f: Send scopes through to acquireToken on Android and update to MSAL 2.2.3 on Android 2.3.0[#](https://ionic.io/docs/intune/changelog#230 "Direct link to heading") ------------------------------------------------------------------------------ ### Minor Changes[#](https://ionic.io/docs/intune/changelog#minor-changes-8 "Direct link to heading") * Update Intune Android to 8.3.0 and iOS to 15.3.0 * [7.0.1](https://ionic.io/docs/intune/changelog#701) * [Patch Changes](https://ionic.io/docs/intune/changelog#patch-changes) * [7.0.0](https://ionic.io/docs/intune/changelog#700) * [Major Changes](https://ionic.io/docs/intune/changelog#major-changes) * [6.0.0](https://ionic.io/docs/intune/changelog#600) * [Major Changes](https://ionic.io/docs/intune/changelog#major-changes-1) * [5.0.0](https://ionic.io/docs/intune/changelog#500) * [Major Changes](https://ionic.io/docs/intune/changelog#major-changes-2) * [4.1.0-next.0](https://ionic.io/docs/intune/changelog#410-next0) * [Minor Changes](https://ionic.io/docs/intune/changelog#minor-changes) * [4.0.0](https://ionic.io/docs/intune/changelog#400) * [Patch Changes](https://ionic.io/docs/intune/changelog#patch-changes-1) * [3.1.1](https://ionic.io/docs/intune/changelog#311) * [Patch Changes](https://ionic.io/docs/intune/changelog#patch-changes-2) * [3.1.0](https://ionic.io/docs/intune/changelog#310) * [Minor Changes](https://ionic.io/docs/intune/changelog#minor-changes-1) * [3.1.0-next.3](https://ionic.io/docs/intune/changelog#310-next3) * [Minor Changes](https://ionic.io/docs/intune/changelog#minor-changes-2) * [3.1.0-next.2](https://ionic.io/docs/intune/changelog#310-next2) * [Minor Changes](https://ionic.io/docs/intune/changelog#minor-changes-3) * [3.1.0-next.1](https://ionic.io/docs/intune/changelog#310-next1) * [Minor Changes](https://ionic.io/docs/intune/changelog#minor-changes-4) * [3.1.0-next.0](https://ionic.io/docs/intune/changelog#310-next0) * [Minor Changes](https://ionic.io/docs/intune/changelog#minor-changes-5) * [3.0.3](https://ionic.io/docs/intune/changelog#303) * [Patch Changes](https://ionic.io/docs/intune/changelog#patch-changes-3) * [3.0.3-next.0](https://ionic.io/docs/intune/changelog#303-next0) * [Patch Changes](https://ionic.io/docs/intune/changelog#patch-changes-4) * [3.0.2](https://ionic.io/docs/intune/changelog#302) * [Patch Changes](https://ionic.io/docs/intune/changelog#patch-changes-5) * [3.0.2-next.0](https://ionic.io/docs/intune/changelog#302-next0) * [Patch Changes](https://ionic.io/docs/intune/changelog#patch-changes-6) * [3.0.1](https://ionic.io/docs/intune/changelog#301) * [Patch Changes](https://ionic.io/docs/intune/changelog#patch-changes-7) * [3.0.0](https://ionic.io/docs/intune/changelog#300) * [Major Changes](https://ionic.io/docs/intune/changelog#major-changes-3) * [Patch Changes](https://ionic.io/docs/intune/changelog#patch-changes-8) * [2.5.1](https://ionic.io/docs/intune/changelog#251) * [Patch Changes](https://ionic.io/docs/intune/changelog#patch-changes-9) * [2.5.0](https://ionic.io/docs/intune/changelog#250) * [Minor Changes](https://ionic.io/docs/intune/changelog#minor-changes-6) * [2.4.5](https://ionic.io/docs/intune/changelog#245) * [Patch Changes](https://ionic.io/docs/intune/changelog#patch-changes-10) * [2.4.4](https://ionic.io/docs/intune/changelog#244) * [Patch Changes](https://ionic.io/docs/intune/changelog#patch-changes-11) * [2.4.3](https://ionic.io/docs/intune/changelog#243) * [Patch Changes](https://ionic.io/docs/intune/changelog#patch-changes-12) * [2.4.2](https://ionic.io/docs/intune/changelog#242) * [Patch Changes](https://ionic.io/docs/intune/changelog#patch-changes-13) * [2.4.1](https://ionic.io/docs/intune/changelog#241) * [Patch Changes](https://ionic.io/docs/intune/changelog#patch-changes-14) * [2.4.0](https://ionic.io/docs/intune/changelog#240) * [Minor Changes](https://ionic.io/docs/intune/changelog#minor-changes-7) * [2.3.0](https://ionic.io/docs/intune/changelog#230) * [Minor Changes](https://ionic.io/docs/intune/changelog#minor-changes-8) --- # Deploying Your App with Appflow | Ionic Secure Solutions Starter [Skip to main content](https://ionic.io/docs/enterprise-starter/appflow#) With your newly minted enterprise application, it is time to get it in your user's hands. The best way to do that is using [Appflow](https://ionic.io/appflow) . Appflow is a continuous integration (CI) and continuous deployment (CD) platform for Ionic development teams. The platform helps development teams continuously build and ship their apps faster than ever! Let's walk through the steps together. Connect Your Repo[#](https://ionic.io/docs/enterprise-starter/appflow#connect-your-repo "Direct link to heading") ------------------------------------------------------------------------------------------------------------------ Appflow works directly with Git version control and uses your code base as the source of truth for Deploy and Package builds. In order for Appflow to access your code, you can choose to integrate directly using a hosting service like GitHub or Bitbucket, or you can push your code directly to Appflow. If you did not connect your app's repo in [earlier part of the tutorial](https://ionic.io/docs/enterprise-starter/enterprise-key#import-your-app) , now is the time to do so. In the [Appflow Dashboard](https://dashboard.ionicframework.com/) ensure you've created your new app and connected to it's git repo. More details can be found within the [Appflow Quickstart](https://ionic.io/docs/appflow/quickstart/connect) , if needed. Install the Appflow SDK[#](https://ionic.io/docs/enterprise-starter/appflow#install-the-appflow-sdk "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------------ In order to take advantage of some of the best Appflow features, like deploying live updates to your app and bypassing the app stores, you'll need to install the Appflow SDK (also known as the Ionic Deploy plugin). The Appflow SDK comes with Ionic Appflow's Live Update feature for detecting and syncing your app with updates that you've pushed to channels. The best way to install the Appflow SDK plugin is to follow the instructions provided in the Dashboard. In the `Deploy > Destinations` section, clicking "Install Instructions" with pop a modal with a command you'll be able to copy and paste into your terminal. The code will look similar to the following, except with all of the values already filled in for you based on your selections within the modal itself: ionic deploy add \ --app-id="YOUR_APP_ID" \ --channel-name="YOUR_CHANNEL_NAME" \ --update-method="background|auto|none" \ Copy More details on installing the Appflow SDK can be found [here](https://ionic.io/docs/appflow/quickstart/installation) . Committing to Appflow[#](https://ionic.io/docs/enterprise-starter/appflow#committing-to-appflow "Direct link to heading") -------------------------------------------------------------------------------------------------------------------------- Once this command you copied from the last step is run in your terminal, be sure to commit the changes just made to your project and push them to your git host: git add . # stage any changesgit commit -m "added appflow sdk" # commit staged changesgit push origin main # push the changes from the main branch to your git host Copy You will now see your commit available in the `Commits` tab of the Dashboard. Additional details on pushing a commit can be found [here](https://ionic.io/docs/appflow/quickstart/push) . Deploy a Live Update[#](https://ionic.io/docs/enterprise-starter/appflow#deploy-a-live-update "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------ With the Appflow SDK installed and your commit pushed up to the Dashboard, you are ready to deploy a live update to a device. The Live Update feature uses the installed Appflow SDK with your native app to listen to a particular `Deploy Channel Destination`. When a `Live Update` is assigned to a `Channel Destination`, that update will be deployed to user devices running binaries that are configured to listen to that specific `Channel Destination`. To get the `Live Update` deployed, a Web build will need to be created. This can be done through the `Start build` icon from the `Commits` tab or by clicking the `New build` button in the top right corner of the `Build > Builds` tab. After selecting the correct commit to deploy, select the `Web` target platform and the `Latest` build stack. Depending on your Appflow plan, you will then be able to include custom environments, if any are configured. Finally, you can enable `Live Update` and pick the Channel to automatically assign the build to once it successfully completes. Upon completion of the Web Build, additional versioning options are available to you. After completing this section, and you have a successful Deploy build, you can then assign it to the same Channel you configured the Appflow SDK to listen to when you installed it by clicking the `Deploy live updates` button in the build detail page. The same can be done by clicking the `Deploy live updates` icon on the build in the `Build > Builds` tab and select the Channel from the dropdown. To receive this live update, you will need to run the app on a device or an emulator. The quickest and easiest way to do this is through the Visual Studio Code - Ionic extension. You will open the Ionic extension panel. Under the Capacitor section, you will `Build`, `Sync`, then choose where you want to run the app in the `Run`. This could be on an iOS simulator or Android Emulator, or a real device if you have one plugged into your computer. Another route would be to open the app in Xcode or Android Studio via the Ionic extension, then run the app on a device or simulator/emulator. Assuming the app is configured correctly to listen to the channel you deployed too, the app should immediately update on startup (if you have chosen the `auto` update method during setup). If the `background` update method was chosen, be sure to stay in the app for about 30 seconds to ensure the update was downloaded. Then, close the application, reopen it, and you will see the updates applied! To dive into more details on the steps to deploy a live update, as well as additional information such as disabling deploy for development, check out the [Deploy a Live Update](https://ionic.io/docs/appflow/quickstart/deploy) section inside the Appflow docs. Build a Native Binary[#](https://ionic.io/docs/enterprise-starter/appflow#build-a-native-binary "Direct link to heading") -------------------------------------------------------------------------------------------------------------------------- Next up is a native binary for your app build and deploy process. This is done via the [Ionic Package](https://ionic.io/docs/appflow/package/intro) service. First things first, you will need to create a [Package build](https://ionic.io/docs/appflow/package/builds) . This can be done by clicking the `Start build` icon from the `Commits` tab or by clicking the `New build` button in the top right from the `Build > Builds` tab. Then you will select the proper commit for your build and fill in the several required fields, as well as any optional fields that you want to specify. After filling in all of the information and the build begins, you can check out it's progress and review the logs if you encounter any errors. Given a successful Package build, an iOS binary (`.ipa` or IPA) or an Android binary (`.apk` or APK) file becomes available to you. The file can subsequently be downloaded so you can install it on a device by clicking the file name in the `Artifacts` section in the right of the build detail page or clicking the `Download IPA/APK` icon on the build in the `Build > Builds` tab. Further information regarding building native binaries can be found inside of the [Build a Native Binary](https://ionic.io/docs/appflow/quickstart/package) section inside the Appflow docs. Create an Automation[#](https://ionic.io/docs/enterprise-starter/appflow#create-an-automation "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------ [Automations](https://ionic.io/docs/appflow/automation/intro) enable you and your team to utilize the full CI/CD powers of Appflow. You can create automations that trigger [Package builds](https://ionic.io/docs/appflow/package/builds) and [Deploy builds](https://ionic.io/docs/appflow/deploy/builds) every time your team commits new code to a given branch. The automations can also be configured to use different environments and native configurations for building different versions of your app for development, staging, QA and production. For more information, visit the [Create an Automation](https://ionic.io/docs/appflow/quickstart/automation) section within the Appflow docs. There you will see details on creating a single automation. However, you can create multiple automations for different branches or workflows and customize them to fit your needs. An important note is that the ability to create an automation is available for those on our [Basic plans](https://ionic.io/pricing) and above. Create an Environment[#](https://ionic.io/docs/enterprise-starter/appflow#create-an-environment "Direct link to heading") -------------------------------------------------------------------------------------------------------------------------- [Package builds](https://ionic.io/docs/appflow/package/builds) and [Deploy builds](https://ionic.io/docs/appflow/deploy/builds) can be futher customized via [Environments](https://ionic.io/docs/appflow/automation/environments) . This powerful feature allows you to create different configurations based on the environment variables passed in at build time. When combined with the [Automation](https://ionic.io/docs/appflow/automation/intro) feature, development teams can easily configure development, staging, and production build configurations, allowing them to embrace DevOps best practices and ship better quality updates faster than ever. Creating an Environment is available for those on our [Basic plans](https://ionic.io/pricing) and above. More information on this can be found in the [Create an Environment](https://ionic.io/docs/appflow/quickstart/environment) section within the Appflow docs. Create a Native Configuration[#](https://ionic.io/docs/enterprise-starter/appflow#create-a-native-configuration "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------------------------ [Native Configurations](https://ionic.io/docs/appflow/package/native-configs) allow you to easily modify common configuration values that can change between different environments (development, production, staging, etc.) so you do not need to use extra logic or manually commit them to version control. Native configurations can be attached to any [Package build](https://ionic.io/docs/appflow/package/intro) or [Automation](https://ionic.io/docs/appflow/automation/intro) . Native configs can be used to: * Overwrite the unique bundle identifier or [id attribute](https://cordova.apache.org/docs/en/latest/config_ref/#widget) in `config.xml` * Overwrite the App Name as it will appear on the home screen of a device * Overwrite the [Appflow SDK (Deploy Plugin) variables and preferences](https://ionic.io/docs/appflow/deploy/api#plugin-variables) For access to the ability to create a Native Configuration, you will need to be on our [Basic plans](https://ionic.io/pricing) and above. Additional details of this feature can be found in the [Create a Native Configuration](https://ionic.io/docs/appflow/quickstart/native-config) section within the Appflow docs. What’s Next?[#](https://ionic.io/docs/enterprise-starter/appflow#whats-next "Direct link to heading") ------------------------------------------------------------------------------------------------------ Congratulations! You developed a complete cross-platform enterprise app that runs on the web, iOS, and Android. Not only that, you have also then built the app and deployed it to you users devices! There are many paths to follow from here. Try adding another [Ionic UI component](https://ionicframework.com/docs/components) to the app, or more [native functionality](https://capacitor.ionicframework.com/docs/apis) . The sky’s the limit. Once you have added another feature run the the build and deploy process again through Appflow to get it out to your users. Happy app building! 💙 [Edit this page](https://github.com/ionic-team/ionic-enterprise-starter/tree/main/website/docs/appflow.md) * [Connect Your Repo](https://ionic.io/docs/enterprise-starter/appflow#connect-your-repo) * [Install the Appflow SDK](https://ionic.io/docs/enterprise-starter/appflow#install-the-appflow-sdk) * [Committing to Appflow](https://ionic.io/docs/enterprise-starter/appflow#committing-to-appflow) * [Deploy a Live Update](https://ionic.io/docs/enterprise-starter/appflow#deploy-a-live-update) * [Build a Native Binary](https://ionic.io/docs/enterprise-starter/appflow#build-a-native-binary) * [Create an Automation](https://ionic.io/docs/enterprise-starter/appflow#create-an-automation) * [Create an Environment](https://ionic.io/docs/enterprise-starter/appflow#create-an-environment) * [Create a Native Configuration](https://ionic.io/docs/enterprise-starter/appflow#create-a-native-configuration) * [What’s Next?](https://ionic.io/docs/enterprise-starter/appflow#whats-next) --- # Intune Support Policy - Intune [Skip to main content](https://ionic.io/docs/intune/support-policy#) This policy is for Intune as maintained by Ionic. Capacitor Core, Capacitor Plugins, or any additional plugins maintained by Ionic are not covered by this support policy. ### Current Support Status[#](https://ionic.io/docs/intune/support-policy#current-support-status "Direct link to heading") | Version | Status | Released | Active Support Ends | Long-Term Support Ends | | --- | --- | --- | --- | --- | | V1 | Not Supported | September 14, 2021 | September 24, 2021 | September 24, 2022 | | V2 | Not Supported | September 24, 2021 | November 30, 2022 | November 30, 2023 | | V3 | Not Supported | November 30, 2022 | Feb 11, 2025 | Feb 11, 2025 | | V4 | Not Supported | April 8, 2020 | July 28, 2021 | Feb 11, 2025 | | V5 | Long-Term Support | July 28, 2021 | Feb 11, 2025 | December 31, 2026 | | V6 | Active | Mar 3, 2025 | December 31, 2026 | TBD | | V7 | Active | Mar 3, 2025 | TBD | TBD | | | | | | | ### Support Policy[#](https://ionic.io/docs/intune/support-policy#support-policy "Direct link to heading") Ionic enterprise products are covered by a 3-stage support plan to ensure that all customers have the best experience with Ionic products and are able to receive our excellent standard of care. These steps are outlined as follows: ### Stage 1: Active Support[#](https://ionic.io/docs/intune/support-policy#stage-1-active-support "Direct link to heading") During the active support period of a product, the entirety of Ionic’s customer support services are available to teams using this enterprise product. ### Stage 2: Long Term Support[#](https://ionic.io/docs/intune/support-policy#stage-2-long-term-support "Direct link to heading") Long Term Support is available to all enterprise products after active support has ended. This duration typically lasts for a period of 12 months, unless otherwise specified. During this stage, most elements of Ionic’s customer support services are available, however products in this stage will only receive bug and security fixes, no new feature requests or updates will be accepted. ### Stage 3: Not Supported[#](https://ionic.io/docs/intune/support-policy#stage-3-not-supported "Direct link to heading") After the period of time for Long Term Support has ended, the product will indefinitely enter the Not Supported stage. Products will still be accessible and usable in this stage, however, support for these versions is limited to existing documentation, knowledge base article or community support. Ionic’s customer support services are not available for products in this stage. We recommend that customers update their software to the latest released version available to enjoy the most stable and complete experience. Ionic offers solutions, workarounds, and other fixes to the best of our ability and at our own discretion. There may be times when the only valid solution is to upgrade to the most recent version of a product. For trial users, support is only offered for the most recent release of a product. We recommend scheduling time to upgrade before the Long Term Support period. Once a product reaches the end of Long Term Support, there will be no additional product support or bug fixes, even if your support contract extends beyond that time. As an example, if you are currently using Identity Vault 5, Ionic may release a series of fixes and feature releases: 5.1, 5.2, 5.3, etc. During this time, Identity Vault version 5 is covered under the Active Support stage and all customer support services are available. When Identity Vault 6 is released, Identity Vault 5 will enter Long Term Support for 12 months and will continue to receive critical bug fixes. You will still be able to receive support through our customer support as well during this period as long as your support contract is still active. At the end of the 12 month period, Identity Vault 5 will move from Long Term Support to Not Supported and no additional support will be provided through Ionic customer support. This support policy covers all products currently supported as of the time of publication and beyond. Ionic reserves the right to make changes to this Support Policy. It is intended exclusively for customers who have purchased Ionic Enterprise products and is not applicable to any open source products that Ionic may maintain. The support status of current and legacy versions will be updated to reflect any changes. * [Current Support Status](https://ionic.io/docs/intune/support-policy#current-support-status) * [Support Policy](https://ionic.io/docs/intune/support-policy#support-policy) * [Stage 1: Active Support](https://ionic.io/docs/intune/support-policy#stage-1-active-support) * [Stage 2: Long Term Support](https://ionic.io/docs/intune/support-policy#stage-2-long-term-support) * [Stage 3: Not Supported](https://ionic.io/docs/intune/support-policy#stage-3-not-supported) --- # Troubleshooting - Intune [Skip to main content](https://ionic.io/docs/intune/troubleshooting#) Official Troubleshooting Guide[#](https://ionic.io/docs/intune/troubleshooting#official-troubleshooting-guide "Direct link to heading") ---------------------------------------------------------------------------------------------------------------------------------------- Refer first to Microsoft's [official troubleshooting documentation](https://docs.microsoft.com/en-us/troubleshoot/mem/intune/troubleshoot-mam) to find solutions to common issues. Additionally, for authentication issues, the `Sign-in logs` section of the Azure Active Directory app registration portal often has helpful error messages that point to Azure-side configuration issues. Please contact your administrator for access to this resource in Azure. iOS[#](https://ionic.io/docs/intune/troubleshooting#ios "Direct link to heading") ---------------------------------------------------------------------------------- ### "Unexpected failure" when performing brokered auth[#](https://ionic.io/docs/intune/troubleshooting#unexpected-failure-when-performing-brokered-auth "Direct link to heading") This error is the same as the one mentioned in [this issue](https://github.com/msintuneappsdk/ms-intune-app-sdk-ios/issues/175) . To fix it, some additional configuration for MSAL is required. Make sure you've added the following line inside of the `CFBundleURLSchemes` as shown below to your `Info.plist` to enable using the authenticator app: CFBundleURLTypes CFBundleURLSchemes msauth.$(PRODUCT_BUNDLE_IDENTIFIER) Copy This enables your app to launch the authenticator. ### MSALErrorDomain -50000 when using brokered auth[#](https://ionic.io/docs/intune/troubleshooting#msalerrordomain--50000-when-using-brokered-auth "Direct link to heading") This is a configuration issue in the Azure Active Directory Portal. Ensure the app registration has permission to access the `Microsoft Mobile Application Management` API. Please contact your administrator to enable your app to access the necessary APIs. Another thing to try is setting `AutoEnrollOnLaunch` to `1` in the `IntuneMAMSettings` in `Info.plist`. ![Azure Troubleshooting 5000 ios](https://ionic.io/docs/intune/assets/images/ios-troubleshooting-5000-efe3f1af44ba0494b5f860aed4462751.png) ### Build error: Undefined symbols and 12.0 deployment target warning[#](https://ionic.io/docs/intune/troubleshooting#build-error-undefined-symbols-and-120-deployment-target-warning "Direct link to heading") If you see this error: ![intune undefined symbols](https://ionic.io/docs/intune/assets/images/ios-troubleshooting-undefined-symbols-4ae051219e5bab2afd965265656a7cbb.png) The issue could be not setting the minimum deployment target for your App to 12.2 or above or the Podfile extra script to disable bitcode in all targets was not added. See the [iOS Installation](https://ionic.io/docs/intune/ios-installation) guide and follow the deployment target and Podfile recommendations to resolve the issue. ### Enable logging[#](https://ionic.io/docs/intune/troubleshooting#enable-logging "Direct link to heading") See [this troubleshooting tip](https://techcommunity.microsoft.com/t5/intune-customer-success/support-tip-troubleshooting-intune-app-protection-policy-using/ba-p/330372) Android[#](https://ionic.io/docs/intune/troubleshooting#android "Direct link to heading") ------------------------------------------------------------------------------------------ ### com.microsoft.identity.client.exception.MsalClientException: The redirect URI in the configuration file doesn't match[#](https://ionic.io/docs/intune/troubleshooting#commicrosoftidentityclientexceptionmsalclientexception-the-redirect-uri-in-the-configuration-file-doesnt-match "Direct link to heading") The error `com.microsoft.identity.client.exception.MsalClientException: The redirect URI in the configuration file doesn't match with the one generated with package name and signature hash. Please verify the uri in the config file and your app registration in Azure portal.` is thrown when attempting to authenticate using `acquireToken` or `loginAndEnrollAccount`. This issue is thrown because the hash used for your redirect uri in `auth_config.json` and/or `AndroidManifest.xml` isn't correct. Follow the [Android installation](https://ionic.io/docs/intune/android-installation) guide to find and set the correct hash for your app. ### Gradle sync error: Null extracted folder for artifact[#](https://ionic.io/docs/intune/troubleshooting#gradle-sync-error-null-extracted-folder-for-artifact "Direct link to heading") This happens when the reference to the Intune App SDK for Android AAR file (Microsoft.Intune.MAM.SDK.aar) cannot be found. ### android.content.pm.PackageManager$NameNotFoundException com.azure.authenticator[#](https://ionic.io/docs/intune/troubleshooting#androidcontentpmpackagemanagernamenotfoundexception-comazureauthenticator "Direct link to heading") This error happens on Android 30 when your `AndroidManifest.xml` is missing `` for the Microsoft Authenticator or Intune Company Portal apps. This is a new Android security feature (as of Android 30) that restrict the app to query for only a defined set of external apps. To fix this issue, follow the Android install guide for the `AndroidManifest.xml` instructions to ensure the proper `` definition has been added. ### Direct local .aar file dependencies are not supported when building an AAR.[#](https://ionic.io/docs/intune/troubleshooting#direct-local-aar-file-dependencies-are-not-supported-when-building-an-aar "Direct link to heading") This compilation error can happen with versions of the plugin 2.4.1 and below. Update to the latest version then open the `build.gradle` file for the `Module: android.app` and ensure it contains the following line in `dependencies`: dependencies { ... implementation files("../../node_modules/@ionic-enterprise/intune/android/ms-intune-app-sdk-android/Microsoft.Intune.MAM.SDK.aar")} Copy ### java.lang.ClassNotFoundException: Didn't find class "com.ionicframework.intune.IntuneApplication"[#](https://ionic.io/docs/intune/troubleshooting#javalangclassnotfoundexception-didnt-find-class-comionicframeworkintuneintuneapplication "Direct link to heading") This runtime error can occur if you have forgotten to add the following line to the `dependencies` of the `build.gradle` file for the `Module: android.app`: dependencies { ... implementation files("../../node_modules/@ionic-enterprise/intune/android/ms-intune-app-sdk-android/Microsoft.Intune.MAM.SDK.aar")} Copy ### MAM Enabled: No when uploading to Microsoft Endpoint Manager[#](https://ionic.io/docs/intune/troubleshooting#mam-enabled-no-when-uploading-to-microsoft-endpoint-manager "Direct link to heading") When uploading a release build APK to the Microsoft Endpoint Manager and it reports "MAM Enabled: No" then you can workaround this by editing the `gradle.properties` file and adding the following line: android.enableResourceOptimizations=false Copy Then create a new release build and upload the APK. It should report "MAM Enabled: Yes". This [issue](https://github.com/msintuneappsdk/ms-intune-app-sdk-android/issues/117) is related to Microsoft Endpoint Manager and is not a problem with your application. ### Incompatible Gradle Version detected[#](https://ionic.io/docs/intune/troubleshooting#incompatible-gradle-version-detected "Direct link to heading") This error can occur when upgrading from 2.x to 3.x of the plugin. It is usually related to version 7.2.1 of the build tools which you can verify in `android/build.gradle`. To fix the problem open this file and change the line: `classpath 'com.android.tools.build:gradle:7.2.1'` to `classpath 'com.android.tools.build:gradle:7.2.2'` The full error is: `incompatible Gradle version detected. Use 7.1.3 or 7.2.2+. For details, see https://issuetracker.google.com/issues/232438924` This issue should be resolved in an upcoming version of Android Studio (Android Studio Dolphin 2021.3.1.11, yet to be released as of December 2022). Client Side Errors[#](https://ionic.io/docs/intune/troubleshooting#client-side-errors "Direct link to heading") ---------------------------------------------------------------------------------------------------------------- ### The account is licensed for intune but is not targeted with mam policy[#](https://ionic.io/docs/intune/troubleshooting#the-account-is-licensed-for-intune-but-is-not-targeted-with-mam-policy "Direct link to heading") This can occur with the following scenarios: * The end user must have an Azure Active Directory (AAD) account. See Add users and give administrative permission to Intune to learn how to create Intune users in Azure Active Directory. * The end user must have a license for Microsoft Intune assigned to their Azure Active Directory account. See Manage Intune licenses to learn how to assign Intune licenses to end users. * The end user must belong to a security group that is targeted by an app protection policy. The same app protection policy must target the specific app being used. App protection policies can be created and deployed in the Intune console ([endpoint.microsoft.com](https://endpoint.microsoft.com/) > `Apps` > `App Protection Policies`). * The end user must sign into the app using their AAD account. ### The operation could not be completed because the user is not licensed for MAM[#](https://ionic.io/docs/intune/troubleshooting#the-operation-could-not-be-completed-because-the-user-is-not-licensed-for-mam "Direct link to heading") This error will occur if the user has logged in with the correct credentials but their user has not been assigned a license for inTune. You can assign a license to a user in [endpoint.microsoft.com](https://endpoint.microsoft.com/) > `Users` > Find the User > `Licenses`. ### Email: Plan for Change: Intune App SDK[#](https://ionic.io/docs/intune/troubleshooting#email-plan-for-change-intune-app-sdk "Direct link to heading") An update required from Microsoft states: "Starting July 1, 2024, iOS apps with Intune App SDK need to update to include a new protocol (intunemam-mtd://) for MAM efficiency. Update your app's `Info.plist` file before this date. Details in the Intune SDK integration guide.". To meet this requirement, you must add the following line to the `Info.plist` file under the `LSApplicationQueriesSchemes` key: intunemam-mtd Copy * [Official Troubleshooting Guide](https://ionic.io/docs/intune/troubleshooting#official-troubleshooting-guide) * [iOS](https://ionic.io/docs/intune/troubleshooting#ios) * ["Unexpected failure" when performing brokered auth](https://ionic.io/docs/intune/troubleshooting#unexpected-failure-when-performing-brokered-auth) * [MSALErrorDomain -50000 when using brokered auth](https://ionic.io/docs/intune/troubleshooting#msalerrordomain--50000-when-using-brokered-auth) * [Build error: Undefined symbols and 12.0 deployment target warning](https://ionic.io/docs/intune/troubleshooting#build-error-undefined-symbols-and-120-deployment-target-warning) * [Enable logging](https://ionic.io/docs/intune/troubleshooting#enable-logging) * [Android](https://ionic.io/docs/intune/troubleshooting#android) * [com.microsoft.identity.client.exception.MsalClientException: The redirect URI in the configuration file doesn't match](https://ionic.io/docs/intune/troubleshooting#commicrosoftidentityclientexceptionmsalclientexception-the-redirect-uri-in-the-configuration-file-doesnt-match) * [Gradle sync error: Null extracted folder for artifact](https://ionic.io/docs/intune/troubleshooting#gradle-sync-error-null-extracted-folder-for-artifact) * [android.content.pm.PackageManager$NameNotFoundException com.azure.authenticator](https://ionic.io/docs/intune/troubleshooting#androidcontentpmpackagemanagernamenotfoundexception-comazureauthenticator) * [Direct local .aar file dependencies are not supported when building an AAR.](https://ionic.io/docs/intune/troubleshooting#direct-local-aar-file-dependencies-are-not-supported-when-building-an-aar) * [java.lang.ClassNotFoundException: Didn't find class "com.ionicframework.intune.IntuneApplication"](https://ionic.io/docs/intune/troubleshooting#javalangclassnotfoundexception-didnt-find-class-comionicframeworkintuneintuneapplication) * [MAM Enabled: No when uploading to Microsoft Endpoint Manager](https://ionic.io/docs/intune/troubleshooting#mam-enabled-no-when-uploading-to-microsoft-endpoint-manager) * [Incompatible Gradle Version detected](https://ionic.io/docs/intune/troubleshooting#incompatible-gradle-version-detected) * [Client Side Errors](https://ionic.io/docs/intune/troubleshooting#client-side-errors) * [The account is licensed for intune but is not targeted with mam policy](https://ionic.io/docs/intune/troubleshooting#the-account-is-licensed-for-intune-but-is-not-targeted-with-mam-policy) * [The operation could not be completed because the user is not licensed for MAM](https://ionic.io/docs/intune/troubleshooting#the-operation-could-not-be-completed-because-the-user-is-not-licensed-for-mam) * [Email: Plan for Change: Intune App SDK](https://ionic.io/docs/intune/troubleshooting#email-plan-for-change-intune-app-sdk) --- # Installation - iOS - Intune [Skip to main content](https://ionic.io/docs/intune/ios-installation#) The following steps attempt to distill the [official Intune App SDK iOS integration documentation](https://docs.microsoft.com/en-us/mem/intune/developer/app-sdk-ios#build-the-sdk-into-your-mobile-app) to the basics needed to integrate into your Ionic/Capacitor app. Please refer to that documentation for the most up-to-date authoritative installation instructions. 0\. Before starting[#](https://ionic.io/docs/intune/ios-installation#0-before-starting "Direct link to heading") ----------------------------------------------------------------------------------------------------------------- Note that version 7.x of `@ionic-enterprise/intune` requires a deployment target of iOS 14 or higher and requires Xcode 15+. 1\. Add Frameworks[#](https://ionic.io/docs/intune/ios-installation#1-add-frameworks "Direct link to heading") --------------------------------------------------------------------------------------------------------------- The Intune App SDK requires the following Core iOS frameworks be added to your app project: * AudioToolbox.framework * CoreServices.framework * ImageIO.framework * libc++.tbd * libsqlite3.tbd * LocalAuthentication.framework * MessageUI.framework * QuartzCore.framework * Security.framework * SystemConfiguration.framework * WebKit.framework [![iOS Frameworks](https://ionic.io/docs/intune/assets/images/ios-frameworks-a3bc21bd3728b5d1daf9d3212d304ba3.png)](https://ionic.io/docs/intune/assets/files/ios-frameworks-a3bc21bd3728b5d1daf9d3212d304ba3.png) 2\. Configure Keychain[#](https://ionic.io/docs/intune/ios-installation#2-configure-keychain "Direct link to heading") ----------------------------------------------------------------------------------------------------------------------- Add the following keychain groups under Signing & Capabilities, making sure to substitute your app's Bundle ID for the first group: * `com.microsoft.intune.mam` * `com.microsoft.adalcache` [![iOS Keychain](https://ionic.io/docs/intune/assets/images/ios-keychain-8b5cdfa59dd83d3db8f1c41a85b03196.png)](https://ionic.io/docs/intune/assets/files/ios-keychain-8b5cdfa59dd83d3db8f1c41a85b03196.png) 3\. Enable Application Queries Schemes[#](https://ionic.io/docs/intune/ios-installation#3-enable-application-queries-schemes "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------------------------------------- Open `Info.plist` and add a new Row with the name `LSApplicationQueriesSchemes` of type `Array` containing all of the protocols your app will attempt to open, for example by using the [App Launcher](https://capacitorjs.com/docs/apis/app-launcher) API in Capacitor. Any custom protocols your app launches must have two entries: the original protocol and a new one with `-intunemam` appended. Additionally, the following intune-specific protocols must be added : LSApplicationQueriesSchemes msauthv2 msauthv3 mvisionmobile scmx lookoutwork-ase lacoonsecurity zips skycure smart-ns smsec betteractiveshield wandera https-intunemam http-intunemam intunemam-mtd microsoft-edge-https-intunemam microsoft-edge-http-intunemam ms-outlook-intunemam companyportal Copy 4\. Set a NSFaceIDUsageDescription[#](https://ionic.io/docs/intune/ios-installation#4-set-a-nsfaceidusagedescription "Direct link to heading") ----------------------------------------------------------------------------------------------------------------------------------------------- To enable Face ID support, add a description for `NSFaceIDUsageScription` also known as `Privacy - Face ID Usage Description` in `Info.plist` 5\. Update Target iOS Version[#](https://ionic.io/docs/intune/ios-installation#5-update-target-ios-version "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------------------- The Intune App SDK supports iOS 13 and above, make sure to set the Deployment target for your app to 13 or higher (or 12.2 if you are using version 2.x of the plugin): [![iOS 13](https://ionic.io/docs/intune/assets/images/ios-13-f864fd528dc65fffe64b298cd602d628.png)](https://ionic.io/docs/intune/assets/files/ios-13-f864fd528dc65fffe64b298cd602d628.png) 6\. Disable Bitcode[#](https://ionic.io/docs/intune/ios-installation#6-disable-bitcode "Direct link to heading") ----------------------------------------------------------------------------------------------------------------- The Intune App SDK does not support Bitcode. In the Build Settings for your app in Xcode, set `Strip Swift Symbols` and `Enable Bitcode` to `NO`: [![Disable bitcode](https://ionic.io/docs/intune/assets/images/ios-disable-bitcode-c5e4a1ed7db6c46c855db76ebffa8df7.png)](https://ionic.io/docs/intune/assets/files/ios-disable-bitcode-c5e4a1ed7db6c46c855db76ebffa8df7.png) [![No strip symbols](https://ionic.io/docs/intune/assets/images/ios-no-strip-symbols-ea9c5202ab28b5d6b2acd3fde1a93c07.png)](https://ionic.io/docs/intune/assets/files/ios-no-strip-symbols-ea9c5202ab28b5d6b2acd3fde1a93c07.png) Also add these lines to the `Podfile` in your app's `ios/App` directory. This will make sure bitcode is not enabled on any Pod targets: post_install do |installer| installer.pods_project.targets.each do |target| target.build_configurations.each do |config| config.build_settings['ENABLE_BITCODE'] = 'NO' end endend Copy 7\. Run IntuneMAMConfigurator[#](https://ionic.io/docs/intune/ios-installation#7-run-intunemamconfigurator "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------------------- As a final step, Microsoft has provided a command line utility to finish configuring your app. To use it, [follow step #7](https://docs.microsoft.com/en-us/mem/intune/developer/app-sdk-ios#build-the-sdk-into-your-mobile-app) on the official SDK integration docs from Microsoft. For example, these commands will clone, copy and run `intuneMAMConfigurator`: git clone https://github.com/msintuneappsdk/ms-intune-app-sdk-ios tmp --depth 1cp tmp/IntuneMAMConfigurator .rm -rf tmpchmod +x IntuneMAMConfigurator./IntuneMAMConfigurator -i ios/App/App/Info.plist -e ios/App/App/App.entitlements Copy When the command is successful it will report `IntuneMAMConfigurator[99999:999999] Success!!!`. If `IntuneMAMConfigurator` is not executable then you will get an error `permission denied`. 8\. Configure MSAL[#](https://ionic.io/docs/intune/ios-installation#8-configure-msal "Direct link to heading") --------------------------------------------------------------------------------------------------------------- MSAL configuration is required to enable brokered auth and other common Azure Active Directory authentication integrations. Follow the [MSAL Configuration](https://docs.microsoft.com/en-us/mem/intune/developer/app-sdk-ios#configure-msal-settings-for-the-intune-app-sdk) docs to finish setting up MSAL in your app. Additionally, in `AppDelegate.swift`, `import MSAL` and override the `application(_:open:options:)` method: import MSAL @UIApplicationMainclass AppDelegate: UIResponder, UIApplicationDelegate { func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool { // Called when the app was launched with a url. Feel free to add additional processing here, // but if you want the App API to support tracking app url opens, make sure to keep this call // return ApplicationDelegateProxy.shared.application(app, open: url, options: options) return MSALPublicClientApplication.handleMSALResponse(url, sourceApplication: options[UIApplication.OpenURLOptionsKey.sourceApplication] as? String) } Copy * [0\. Before starting](https://ionic.io/docs/intune/ios-installation#0-before-starting) * [1\. Add Frameworks](https://ionic.io/docs/intune/ios-installation#1-add-frameworks) * [2\. Configure Keychain](https://ionic.io/docs/intune/ios-installation#2-configure-keychain) * [3\. Enable Application Queries Schemes](https://ionic.io/docs/intune/ios-installation#3-enable-application-queries-schemes) * [4\. Set a NSFaceIDUsageDescription](https://ionic.io/docs/intune/ios-installation#4-set-a-nsfaceidusagedescription) * [5\. Update Target iOS Version](https://ionic.io/docs/intune/ios-installation#5-update-target-ios-version) * [6\. Disable Bitcode](https://ionic.io/docs/intune/ios-installation#6-disable-bitcode) * [7\. Run IntuneMAMConfigurator](https://ionic.io/docs/intune/ios-installation#7-run-intunemamconfigurator) * [8\. Configure MSAL](https://ionic.io/docs/intune/ios-installation#8-configure-msal) --- # Installation - Android - Intune [Skip to main content](https://ionic.io/docs/intune/android-installation#) Android Installation[#](https://ionic.io/docs/intune/android-installation#android-installation "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------- ### Configuring Gradle Plugin[#](https://ionic.io/docs/intune/android-installation#configuring-gradle-plugin "Direct link to heading") On Android, the Intune App SDK functions by wrapping key Android API classes with Intune-managed ones, using a Gradle plugin to replace Android API class references at build time. This Gradle plugin must be manually configured in your app to enable Intune MAM features in your app. To start, open your app in Android Studio. If using Capacitor, run one of the following commands. If using Cordova, manually open your `platforms/android` folder in Android Studio. npx cap open android# orionic capacitor open android Copy ### Install Gradle Plugin[#](https://ionic.io/docs/intune/android-installation#install-gradle-plugin "Direct link to heading") Next, open the `build.gradle` file for your main application (this is typically listed first and named `build.gradle (Project: android)` in the Gradle Scripts dropdown in Android Studio when opening your project). At the top, there should be a `buildscript` definition, and two new dependencies below need to be added to the `dependencies` definition: buildscript { repositories { google() jcenter() } dependencies { classpath 'com.android.tools.build:gradle:8.1.1' classpath 'com.google.gms:google-services:4.3.15' // ADD THIS: classpath "org.javassist:javassist:3.29.2-GA" // Capacitor users: add reference to the gradle plugin classpath files("../node_modules/@ionic-enterprise/intune/android/ms-intune-app-sdk-android/GradlePlugin/com.microsoft.intune.mam.build.jar") // Cordova users: add this line instead // classpath files("./app/src/main/libs/com.microsoft.intune.mam.build.jar") }} Copy **Capacitor only:** Next, there's an issue with the current version of the Intune App SDK for Android that requires the following maven repo for the `Duo-SDK-Feed` to be added to the `allprojects` `repositories` definition below the above `buildscript` definition: allprojects { repositories { google() jcenter() maven { // ADD THESE TWO LINES: url 'https://pkgs.dev.azure.com/MicrosoftDeviceSDK/DuoSDK-Public/_packaging/Duo-SDK-Feed/maven/v1' name 'Duo-SDK-Feed' } }} Copy **Capacitor only:** Open the `build.gradle` file for the `Module: android.app` and add the following lines to make sure the Intune App SDK Gradle plugin properly transforms these external libraries. Add any extra libraries your app uses that also need to be transformed: apply plugin: 'com.microsoft.intune.mam' Copy dependencies { ... implementation files("../../node_modules/@ionic-enterprise/intune/android/ms-intune-app-sdk-android/Microsoft.Intune.MAM.SDK.aar")} Copy Open the `gradle.properties` file and adding the following line: android.enableResourceOptimizations=false Copy ### Setting Android Manifest Configuration[#](https://ionic.io/docs/intune/android-installation#setting-android-manifest-configuration "Direct link to heading") Add to your `` declaration will look similar to: Copy To use brokered auth with Microsoft Authenticator or the Intune Company Portal app, add these `` to the top level of your `AndroidManifest.xml` file (directly inside the top-level `` declaration). Note: this is required as of Android 12 API Level 30, apps targeting older versions may function fine without it. Copy Finally, a new intent filter needs to be added inside your root ``. Replace the `YOUR_PACKAGE` and `YOUR_HASH` with the relevant values: Copy ### Setting Auth Configuration[#](https://ionic.io/docs/intune/android-installation#setting-auth-configuration "Direct link to heading") Configuring Auth involves two steps: finding your app's signing signature hash, and copying the MSAL config for your app's Redirect URIs from Azure AD #### Finding the Signature Hash[#](https://ionic.io/docs/intune/android-installation#finding-the-signature-hash "Direct link to heading") MSAL requires your app's signature hash in order to correctly use your app's Redirect URIs. To find this hash, read the [MSAL FAQ for Redirect URI Issues](https://github.com/AzureAD/microsoft-authentication-library-for-android/wiki/MSAL-FAQ#redirect-uri-issues) . If you are still struggling to find the correct hash for your app, this code may be dropped into the `MainActivity` `onCreate` method to log the package hash key for development, but keep in mind this should only be used for development mode. For production, follow the above FAQ: try { PackageInfo info = getPackageManager().getPackageInfo("your.package.name", PackageManager.GET_SIGNATURES); for (Signature signature : info.signatures) { MessageDigest md; md = MessageDigest.getInstance("SHA"); md.update(signature.toByteArray()); String something = new String(Base64.encode(md.digest(), 0)); Log.e("hash key", something); }} catch (Exception e) { Log.e("exception", e.toString());} Copy Once you have the correct hash, register your Redirect URI in the Azure AD dashboard: [Android AAD MSAL Dashboard](https://ionic.io/docs/intune/assets/files/android-aad-msal-config-92e04109ceec7187bfacfa71d1e019d9.png) #### Creating Configuration JSON File[#](https://ionic.io/docs/intune/android-installation#creating-configuration-json-file "Direct link to heading") The Intune App SDK for Android reads the JSON portion of your Azure AD auth configuration to configure the underlying Microsoft Authentication Library (MSAL). This file must be named `auth_config.json` and placed in a new `raw` resource directory in your app. First, create the new resource directory by right-clicking on the `res` folder and choosing New -> Android Resource Directory: ![Raw Resource Directory](https://ionic.io/docs/intune/assets/images/android-raw-directory-dropdown-3bac09d191582f45b1b3e0c978790b14.png) Then, in the wizard that pops up, choose `raw` from the `Resource type:` dropdown and click `OK`: ![Raw Resource Type](https://ionic.io/docs/intune/assets/images/android-raw-resource-directory-0800feb69e2631c490fa460026b3872c.png) Finally, right click on the new `raw` directory and click New -> File. Name the file `auth_config.json` and paste in the JSON portion of the auth config found in the Azure portal. This configuration can be found in Azure Active Directory -> App registrations -> Your App -> Authentication -> Platform configurations -> Android When selecting `View` on a `Redirect URI` entry: ![Android AAD MSAL Config](https://ionic.io/docs/intune/assets/images/android-aad-msal-config-92e04109ceec7187bfacfa71d1e019d9.png) ![Android AAD MSAL Config JSON](https://ionic.io/docs/intune/assets/images/android-aad-msal-config-json-60965fc2e308e2dbb70bd1010853babc.png) * [Android Installation](https://ionic.io/docs/intune/android-installation#android-installation) * [Configuring Gradle Plugin](https://ionic.io/docs/intune/android-installation#configuring-gradle-plugin) * [Install Gradle Plugin](https://ionic.io/docs/intune/android-installation#install-gradle-plugin) * [Setting Android Manifest Configuration](https://ionic.io/docs/intune/android-installation#setting-android-manifest-configuration) * [Setting Auth Configuration](https://ionic.io/docs/intune/android-installation#setting-auth-configuration) --- # Filesystem - Supported Plugins [Skip to main content](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#) This plugin presents a simple and intuitive interface for common filesytem operations such as reading/writing and listing the contents of directories. Installation[​](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#installation "Direct link to heading") --------------------------------------------------------------------------------------------------------------------------- If you have not already setup Ionic Enterprise in your app, [follow the one-time setup steps](https://ionic.io/docs/supported-plugins/setup) . Next, install the plugin: * Capacitor * Cordova npm install @ionic-enterprise/filesystemnpx cap sync Copy ionic cordova plugin add @ionic-enterprise/filesystem Copy Usage[​](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#usage "Direct link to heading") ------------------------------------------------------------------------------------------------------------- The Filesystem plugin ship with a native Angular & es2015+/Typescript wrappers as well as being available on window. // Angularimport { Filesystem } from '@ionic-enterprise/filesystem/ngx';import { Directories } from '@ionic-enterprise/filesystem';...constructor(private filesystem: Filesystem) { }async statApplicationDirectory() { const info = await this.filesystem.stat({path: '/', directory: Directories.Application}); console.log('Stat Info: ', info);}...// ES2015+/TypeScriptimport { Directories, Filesystem } from '@ionic-enterprise/filesystem';Filesystem.stat({path: '/', directory: Directories.Application}) .then((info) => console.log('Stat Info: ', info)) .catch((e) => console.log('Error occurred while doing stat: ', e));...// Vanilla JSdocument.addEventListener('deviceready', () => { IonicFilesystem.stat({path: '/', directory: IonicFilesystem.Directories.Application}) .then((info) => console.log('Stat Info: ', info)) .catch((e) => console.log('Error occurred while doing stat: ', e));}); Copy API Documentation[​](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#api-documentation "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------------------- You can find the API and interface documentation for everything below. The main classes to pay attention to are: * [Filesystem](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#filesystem) - This is the main API for interacting with the filesystem. * [Directories](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#directories) - The available directory locations for the application. * [Encodings](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#encodings) - The available encodings when reading/writing a file. Index[​](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#index "Direct link to heading") ------------------------------------------------------------------------------------------------------------- ### Enumerations[​](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#enumerations "Direct link to heading") * [Directories](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#directories) * [Encodings](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#encodings) ### Classes[​](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#classes "Direct link to heading") * [Filesystem](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#filesystem) ### Interfaces[​](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#interfaces "Direct link to heading") * [EmptyResult](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#emptyresult) * [FileReadOptions](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#filereadoptions) * [FileReadResult](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#filereadresult) * [FileWriteOptions](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#filewriteoptions) * [GetUriResult](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#geturiresult) * [MkdirOptions](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#mkdiroptions) * [PathOptions](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#pathoptions) * [ReaddirResult](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#readdirresult) * [StatResult](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#statresult) * * * Enumerations[​](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#enumerations-1 "Direct link to heading") ----------------------------------------------------------------------------------------------------------------------------- ### Directories[​](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#directories "Direct link to heading") **Directories**: The avaiable directories on the system ### Application[​](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#application "Direct link to heading") **Application**: = "APPLICATION" The Application directory * * * ### Cache[​](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#cache "Direct link to heading") **Cache**: = "CACHE" The Cache directory * * * ### Data[​](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#data "Direct link to heading") **Data**: = "DATA" The Data directory * * * ### Documents[​](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#documents "Direct link to heading") **Documents**: = "DOCUMENTS" The Documents directory * * * ### External[​](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#external "Direct link to heading") **External**: = "EXTERNAL" The external directory (Android only) * * * ### ExternalStorage[​](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#externalstorage "Direct link to heading") **ExternalStorage**: = "EXTERNAL\_STORAGE" The external storage directory (Android only) * * * * * * ### Encodings[​](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#encodings "Direct link to heading") **Encodings**: The possible encoding types ### ASCII[​](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#ascii "Direct link to heading") **ASCII**: = "ascii" ASCII encoding * * * ### UTF16[​](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#utf16 "Direct link to heading") **UTF16**: = "utf16" UTF16 encoding * * * ### UTF8[​](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#utf8 "Direct link to heading") **UTF8**: = "utf8" UTF8 encoding * * * * * * Classes[​](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#classes-1 "Direct link to heading") ------------------------------------------------------------------------------------------------------------------- ### Filesystem[​](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#filesystem "Direct link to heading") **Filesystem**: _**description**_: Provides API to read/write to the file sytems _**usage**_: // Angularimport { Filesystem } from '@ionic-enterprise/filesystem/ngx';import { Directories } from '@ionic-enterprise/filesystem';...constructor(private filesystem: Filesystem) { }async statApplicationDirectory() { const info = await this.filesystem.stat({path: '/', directory: Directories.Application}); console.log('Stat Info: ', info);}...// ES2015+/TypeScriptimport { Directories, Filesystem } from '@ionic-enterprise/filesystem';Filesystem.stat({path: '/', directory: Directories.Application}) .then((info) => console.log('Stat Info: ', info)) .catch((e) => console.log('Error occurred while doing stat: ', e));...// Vanilla JSdocument.addEventListener('deviceready', () => { IonicFilesystem.stat({path: '/', directory: IonicFilesystem.Directories.Application}) .then((info) => console.log('Stat Info: ', info)) .catch((e) => console.log('Error occurred while doing stat: ', e));}); Copy ### Directories[​](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#directories-1 "Direct link to heading") **● Directories**: _[Directories](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#directories) _ = Directories The avaiable directories on the system * * * ### Encodings[​](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#encodings-1 "Direct link to heading") **● Encodings**: _[Encodings](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#encodings) _ = Encodings The possible encoding types * * * ### appendFile[​](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#appendfile "Direct link to heading") ▸ **appendFile**(options: _[FileWriteOptions](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#filewriteoptions) _): `Promise`<[EmptyResult](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#emptyresult) \> Append to a file on disk in the specified location on device **Parameters:** | Name | Type | Description | | --- | --- | --- | | options | [FileWriteOptions](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#filewriteoptions) | options for the file append | **Returns:** `Promise`<[EmptyResult](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#emptyresult) \> a promise that resolves with the file write result * * * ### deleteFile[​](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#deletefile "Direct link to heading") ▸ **deleteFile**(options: _[PathOptions](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#pathoptions) _): `Promise`<[EmptyResult](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#emptyresult) \> Delete a file from disk **Parameters:** | Name | Type | Description | | --- | --- | --- | | options | [PathOptions](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#pathoptions) | options for the file delete | **Returns:** `Promise`<[EmptyResult](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#emptyresult) \> a promise that resolves with the deleted file data result * * * ### getUri[​](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#geturi "Direct link to heading") ▸ **getUri**(options: _[PathOptions](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#pathoptions) _): `Promise`<[GetUriResult](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#geturiresult) \> Return full File URI for a path and directory **Parameters:** | Name | Type | Description | | --- | --- | --- | | options | [PathOptions](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#pathoptions) | the options for the stat operation | **Returns:** `Promise`<[GetUriResult](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#geturiresult) \> a promise that resolves with the file stat result * * * ### mkdir[​](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#mkdir "Direct link to heading") ▸ **mkdir**(options: _[MkdirOptions](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#mkdiroptions) _): `Promise`<[EmptyResult](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#emptyresult) \> Create a directory. **Parameters:** | Name | Type | Description | | --- | --- | --- | | options | [MkdirOptions](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#mkdiroptions) | options for the mkdir | **Returns:** `Promise`<[EmptyResult](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#emptyresult) \> a promise that resolves with the mkdir result * * * ### readFile[​](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#readfile "Direct link to heading") ▸ **readFile**(options: _[FileReadOptions](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#filereadoptions) _): `Promise`<[FileReadResult](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#filereadresult) \> Read a file from disk **Parameters:** | Name | Type | Description | | --- | --- | --- | | options | [FileReadOptions](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#filereadoptions) | options for the file read | **Returns:** `Promise`<[FileReadResult](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#filereadresult) \> a promise that resolves with the read file data result * * * ### readdir[​](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#readdir "Direct link to heading") ▸ **readdir**(options: _[PathOptions](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#pathoptions) _): `Promise`<[ReaddirResult](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#readdirresult) \> Return a list of files from the directory (not recursive) **Parameters:** | Name | Type | Description | | --- | --- | --- | | options | [PathOptions](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#pathoptions) | the options for the readdir operation | **Returns:** `Promise`<[ReaddirResult](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#readdirresult) \> a promise that resolves with the readdir directory listing result * * * ### rmdir[​](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#rmdir "Direct link to heading") ▸ **rmdir**(options: _[PathOptions](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#pathoptions) _): `Promise`<[EmptyResult](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#emptyresult) \> Remove a directory **Parameters:** | Name | Type | Description | | --- | --- | --- | | options | [PathOptions](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#pathoptions) | the options for the directory remove | **Returns:** `Promise`<[EmptyResult](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#emptyresult) \> * * * ### stat[​](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#stat "Direct link to heading") ▸ **stat**(options: _[PathOptions](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#pathoptions) _): `Promise`<[StatResult](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#statresult) \> Return data about a file **Parameters:** | Name | Type | Description | | --- | --- | --- | | options | [PathOptions](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#pathoptions) | the options for the stat operation | **Returns:** `Promise`<[StatResult](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#statresult) \> a promise that resolves with the file stat result * * * ### writeFile[​](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#writefile "Direct link to heading") ▸ **writeFile**(options: _[FileWriteOptions](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#filewriteoptions) _): `Promise`<[EmptyResult](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#emptyresult) \> Write a file to disk in the specified location on device **Parameters:** | Name | Type | Description | | --- | --- | --- | | options | [FileWriteOptions](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#filewriteoptions) | options for the file write | **Returns:** `Promise`<[EmptyResult](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#emptyresult) \> a promise that resolves with the file write result * * * * * * Interfaces[​](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#interfaces-1 "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------- ### EmptyResult[​](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#emptyresult "Direct link to heading") **EmptyResult**: * * * ### FileReadOptions[​](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#filereadoptions "Direct link to heading") **FileReadOptions**: ### `` directory[​](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#optional-directory "Direct link to heading") **● directory**: _[Directories](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#directories) _ The directory to start in * * * ### `` encoding[​](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#optional-encoding "Direct link to heading") **● encoding**: _[Encodings](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#encodings) _ The encoding to read/write the file in, if not provided, data is read as binary and returned as base64 encoded data. Pass [Encodings.UTF8](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#encodings.utf8) to read data as string * * * ### path[​](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#path "Direct link to heading") **● path**: _`string`_ The path to the file or directory with one of the [Directories](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#directories) * * * * * * ### FileReadResult[​](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#filereadresult "Direct link to heading") **FileReadResult**: ### data[​](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#data-1 "Direct link to heading") **● data**: _`string`_ The data in the file * * * * * * ### FileWriteOptions[​](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#filewriteoptions "Direct link to heading") **FileWriteOptions**: ### data[​](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#data-2 "Direct link to heading") **● data**: _`string`_ The data to write * * * ### `` directory[​](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#optional-directory-1 "Direct link to heading") **● directory**: _[Directories](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#directories) _ The directory to start in * * * ### `` encoding[​](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#optional-encoding-1 "Direct link to heading") **● encoding**: _[Encodings](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#encodings) _ The encoding to write the file in * * * ### path[​](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#path-1 "Direct link to heading") **● path**: _`string`_ The path to the file or directory with one of the [Directories](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#directories) * * * * * * ### GetUriResult[​](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#geturiresult "Direct link to heading") **GetUriResult**: ### uri[​](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#uri "Direct link to heading") **● uri**: _`string`_ * * * * * * ### MkdirOptions[​](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#mkdiroptions "Direct link to heading") **MkdirOptions**: ### createIntermediateDirectories[​](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#createintermediatedirectories "Direct link to heading") **● createIntermediateDirectories**: _`boolean`_ Whether to create any missing parent directories as well * * * ### `` directory[​](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#optional-directory-2 "Direct link to heading") **● directory**: _[Directories](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#directories) _ The directory to start in * * * ### path[​](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#path-2 "Direct link to heading") **● path**: _`string`_ The path to the file or directory with one of the [Directories](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#directories) * * * * * * ### PathOptions[​](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#pathoptions "Direct link to heading") **PathOptions**: ### `` directory[​](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#optional-directory-3 "Direct link to heading") **● directory**: _[Directories](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#directories) _ The directory to start in * * * ### path[​](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#path-3 "Direct link to heading") **● path**: _`string`_ The path to the file or directory with one of the [Directories](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#directories) * * * * * * ### ReaddirResult[​](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#readdirresult "Direct link to heading") **ReaddirResult**: ### files[​](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#files "Direct link to heading") **● files**: _`string`\[\]_ the list of files in the directory * * * * * * ### StatResult[​](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#statresult "Direct link to heading") **StatResult**: ### `` ctime[​](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#optional-ctime "Direct link to heading") **● ctime**: _`undefined` | `number`_ The created time if available * * * ### mtime[​](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#mtime "Direct link to heading") **● mtime**: _`number`_ The last modified time * * * ### size[​](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#size "Direct link to heading") **● size**: _`number`_ The size of the item * * * ### type[​](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#type "Direct link to heading") **● type**: _"file" | "directory"_ Whether the item is a file or a directory * * * ### uri[​](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#uri-1 "Direct link to heading") **● uri**: _`string`_ The size of the item * * * * * * Change Log[​](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#change-log "Direct link to heading") ----------------------------------------------------------------------------------------------------------------------- ### \[1.0.2\] (2019-08-02)[​](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#102-2019-08-02 "Direct link to heading") ### Bug Fixes[​](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#bug-fixes "Direct link to heading") * **iOS:** Update iOS deleteFile method bug where deleteFile would actually make a directory. * [Usage](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#usage) * [API Documentation](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#api-documentation) * [Index](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#index) * [Enumerations](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#enumerations) * [Classes](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#classes) * [Interfaces](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#interfaces) * [Enumerations](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#enumerations-1) * [Directories](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#directories) * [Application](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#application) * [Cache](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#cache) * [Data](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#data) * [Documents](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#documents) * [External](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#external) * [ExternalStorage](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#externalstorage) * [Encodings](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#encodings) * [ASCII](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#ascii) * [UTF16](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#utf16) * [UTF8](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#utf8) * [Classes](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#classes-1) * [Filesystem](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#filesystem) * [Directories](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#directories-1) * [Encodings](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#encodings-1) * [appendFile](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#appendfile) * [deleteFile](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#deletefile) * [getUri](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#geturi) * [mkdir](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#mkdir) * [readFile](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#readfile) * [readdir](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#readdir) * [rmdir](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#rmdir) * [stat](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#stat) * [writeFile](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#writefile) * [Interfaces](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#interfaces-1) * [EmptyResult](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#emptyresult) * [FileReadOptions](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#filereadoptions) * [`` directory](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#optional-directory) * [`` encoding](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#optional-encoding) * [path](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#path) * [FileReadResult](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#filereadresult) * [data](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#data-1) * [FileWriteOptions](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#filewriteoptions) * [data](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#data-2) * [`` directory](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#optional-directory-1) * [`` encoding](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#optional-encoding-1) * [path](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#path-1) * [GetUriResult](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#geturiresult) * [uri](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#uri) * [MkdirOptions](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#mkdiroptions) * [createIntermediateDirectories](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#createintermediatedirectories) * [`` directory](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#optional-directory-2) * [path](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#path-2) * [PathOptions](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#pathoptions) * [`` directory](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#optional-directory-3) * [path](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#path-3) * [ReaddirResult](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#readdirresult) * [files](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#files) * [StatResult](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#statresult) * [`` ctime](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#optional-ctime) * [mtime](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#mtime) * [size](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#size) * [type](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#type) * [uri](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#uri-1) * [Change Log](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#change-log) * [1.0.2 (2019-08-02)](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#102-2019-08-02) * [Bug Fixes](https://ionic.io/docs/supported-plugins/filesystem/1.0.X/filesystem#bug-fixes) --- # Contacts - Supported Plugins [Skip to main content](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#) The Contacts plugin provides access to read, write, or select device contacts. Installation[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#installation "Direct link to heading") ----------------------------------------------------------------------------------------------------------------------- If you have not already setup Ionic Enterprise in your app, [follow the one-time setup steps](https://ionic.io/docs/supported-plugins/setup) . Next, install the plugin: * Capacitor * Cordova npm install @ionic-enterprise/contactsnpx cap sync Copy ionic cordova plugin add @ionic-enterprise/contacts Copy Usage[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#usage "Direct link to heading") --------------------------------------------------------------------------------------------------------- The Contacts plugin ship with a native Angular & es2015+/Typescript wrappers as well as being available on window. // Angularimport { Contacts } from '@ionic-enterprise/contacts/ngx';import { Contact, ContactName, ContactField } from '@ionic-enterprise/contacts';...constructor(private contacts: Contacts) { }async createContact() { let contact = this.contacts.create(); contact.name = new ContactName(null, 'Smith', 'John'); contact.phoneNumbers = [new ContactField('mobile', '6471234567')]; contact.save().then( () => console.log('Contact saved!', contact), (error: any) => console.error('Error saving contact.', error) );}...// ES2015+/TypeScriptimport { Contacts, Contact, ContactName, ContactField } from '@ionic-enterprise/contacts';let contact = Contacts.create();contact.name = new ContactName(null, 'Smith', 'John');contact.phoneNumbers = [new ContactField('mobile', '6471234567')];contact.save().then( () => console.log('Contact saved!', contact), (error: any) => console.error('Error saving contact.', error));...// Vanilla JSdocument.addEventListener('deviceready', () => { let contact = IonicContacts.create(); contact.name = {familyName: 'Smith', givenName: 'John'}; contact.phoneNumbers = {type: 'mobile', value: '6471234567'}; contact.save().then( () => console.log('Contact saved!', contact), (error) => console.error('Error saving contact.', error) );}); Copy Index[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#index "Direct link to heading") --------------------------------------------------------------------------------------------------------- ### Classes[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#classes "Direct link to heading") * [Contact](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contact) * [ContactAddress](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contactaddress) * [ContactError](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contacterror) * [ContactField](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contactfield) * [ContactFindOptions](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contactfindoptions) * [ContactName](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contactname) * [ContactOrganization](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contactorganization) * [Contacts](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contacts) ### Type aliases[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#type-aliases "Direct link to heading") * [ContactFieldType](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contactfieldtype) * * * Classes[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#classes-1 "Direct link to heading") --------------------------------------------------------------------------------------------------------------- ### Contact[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contact "Direct link to heading") **Contact**: Contains information about a single contact. ### constructor[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#constructor "Direct link to heading") ⊕ **new Contact**(id?: _`undefined` | `string`_, displayName?: _`undefined` | `string`_, name?: _[ContactName](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contactname) _, nickname?: _`undefined` | `string`_, phoneNumbers?: _[ContactField](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contactfield) \[\]_, emails?: _[ContactField](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contactfield) \[\]_, addresses?: _[ContactAddress](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contactaddress) \[\]_, ims?: _[ContactField](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contactfield) \[\]_, organizations?: _[ContactOrganization](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contactorganization) \[\]_, birthday?: _`Date` | `string` | `null`_, note?: _`undefined` | `string`_, photos?: _[ContactField](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contactfield) \[\]_, categories?: _[ContactField](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contactfield) \[\]_, urls?: _[ContactField](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contactfield) \[\]_): [Contact](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contact) **Parameters:** | Name | Type | | --- | --- | | `Optional` id | `undefined` \| `string` | | `Optional` displayName | `undefined` \| `string` | | `Optional` name | [ContactName](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contactname) | | `Optional` nickname | `undefined` \| `string` | | `Optional` phoneNumbers | [ContactField](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contactfield)
\[\] | | `Optional` emails | [ContactField](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contactfield)
\[\] | | `Optional` addresses | [ContactAddress](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contactaddress)
\[\] | | `Optional` ims | [ContactField](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contactfield)
\[\] | | `Optional` organizations | [ContactOrganization](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contactorganization)
\[\] | | `Optional` birthday | `Date` \| `string` \| `null` | | `Optional` note | `undefined` \| `string` | | `Optional` photos | [ContactField](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contactfield)
\[\] | | `Optional` categories | [ContactField](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contactfield)
\[\] | | `Optional` urls | [ContactField](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contactfield)
\[\] | **Returns:** [Contact](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contact) * * * ### `` addresses[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-addresses "Direct link to heading") **● addresses**: _[ContactAddress](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contactaddress) \[\] | `null`_ An array of all the contact's addresses. * * * ### `` birthday[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-birthday "Direct link to heading") **● birthday**: _`Date` | `string` | `null`_ The birthday of the contact. * * * ### `` categories[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-categories "Direct link to heading") **● categories**: _[ContactField](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contactfield) \[\] | `null`_ An array of all the user-defined categories associated with the contact. * * * ### `` displayName[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-displayname "Direct link to heading") **● displayName**: _`string` | `null`_ The name of this Contact, suitable for display to end users. * * * ### `` emails[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-emails "Direct link to heading") **● emails**: _[ContactField](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contactfield) \[\] | `null`_ An array of all the contact's email addresses. * * * ### `` id[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-id "Direct link to heading") **● id**: _`string` | `null`_ A globally unique identifier. * * * ### `` ims[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-ims "Direct link to heading") **● ims**: _[ContactField](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contactfield) \[\] | `null`_ An array of all the contact's IM addresses. * * * ### `` name[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-name "Direct link to heading") **● name**: _[ContactName](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contactname) | `null`_ An object containing all components of a persons name. * * * ### `` nickname[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-nickname "Direct link to heading") **● nickname**: _`string` | `null`_ A casual name by which to address the contact. * * * ### `` note[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-note "Direct link to heading") **● note**: _`string` | `null`_ A note about the contact on Android. * * * ### `` organizations[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-organizations "Direct link to heading") **● organizations**: _[ContactOrganization](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contactorganization) \[\] | `null`_ An array of all the contact's organizations. * * * ### `` phoneNumbers[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-phonenumbers "Direct link to heading") **● phoneNumbers**: _[ContactField](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contactfield) \[\] | `null`_ An array of all the contact's phone numbers. * * * ### `` photos[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-photos "Direct link to heading") **● photos**: _[ContactField](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contactfield) \[\] | `null`_ An array of the contact's photos. * * * ### `` rawId[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-rawid "Direct link to heading") **● rawId**: _`string` | `null`_ A globally unique identifier on Android. * * * ### `` urls[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-urls "Direct link to heading") **● urls**: _[ContactField](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contactfield) \[\] | `null`_ An array of web pages associated with the contact. * * * ### clone[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#clone "Direct link to heading") ▸ **clone**(): [Contact](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contact) Creates a deep copy of this Contact. With the contact ID set to null. **Returns:** [Contact](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contact) copy of this Contact * * * ### display[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#display "Direct link to heading") ▸ **display**(allowEdit?: _`undefined` | `false` | `true`_): `Promise`<`any`\> iOS only Display a contact in the native Contact Picker UI **Parameters:** | Name | Type | Description | | --- | --- | --- | | `Optional` allowEdit | `undefined` \| `false` \| `true` | true display the contact and allow editing it false (default) display contact without editing | **Returns:** `Promise`<`any`\> * * * ### remove[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#remove "Direct link to heading") ▸ **remove**(): `Promise`<`any`\> Removes contact from device storage. **Returns:** `Promise`<`any`\> * * * ### save[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#save "Direct link to heading") ▸ **save**(): `Promise`<`any`\> Persists contact to device storage. **Returns:** `Promise`<`any`\> * * * * * * ### ContactAddress[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contactaddress "Direct link to heading") **ContactAddress**: Contact address. ### constructor[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#constructor-1 "Direct link to heading") ⊕ **new ContactAddress**(pref?: _`undefined` | `false` | `true`_, type?: _`undefined` | `string`_, formatted?: _`undefined` | `string`_, streetAddress?: _`undefined` | `string`_, locality?: _`undefined` | `string`_, region?: _`undefined` | `string`_, postalCode?: _`undefined` | `string`_, country?: _`undefined` | `string`_): [ContactAddress](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contactaddress) **Parameters:** | Name | Type | | --- | --- | | `Optional` pref | `undefined` \| `false` \| `true` | | `Optional` type | `undefined` \| `string` | | `Optional` formatted | `undefined` \| `string` | | `Optional` streetAddress | `undefined` \| `string` | | `Optional` locality | `undefined` \| `string` | | `Optional` region | `undefined` \| `string` | | `Optional` postalCode | `undefined` \| `string` | | `Optional` country | `undefined` \| `string` | **Returns:** [ContactAddress](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contactaddress) * * * ### `` country[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-country "Direct link to heading") **● country**: _`string` | `null`_ The country name. * * * ### `` formatted[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-formatted "Direct link to heading") **● formatted**: _`string` | `null`_ The full address formatted for display. * * * ### `` id[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-id-1 "Direct link to heading") **● id**: _`string` | `null`_ unique identifier, should only be set by native code * * * ### `` locality[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-locality "Direct link to heading") **● locality**: _`string` | `null`_ The city or locality. * * * ### `` postalCode[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-postalcode "Direct link to heading") **● postalCode**: _`string` | `null`_ The zip code or postal code. * * * ### `` pref[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-pref "Direct link to heading") **● pref**: _`undefined` | `false` | `true`_ Set to true if this ContactAddress contains the user's preferred value. * * * ### `` region[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-region "Direct link to heading") **● region**: _`string` | `null`_ The state or region. * * * ### `` streetAddress[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-streetaddress "Direct link to heading") **● streetAddress**: _`string` | `null`_ The full street address. * * * ### `` type[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-type "Direct link to heading") **● type**: _`string` | `null`_ A string indicating what type of field this is, home for example. * * * * * * ### ContactError[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contacterror "Direct link to heading") **ContactError**: ContactError. An error code assigned by an implementation when an error has occurred _**constructor**_: ### constructor[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#constructor-2 "Direct link to heading") ⊕ **new ContactError**(code: _`number`_): [ContactError](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contacterror) **Parameters:** | Name | Type | | --- | --- | | code | `number` | **Returns:** [ContactError](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contacterror) * * * ### code[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#code "Direct link to heading") **● code**: _`number`_ Error code * * * ### `` message[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-message "Direct link to heading") **● message**: _`undefined` | `string`_ Error message * * * ### `` INVALID\_ARGUMENT\_ERROR[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#static-invalid_argument_error "Direct link to heading") **● INVALID\_ARGUMENT\_ERROR**: _`number`_ = 1 * * * ### `` IO\_ERROR[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#static-io_error "Direct link to heading") **● IO\_ERROR**: _`number`_ = 4 * * * ### `` NOT\_SUPPORTED\_ERROR[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#static-not_supported_error "Direct link to heading") **● NOT\_SUPPORTED\_ERROR**: _`number`_ = 5 * * * ### `` OPERATION\_CANCELLED\_ERROR[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#static-operation_cancelled_error "Direct link to heading") **● OPERATION\_CANCELLED\_ERROR**: _`number`_ = 6 * * * ### `` PENDING\_OPERATION\_ERROR[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#static-pending_operation_error "Direct link to heading") **● PENDING\_OPERATION\_ERROR**: _`number`_ = 3 * * * ### `` PERMISSION\_DENIED\_ERROR[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#static-permission_denied_error "Direct link to heading") **● PERMISSION\_DENIED\_ERROR**: _`number`_ = 20 * * * ### `` TIMEOUT\_ERROR[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#static-timeout_error "Direct link to heading") **● TIMEOUT\_ERROR**: _`number`_ = 2 * * * ### `` UNKNOWN\_ERROR[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#static-unknown_error "Direct link to heading") **● UNKNOWN\_ERROR**: _`number`_ = 0 Error codes * * * * * * ### ContactField[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contactfield "Direct link to heading") **ContactField**: Generic contact field. ### constructor[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#constructor-3 "Direct link to heading") ⊕ **new ContactField**(type?: _`undefined` | `string`_, value?: _`undefined` | `string`_, pref?: _`undefined` | `false` | `true`_): [ContactField](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contactfield) **Parameters:** | Name | Type | | --- | --- | | `Optional` type | `undefined` \| `string` | | `Optional` value | `undefined` \| `string` | | `Optional` pref | `undefined` \| `false` \| `true` | **Returns:** [ContactField](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contactfield) * * * ### `` id[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-id-2 "Direct link to heading") **● id**: _`string` | `null`_ unique identifier, should only be set by native code * * * ### `` pref[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-pref-1 "Direct link to heading") **● pref**: _`undefined` | `false` | `true`_ Set to true if this ContactField contains the user's preferred value. * * * ### `` type[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-type-1 "Direct link to heading") **● type**: _`string` | `null`_ A string that indicates what type of field this is, home for example. * * * ### `` value[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-value "Direct link to heading") **● value**: _`string` | `null`_ The value of the field, such as a phone number or email address. * * * * * * ### ContactFindOptions[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contactfindoptions "Direct link to heading") **ContactFindOptions**: ContactFindOptions. Search options to filter ### constructor[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#constructor-4 "Direct link to heading") ⊕ **new ContactFindOptions**(filter?: _`undefined` | `string`_, multiple?: _`undefined` | `false` | `true`_, desiredFields?: _`string`\[\]_, hasPhoneNumber?: _`undefined` | `false` | `true`_): [ContactFindOptions](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contactfindoptions) **Parameters:** | Name | Type | | --- | --- | | `Optional` filter | `undefined` \| `string` | | `Optional` multiple | `undefined` \| `false` \| `true` | | `Optional` desiredFields | `string`\[\] | | `Optional` hasPhoneNumber | `undefined` \| `false` \| `true` | **Returns:** [ContactFindOptions](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contactfindoptions) * * * ### `` desiredFields[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-desiredfields "Direct link to heading") **● desiredFields**: _`string`\[\]_ Contact fields to be returned back. If specified, the resulting Contact object only features values for these fields. * * * ### `` filter[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-filter "Direct link to heading") **● filter**: _`undefined` | `string`_ The search string used to find navigator.contacts. * * * ### `` hasPhoneNumber[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-hasphonenumber "Direct link to heading") **● hasPhoneNumber**: _`undefined` | `false` | `true`_ (Android only): Filters the search to only return contacts with a phone number informed. * * * ### `` multiple[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-multiple "Direct link to heading") **● multiple**: _`undefined` | `false` | `true`_ Determines if the find operation returns multiple navigator.contacts. Defaults to false. * * * * * * ### ContactName[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contactname "Direct link to heading") **ContactName**: Contact name. ### constructor[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#constructor-5 "Direct link to heading") ⊕ **new ContactName**(formatted?: _`undefined` | `string`_, familyName?: _`undefined` | `string`_, givenName?: _`undefined` | `string`_, middleName?: _`undefined` | `string`_, honorificPrefix?: _`undefined` | `string`_, honorificSuffix?: _`undefined` | `string`_): [ContactName](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contactname) **Parameters:** | Name | Type | | --- | --- | | `Optional` formatted | `undefined` \| `string` | | `Optional` familyName | `undefined` \| `string` | | `Optional` givenName | `undefined` \| `string` | | `Optional` middleName | `undefined` \| `string` | | `Optional` honorificPrefix | `undefined` \| `string` | | `Optional` honorificSuffix | `undefined` \| `string` | **Returns:** [ContactName](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contactname) * * * ### `` familyName[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-familyname "Direct link to heading") **● familyName**: _`string` | `null`_ The contact's family name. * * * ### `` formatted[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-formatted-1 "Direct link to heading") **● formatted**: _`string` | `null`_ The complete name of the contact. * * * ### `` givenName[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-givenname "Direct link to heading") **● givenName**: _`string` | `null`_ The contact's given name. * * * ### `` honorificPrefix[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-honorificprefix "Direct link to heading") **● honorificPrefix**: _`string` | `null`_ The contact's prefix (example Mr. or Dr.) * * * ### `` honorificSuffix[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-honorificsuffix "Direct link to heading") **● honorificSuffix**: _`string` | `null`_ The contact's suffix (example Esq.). * * * ### `` middleName[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-middlename "Direct link to heading") **● middleName**: _`string` | `null`_ The contact's middle name. * * * * * * ### ContactOrganization[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contactorganization "Direct link to heading") **ContactOrganization**: Contact organization. ### constructor[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#constructor-6 "Direct link to heading") ⊕ **new ContactOrganization**(type?: _`undefined` | `string`_, name?: _`undefined` | `string`_, department?: _`undefined` | `string`_, title?: _`undefined` | `string`_, pref?: _`undefined` | `false` | `true`_): [ContactOrganization](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contactorganization) **Parameters:** | Name | Type | | --- | --- | | `Optional` type | `undefined` \| `string` | | `Optional` name | `undefined` \| `string` | | `Optional` department | `undefined` \| `string` | | `Optional` title | `undefined` \| `string` | | `Optional` pref | `undefined` \| `false` \| `true` | **Returns:** [ContactOrganization](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contactorganization) * * * ### `` department[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-department "Direct link to heading") **● department**: _`string` | `null`_ The department the contract works for. * * * ### `` id[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-id-3 "Direct link to heading") **● id**: _`string` | `null`_ unique identifier, should only be set by native code * * * ### `` name[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-name-1 "Direct link to heading") **● name**: _`string` | `null`_ The name of the organization. * * * ### `` pref[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-pref-2 "Direct link to heading") **● pref**: _`undefined` | `false` | `true`_ Set to true if this ContactOrganization contains the user's preferred value. * * * ### `` title[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-title "Direct link to heading") **● title**: _`string` | `null`_ The contact's title at the organization. * * * ### `` type[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-type-2 "Direct link to heading") **● type**: _`string` | `null`_ A string that indicates what type of field this is, home for example. * * * * * * ### Contacts[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contacts-1 "Direct link to heading") **Contacts**: Access and manage Contacts on the device. ### create[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#create "Direct link to heading") ▸ **create**(properties?: _`any`_): [Contact](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contact) This function creates a new contact, but it does not persist the contact to device storage. To persist the contact to device storage, invoke contact.save(). **Parameters:** | Name | Type | Description | | --- | --- | --- | | `Optional` properties | `any` | an object whose properties will be examined to create a new Contact | **Returns:** [Contact](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contact) new Contact object * * * ### find[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#find "Direct link to heading") ▸ **find**(fields: _[ContactFieldType](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contactfieldtype) \[\]_, options?: _[ContactFindOptions](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contactfindoptions) _): `Promise`<[Contact](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contact) \[\]> Returns an array of Contacts matching the search criteria. **Parameters:** | Name | Type | Description | | --- | --- | --- | | fields | [ContactFieldType](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contactfieldtype)
\[\] | that should be searched | | `Optional` options | [ContactFindOptions](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contactfindoptions) | that can be applied to contact searching | **Returns:** `Promise`<[Contact](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contact) \[\]> a promise that resolves with the array of Contacts matching search criteria * * * ### newContactUI[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#newcontactui "Direct link to heading") ▸ **newContactUI**(): `Promise`<`string`\> iOS only Create a contact using the iOS Contact Picker UI returns: a promise that resolves with the id of the created contact as param to successCallback **Returns:** `Promise`<`string`\> * * * ### pickContact[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#pickcontact "Direct link to heading") ▸ **pickContact**(): `Promise`<[Contact](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contact) \> This function picks contact from phone using contact picker UI **Returns:** `Promise`<[Contact](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contact) \> a promise that resolves with the selected Contact object * * * * * * Type aliases[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#type-aliases-1 "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------- ### ContactFieldType[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contactfieldtype "Direct link to heading") **Ƭ ContactFieldType**: _"_" | "addresses" | "birthday" | "categories" | "country" | "department" | "displayName" | "emails" | "name.familyName" | "name.formatted" | "name.givenName" | "name.honorificPrefix" | "name.honorificSuffix" | "id" | "ims" | "locality" | "name.middleName" | "name" | "nickname" | "note" | "organizations" | "phoneNumbers" | "photos" | "postalCode" | "region" | "streetAddress" | "title" | "urls"\* * * * ### \[1.0.6\] (2020-02-07)[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#106-2020-02-07 "Direct link to heading") ### Bug Fixes[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#bug-fixes "Direct link to heading") * **ios:** make save work on existing contacts ### \[1.0.5\] (2019-11-22)[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#105-2019-11-22 "Direct link to heading") ### Bug Fixes[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#bug-fixes-1 "Direct link to heading") * prevent devideready block when package is not installed as plugin ### \[1.0.4\] (2019-11-08)[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#104-2019-11-08 "Direct link to heading") ### Bug Fixes[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#bug-fixes-2 "Direct link to heading") * **ios:** make pickContact prompt for permission if not granted ### \[1.0.3\] (2019-11-04)[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#103-2019-11-04 "Direct link to heading") ### Bug Fixes[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#bug-fixes-3 "Direct link to heading") * make plugin don't break web context ### \[1.0.2\] (2019-10-02)[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#102-2019-10-02 "Direct link to heading") ### Bug Fixes[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#bug-fixes-4 "Direct link to heading") * **ios:** remove contact notes code to work on iOS 13 ### 1.0.1 (2019-09-20)[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#101-2019-09-20 "Direct link to heading") ### Bug Fixes[​](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#bug-fixes-5 "Direct link to heading") * plugin files not included on published package * [Usage](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#usage) * [Index](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#index) * [Classes](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#classes) * [Type aliases](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#type-aliases) * [Classes](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#classes-1) * [Contact](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contact) * [constructor](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#constructor) * [`` addresses](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-addresses) * [`` birthday](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-birthday) * [`` categories](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-categories) * [`` displayName](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-displayname) * [`` emails](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-emails) * [`` id](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-id) * [`` ims](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-ims) * [`` name](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-name) * [`` nickname](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-nickname) * [`` note](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-note) * [`` organizations](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-organizations) * [`` phoneNumbers](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-phonenumbers) * [`` photos](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-photos) * [`` rawId](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-rawid) * [`` urls](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-urls) * [clone](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#clone) * [display](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#display) * [remove](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#remove) * [save](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#save) * [ContactAddress](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contactaddress) * [constructor](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#constructor-1) * [`` country](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-country) * [`` formatted](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-formatted) * [`` id](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-id-1) * [`` locality](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-locality) * [`` postalCode](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-postalcode) * [`` pref](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-pref) * [`` region](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-region) * [`` streetAddress](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-streetaddress) * [`` type](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-type) * [ContactError](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contacterror) * [constructor](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#constructor-2) * [code](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#code) * [`` message](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-message) * [`` INVALID\_ARGUMENT\_ERROR](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#static-invalid_argument_error) * [`` IO\_ERROR](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#static-io_error) * [`` NOT\_SUPPORTED\_ERROR](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#static-not_supported_error) * [`` OPERATION\_CANCELLED\_ERROR](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#static-operation_cancelled_error) * [`` PENDING\_OPERATION\_ERROR](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#static-pending_operation_error) * [`` PERMISSION\_DENIED\_ERROR](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#static-permission_denied_error) * [`` TIMEOUT\_ERROR](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#static-timeout_error) * [`` UNKNOWN\_ERROR](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#static-unknown_error) * [ContactField](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contactfield) * [constructor](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#constructor-3) * [`` id](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-id-2) * [`` pref](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-pref-1) * [`` type](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-type-1) * [`` value](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-value) * [ContactFindOptions](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contactfindoptions) * [constructor](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#constructor-4) * [`` desiredFields](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-desiredfields) * [`` filter](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-filter) * [`` hasPhoneNumber](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-hasphonenumber) * [`` multiple](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-multiple) * [ContactName](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contactname) * [constructor](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#constructor-5) * [`` familyName](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-familyname) * [`` formatted](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-formatted-1) * [`` givenName](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-givenname) * [`` honorificPrefix](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-honorificprefix) * [`` honorificSuffix](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-honorificsuffix) * [`` middleName](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-middlename) * [ContactOrganization](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contactorganization) * [constructor](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#constructor-6) * [`` department](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-department) * [`` id](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-id-3) * [`` name](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-name-1) * [`` pref](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-pref-2) * [`` title](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-title) * [`` type](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#optional-type-2) * [Contacts](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contacts-1) * [create](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#create) * [find](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#find) * [newContactUI](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#newcontactui) * [pickContact](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#pickcontact) * [Type aliases](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#type-aliases-1) * [ContactFieldType](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#contactfieldtype) * [1.0.6 (2020-02-07)](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#106-2020-02-07) * [Bug Fixes](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#bug-fixes) * [1.0.5 (2019-11-22)](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#105-2019-11-22) * [Bug Fixes](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#bug-fixes-1) * [1.0.4 (2019-11-08)](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#104-2019-11-08) * [Bug Fixes](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#bug-fixes-2) * [1.0.3 (2019-11-04)](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#103-2019-11-04) * [Bug Fixes](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#bug-fixes-3) * [1.0.2 (2019-10-02)](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#102-2019-10-02) * [Bug Fixes](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#bug-fixes-4) * [1.0.1 (2019-09-20)](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#101-2019-09-20) * [Bug Fixes](https://ionic.io/docs/supported-plugins/contacts/1.0.X/contacts#bug-fixes-5) --- # Usage - Intune [Skip to main content](https://ionic.io/docs/intune/usage#) **Interested in Intune support?** [Get in touch](https://ionic.io/contact/sales) . Capacitor: Importing[#](https://ionic.io/docs/intune/usage#capacitor-importing "Direct link to heading") --------------------------------------------------------------------------------------------------------- Import from `@ionic-enterprise/intune`, for example: import { IntuneMAM } from '@ionic-enterprise/intune'; Copy Cordova: Importing, TypeScript, and Usage[#](https://ionic.io/docs/intune/usage#cordova-importing-typescript-and-usage "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------------------------------- Cordova developers can access `IntuneMAM` directly on `window`. For using TypeScript, import the types as such (note the `import type`): import type { IntuneMAMPlugin, // If using, other types can be imported as such: IntuneMAMAppConfig, IntuneMAMGroupName, IntuneMAMPolicy, IntuneMAMUser, IntuneMAMVersionInfo,} from '@ionic-enterprise/intune/cordova/definitions'; Copy Then, when accessing `IntuneMAM`, it can be typed like this: const IntuneMAM = (window as any).IntuneMAM as IntuneMAMPlugin; Copy Accessing `IntuneMAM` should be done _after_ `deviceready` fires, regardless of the above. MSAL Acquire Token and Intune Register Flow[#](https://ionic.io/docs/intune/usage#msal-acquire-token-and-intune-register-flow "Direct link to heading") -------------------------------------------------------------------------------------------------------------------------------------------------------- For apps that need access to a token from MSAL (to make authenticated requests to Microsoft graph services, for example), must follow the `acquireToken`, `acquireTokenSilent`, and `registerAndEnrollAccount` flow. First, the user must log in using `acquireToken` which presents an interactive authentication experience, and then `registerAndEnrollAccount` should be called to enroll the user in Intune: // Login page componentconst authInfo = await IntuneMAM.acquireToken({ scopes: ['scope-1', 'scope-2'], forcePrompt: false}); try { await IntuneMAM.registerAndEnrollAccount({ accountId: authInfo.accountId, });} catch (error) { // Handle errors} Copy The `forcePrompt` option can be used to force the user to re-enter their login information. The default is `false`. On successfully enrolling your application will close on iOS. If your application does not need to be managed by your company you do not need to call `registerAndEnrollAccount`. The response from `acquireToken` and `acquireTokenSilent` will be of the form: export interface IntuneMAMAcquireToken { accountId: string; accessToken: string; accountIdentifier: string; idToken?: string;} Copy Then, on subsequent loads, the app should request a token silently using `acquireTokenSilent` and passing in the `accountId` for the user. If that fails, then the app must present the interactive authentication flow again, for example: // Home/App componenttry { const tokenInfo = await IntuneMAM.acquireTokenSilent({ scopes: ['https://graph.microsoft.com/.default'], accountId: this.accountId, forceRefresh: false }); setTokenInfo(tokenInfo);} catch { console.error('Unable to silently acquire token, getting interactive'); const tokenInfo = await IntuneMAM.acquireToken({ scopes: ['https://graph.microsoft.com/.default'], }); setTokenInfo(tokenInfo);} Copy Note: You can choose to set the `forceRefresh` property to `true` to force a new token to be obtained. The default `false` will return a cached token if the token has not expired. See the [Demo app](https://ionic.io/docs/intune/demo-app) for an example of this flow. `acquireToken` and `acquireTokenSilent` both expect a set of scopes to be provided, (for example `"https://graph.microsoft.com/.default"`). Learn more about MSAL Scopes: [https://docs.microsoft.com/en-us/azure/active-directory/develop/msal-acquire-cache-tokens](https://docs.microsoft.com/en-us/azure/active-directory/develop/msal-acquire-cache-tokens) [https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-permissions-and-consent#openid-connect-scopes](https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-permissions-and-consent#openid-connect-scopes) Logging in and Enrolling Account[#](https://ionic.io/docs/intune/usage#logging-in-and-enrolling-account "Direct link to heading") ---------------------------------------------------------------------------------------------------------------------------------- For apps that do not need a token from MSAL, `loginAndEnrollAccount` will authenticate and enroll the user in Intune for access to policies and configuration: await IntuneMAM.loginAndEnrollAccount(); Copy Get Enrolled Account[#](https://ionic.io/docs/intune/usage#get-enrolled-account "Direct link to heading") ---------------------------------------------------------------------------------------------------------- Once a user is logged in and enrolled, the accountId can be accessed with: const user = await IntuneMAM.enrolledAccount(); // User's ObjectID can be accessed using the accountId field:// user.accountId Copy Sign out and Deregister Account[#](https://ionic.io/docs/intune/usage#sign-out-and-deregister-account "Direct link to heading") -------------------------------------------------------------------------------------------------------------------------------- To sign a user out and un-enroll them: await IntuneMAM.deRegisterAndUnenrollAccount(user); Copy Note: On successful un-enrollment the application will close on iOS. Sign out using MSAL[#](https://ionic.io/docs/intune/usage#sign-out-using-msal "Direct link to heading") -------------------------------------------------------------------------------------------------------- To sign a user out using MSAL: await IntuneMAM.logoutOfAccount(user); Copy Note: Unlike `deRegisterAndUnenrollAccount` this method does not wipe app data nor close the application on iOS. Load App Config[#](https://ionic.io/docs/intune/usage#load-app-config "Direct link to heading") ------------------------------------------------------------------------------------------------ Access the remote app configuration: await IntuneMAM.appConfig(user); Copy Get App Policy[#](https://ionic.io/docs/intune/usage#get-app-policy "Direct link to heading") ---------------------------------------------------------------------------------------------- Get the remote app policy: await IntuneMAM.getPolicy(user); Copy Listen for Policy and Config changes[#](https://ionic.io/docs/intune/usage#listen-for-policy-and-config-changes "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------------------------ **Note: not yet supported for Cordova.** To listen for remote app configuration or policy changes, the following events can be subscribed to: IntuneMAM.addListener('appConfigChange', () => { console.log('App config change here');});IntuneMAM.addListener('policyChange', () => { console.log('Policy change here');}); Copy Get User Group Name[#](https://ionic.io/docs/intune/usage#get-user-group-name "Direct link to heading") -------------------------------------------------------------------------------------------------------- Get the group name of the user (if any) await IntuneMAM.groupName(user); Copy Diagnostics and Debugging[#](https://ionic.io/docs/intune/usage#diagnostics-and-debugging "Direct link to heading") -------------------------------------------------------------------------------------------------------------------- Intune is a complex environment, and making it easy for users to provide diagnostics and debugging information can be very helpful. To fetch the version of the Intune SDK in use: await IntuneMAM.sdkVersion(); Copy To display a diagnostic console to access logs to share with your network administrator: await IntuneMAM.displayDiagnosticConsole(); Copy * [Capacitor: Importing](https://ionic.io/docs/intune/usage#capacitor-importing) * [Cordova: Importing, TypeScript, and Usage](https://ionic.io/docs/intune/usage#cordova-importing-typescript-and-usage) * [MSAL Acquire Token and Intune Register Flow](https://ionic.io/docs/intune/usage#msal-acquire-token-and-intune-register-flow) * [Logging in and Enrolling Account](https://ionic.io/docs/intune/usage#logging-in-and-enrolling-account) * [Get Enrolled Account](https://ionic.io/docs/intune/usage#get-enrolled-account) * [Sign out and Deregister Account](https://ionic.io/docs/intune/usage#sign-out-and-deregister-account) * [Sign out using MSAL](https://ionic.io/docs/intune/usage#sign-out-using-msal) * [Load App Config](https://ionic.io/docs/intune/usage#load-app-config) * [Get App Policy](https://ionic.io/docs/intune/usage#get-app-policy) * [Listen for Policy and Config changes](https://ionic.io/docs/intune/usage#listen-for-policy-and-config-changes) * [Get User Group Name](https://ionic.io/docs/intune/usage#get-user-group-name) * [Diagnostics and Debugging](https://ionic.io/docs/intune/usage#diagnostics-and-debugging) --- # Capacitor and Cordova Android Permissions Plugin | Ionic [Skip to main content](https://ionic.io/docs/supported-plugins/android-permissions#) ##### EOL Notice Android Permissions will reach its end-of-life on July 1, 2024, and will no longer receive updates or support. Please see [Support Policy](https://ionic.io/docs/supported-plugins/support-policy) for additional information. The Android Permissions plugin is designed to support Android's new permissions checking mechanism, introduced in Android 8.0 (API level 26). Permissions are requested at time of use rather than at runtime. You can find all permissions [here](https://developer.android.com/reference/android/Manifest.permission.html) . Installation[​](https://ionic.io/docs/supported-plugins/android-permissions#installation "Direct link to heading") ------------------------------------------------------------------------------------------------------------------- If you have not already setup Ionic Enterprise in your app, [follow the one-time setup steps](https://ionic.io/docs/supported-plugins/setup) . Next, install the plugin: * Capacitor * Cordova npm install @ionic-enterprise/android-permissionsnpx cap sync Copy ionic cordova plugin add @ionic-enterprise/android-permissions Copy Index[​](https://ionic.io/docs/supported-plugins/android-permissions#index "Direct link to heading") ----------------------------------------------------------------------------------------------------- ### Classes[​](https://ionic.io/docs/supported-plugins/android-permissions#classes "Direct link to heading") * [AndroidPermissions](https://ionic.io/docs/supported-plugins/android-permissions#androidpermissions) * * * Classes[​](https://ionic.io/docs/supported-plugins/android-permissions#classes-1 "Direct link to heading") ----------------------------------------------------------------------------------------------------------- ### AndroidPermissions[​](https://ionic.io/docs/supported-plugins/android-permissions#androidpermissions "Direct link to heading") _**usage**_: import { AndroidPermissions } from '@ionic-enterprise/android-permissions/ngx';constructor(private androidPermissions: AndroidPermissions) { }...this.androidPermissions.checkPermission(this.androidPermissions.PERMISSION.CAMERA).then( result => console.log('Has permission?',result.hasPermission), err => this.androidPermissions.requestPermission(this.androidPermissions.PERMISSION.CAMERA));this.androidPermissions.requestPermissions([this.androidPermissions.PERMISSION.CAMERA, this.androidPermissions.PERMISSION.GET_ACCOUNTS]); Copy ### PERMISSION[​](https://ionic.io/docs/supported-plugins/android-permissions#permission "Direct link to heading") **● PERMISSION**: _`any`_ * * * ### checkPermission[​](https://ionic.io/docs/supported-plugins/android-permissions#checkpermission "Direct link to heading") ▸ **checkPermission**(permission: _`string`_): `Promise`<`any`\> Check permission **Parameters:** | Name | Type | Description | | --- | --- | --- | | permission | `string` | The name of the permission | **Returns:** `Promise`<`any`\> Returns a promise * * * ### hasPermission[​](https://ionic.io/docs/supported-plugins/android-permissions#haspermission "Direct link to heading") ▸ **hasPermission**(permission: _`string`_): `Promise`<`any`\> This function still works now, will not support in the future. **Parameters:** | Name | Type | Description | | --- | --- | --- | | permission | `string` | The name of the permission | **Returns:** `Promise`<`any`\> Returns a promise * * * ### requestPermission[​](https://ionic.io/docs/supported-plugins/android-permissions#requestpermission "Direct link to heading") ▸ **requestPermission**(permission: _`string`_): `Promise`<`any`\> Request permission **Parameters:** | Name | Type | Description | | --- | --- | --- | | permission | `string` | The name of the permission to request | **Returns:** `Promise`<`any`\> * * * ### requestPermissions[​](https://ionic.io/docs/supported-plugins/android-permissions#requestpermissions "Direct link to heading") ▸ **requestPermissions**(permissions: _`string`\[\]_): `Promise`<`any`\> Request permissions **Parameters:** | Name | Type | Description | | --- | --- | --- | | permissions | `string`\[\] | An array with permissions | **Returns:** `Promise`<`any`\> Returns a promise * * * * * * * [Index](https://ionic.io/docs/supported-plugins/android-permissions#index) * [Classes](https://ionic.io/docs/supported-plugins/android-permissions#classes) * [Classes](https://ionic.io/docs/supported-plugins/android-permissions#classes-1) * [AndroidPermissions](https://ionic.io/docs/supported-plugins/android-permissions#androidpermissions) * [PERMISSION](https://ionic.io/docs/supported-plugins/android-permissions#permission) * [checkPermission](https://ionic.io/docs/supported-plugins/android-permissions#checkpermission) * [hasPermission](https://ionic.io/docs/supported-plugins/android-permissions#haspermission) * [requestPermission](https://ionic.io/docs/supported-plugins/android-permissions#requestpermission) * [requestPermissions](https://ionic.io/docs/supported-plugins/android-permissions#requestpermissions) --- # App Version - Supported Plugins [Skip to main content](https://ionic.io/docs/supported-plugins/app-version#) ##### EOL Notice App Version will reach its end-of-life on July 1, 2024, and will no longer receive updates or support. Please see [Support Policy](https://ionic.io/docs/supported-plugins/support-policy) for additional information. The App Version plugin provides access to your app's metadata, including app name, package name, and version number. Installation[​](https://ionic.io/docs/supported-plugins/app-version#installation "Direct link to heading") ----------------------------------------------------------------------------------------------------------- If you have not already setup Ionic Enterprise in your app, [follow the one-time setup steps](https://ionic.io/docs/supported-plugins/setup) . Next, install the plugin: * Capacitor * Cordova npm install @ionic-enterprise/app-versionnpx cap sync Copy ionic cordova plugin add @ionic-enterprise/app-version Copy Index[​](https://ionic.io/docs/supported-plugins/app-version#index "Direct link to heading") --------------------------------------------------------------------------------------------- ### Classes[​](https://ionic.io/docs/supported-plugins/app-version#classes "Direct link to heading") * [AppVersion](https://ionic.io/docs/supported-plugins/app-version#appversion) * * * Classes[​](https://ionic.io/docs/supported-plugins/app-version#classes-1 "Direct link to heading") --------------------------------------------------------------------------------------------------- ### AppVersion[​](https://ionic.io/docs/supported-plugins/app-version#appversion "Direct link to heading") _**usage**_: import { AppVersion } from '@ionic-enterprise/app-version/ngx';constructor(private appVersion: AppVersion) { }...this.appVersion.getAppName();this.appVersion.getPackageName();this.appVersion.getVersionCode();this.appVersion.getVersionNumber(); Copy ### getAppName[​](https://ionic.io/docs/supported-plugins/app-version#getappname "Direct link to heading") ▸ **getAppName**(): `Promise`<`string`\> Returns the name of the app, e.g.: "My Awesome App" **Returns:** `Promise`<`string`\> * * * ### getPackageName[​](https://ionic.io/docs/supported-plugins/app-version#getpackagename "Direct link to heading") ▸ **getPackageName**(): `Promise`<`string`\> Returns the package name of the app, e.g.: "com.example.myawesomeapp" **Returns:** `Promise`<`string`\> * * * ### getVersionCode[​](https://ionic.io/docs/supported-plugins/app-version#getversioncode "Direct link to heading") ▸ **getVersionCode**(): `Promise`<`string` | `number`\> Returns the build identifier of the app. In iOS a string with the build version like "1.6095" In Android a number generated from the version string, like 10203 for version "1.2.3" **Returns:** `Promise`<`string` | `number`\> * * * ### getVersionNumber[​](https://ionic.io/docs/supported-plugins/app-version#getversionnumber "Direct link to heading") ▸ **getVersionNumber**(): `Promise`<`string`\> Returns the version of the app, e.g.: "1.2.3" **Returns:** `Promise`<`string`\> * * * * * * * [Index](https://ionic.io/docs/supported-plugins/app-version#index) * [Classes](https://ionic.io/docs/supported-plugins/app-version#classes) * [Classes](https://ionic.io/docs/supported-plugins/app-version#classes-1) * [AppVersion](https://ionic.io/docs/supported-plugins/app-version#appversion) * [getAppName](https://ionic.io/docs/supported-plugins/app-version#getappname) * [getPackageName](https://ionic.io/docs/supported-plugins/app-version#getpackagename) * [getVersionCode](https://ionic.io/docs/supported-plugins/app-version#getversioncode) * [getVersionNumber](https://ionic.io/docs/supported-plugins/app-version#getversionnumber) --- # Badge - Supported Plugins [Skip to main content](https://ionic.io/docs/supported-plugins/badge#) ##### EOL Notice Badge will reach its end-of-life on July 1, 2024, and will no longer receive updates or support. Please see [Support Policy](https://ionic.io/docs/supported-plugins/support-policy) for additional information. The Badge plugin enables an application to inform its users that it has something for them — for example, unread messages — when the application isn’t running in the foreground. Android Note: Badges have historically only been a feature implemented by third party launchers and not visible unless one of those launchers was being used (E.G. Samsung or Nova Launcher) and if enabled by the user. As of Android 8 (Oreo), [notification badges](https://developer.android.com/training/notify-user/badges) were introduced officially to reflect unread notifications. This plugin is unlikely to work as expected on devices running Android 8 or newer. Please see the [local notifications plugin docs](https://github.com/katzer/cordova-plugin-local-notifications) for more information on badge use with notifications. Installation[​](https://ionic.io/docs/supported-plugins/badge#installation "Direct link to heading") ----------------------------------------------------------------------------------------------------- If you have not already setup Ionic Enterprise in your app, [follow the one-time setup steps](https://ionic.io/docs/supported-plugins/setup) . Next, install the plugin: * Capacitor * Cordova npm install @ionic-enterprise/badgenpx cap sync Copy ionic cordova plugin add @ionic-enterprise/badge Copy Index[​](https://ionic.io/docs/supported-plugins/badge#index "Direct link to heading") --------------------------------------------------------------------------------------- ### Classes[​](https://ionic.io/docs/supported-plugins/badge#classes "Direct link to heading") * [Badge](https://ionic.io/docs/supported-plugins/badge#badge) * * * Classes[​](https://ionic.io/docs/supported-plugins/badge#classes-1 "Direct link to heading") --------------------------------------------------------------------------------------------- ### Badge[​](https://ionic.io/docs/supported-plugins/badge#badge "Direct link to heading") **Badge**: _**usage**_: import { Badge } from '@ionic-enterprise/badge/ngx';constructor(private badge: Badge) { }...this.badge.set(10);this.badge.increase(1);this.badge.clear(); Copy ### clear[​](https://ionic.io/docs/supported-plugins/badge#clear "Direct link to heading") ▸ **clear**(): `Promise`<`boolean`\> Clear the badge of the app icon. **Returns:** `Promise`<`boolean`\> * * * ### decrease[​](https://ionic.io/docs/supported-plugins/badge#decrease "Direct link to heading") ▸ **decrease**(decreaseBy: _`number`_): `Promise`<`any`\> Decrease the badge number. **Parameters:** | Name | Type | Description | | --- | --- | --- | | decreaseBy | `number` | Count to subtract from the current badge number | **Returns:** `Promise`<`any`\> * * * ### get[​](https://ionic.io/docs/supported-plugins/badge#get "Direct link to heading") ▸ **get**(): `Promise`<`any`\> Get the badge of the app icon. **Returns:** `Promise`<`any`\> * * * ### hasPermission[​](https://ionic.io/docs/supported-plugins/badge#haspermission "Direct link to heading") ▸ **hasPermission**(): `Promise`<`any`\> Determine if the app has permission to show badges. **Returns:** `Promise`<`any`\> * * * ### increase[​](https://ionic.io/docs/supported-plugins/badge#increase "Direct link to heading") ▸ **increase**(increaseBy: _`number`_): `Promise`<`any`\> Increase the badge number. **Parameters:** | Name | Type | Description | | --- | --- | --- | | increaseBy | `number` | Count to add to the current badge number | **Returns:** `Promise`<`any`\> * * * ### isSupported[​](https://ionic.io/docs/supported-plugins/badge#issupported "Direct link to heading") ▸ **isSupported**(): `Promise`<`any`\> Check support to show badges. **Returns:** `Promise`<`any`\> * * * ### requestPermission[​](https://ionic.io/docs/supported-plugins/badge#requestpermission "Direct link to heading") ▸ **requestPermission**(): `Promise`<`any`\> Register permission to set badge notifications **Returns:** `Promise`<`any`\> * * * ### set[​](https://ionic.io/docs/supported-plugins/badge#set "Direct link to heading") ▸ **set**(badgeNumber: _`number`_): `Promise`<`any`\> Set the badge of the app icon. **Parameters:** | Name | Type | Description | | --- | --- | --- | | badgeNumber | `number` | The new badge number. | **Returns:** `Promise`<`any`\> * * * * * * * [Index](https://ionic.io/docs/supported-plugins/badge#index) * [Classes](https://ionic.io/docs/supported-plugins/badge#classes) * [Classes](https://ionic.io/docs/supported-plugins/badge#classes-1) * [Badge](https://ionic.io/docs/supported-plugins/badge#badge) * [clear](https://ionic.io/docs/supported-plugins/badge#clear) * [decrease](https://ionic.io/docs/supported-plugins/badge#decrease) * [get](https://ionic.io/docs/supported-plugins/badge#get) * [hasPermission](https://ionic.io/docs/supported-plugins/badge#haspermission) * [increase](https://ionic.io/docs/supported-plugins/badge#increase) * [isSupported](https://ionic.io/docs/supported-plugins/badge#issupported) * [requestPermission](https://ionic.io/docs/supported-plugins/badge#requestpermission) * [set](https://ionic.io/docs/supported-plugins/badge#set) --- # Supported Plugins - Supported Plugins [Skip to main content](https://ionic.io/docs/supported-plugins#) Supported Plugins are a library of fully supported Capacitor and Cordova plugins and third-party integrations for teams building enterprise-grade apps with Ionic. What is a Supported Plugin?[​](https://ionic.io/docs/supported-plugins#what-is-a-supported-plugin "Direct link to heading") ---------------------------------------------------------------------------------------------------------------------------- For teams building mission-critical apps, our Supported Plugins are a curated collection of plugins that are actively supported and maintained by Ionic, with stability assurances and guaranteed to work on all major platforms and versions. Take on mobile projects with peace of mind, knowing the native features, security, and performance you need will just work - now and in the future. Our Supported Plugins are supported and maintained by the Ionic team, but are sourced from popular community plugins. You have dedicated support, SLAs, security patches, and more available with Supported Plugins. | Features | Community Plugins

$0/mo | Supported Plugins

Contact Us | | --- | --- | --- | | Maintainer | OSS Community | Ionic | | Regular Release Cycles & Updates | No | | | Support SLA & Ticketing System | No | | | Advisory & Support | No | | | Security & Bug fixes | OSS Community | | | Implementation Guidance | No | | | Guaranteed SLA | No | | | | | [Learn More](https://ionicframework.com/enterprise-edition) | Which Plugins Should I Choose?[​](https://ionic.io/docs/supported-plugins#which-plugins-should-i-choose "Direct link to heading") ---------------------------------------------------------------------------------------------------------------------------------- The same native functionality may be implemented by plugins existing in several different portions of the plugin ecosystem. This issue is compounded in Capacitor based projects since Capacitor is capable of supporting Capacitor and Cordova based plugins. As such, for Capacitor based applications we suggest choosing the plugin to use based on the following hierarchy: 1. Capacitor Official Plugins (`@capacitor` scoped plugins, supported by Ionic) 2. Cordova Supported Plugins (See the "Cordova Plugin APIs" section here, supported by Ionic) 3. Capacitor Community Plugins (`@capacitor-community` scoped plugins) 4. Cordova Community Plugins As an example, if you want to access the camera, favor the `@capacitor/camera` plugin over `@ionic-enterprise/camera`, which is a Cordova plugin. The `@ionic-enterprise/camera` plugin is favored over the community based Cordova camera plugin. If you are using Cordova to implement your native layer, you need to drop the Capacitor plugins and consider the plugins using just the following hierarchy: 1. Cordova Supported Plugins (See the "Cordova Plugin APIs" section here, supported by Ionic) 2. Cordova Community Plugins Plugin List[​](https://ionic.io/docs/supported-plugins#plugin-list "Direct link to heading") --------------------------------------------------------------------------------------------- Accelerate your app development with powerful solutions to common enterprise use cases. Ionic’s growing library are ready to deploy into any of the apps you build. ### Supported Plugins[​](https://ionic.io/docs/supported-plugins#supported-plugins "Direct link to heading") * [Android Permissions](https://ionic.io/docs/supported-plugins/android-permissions) * [App Rate](https://ionic.io/docs/supported-plugins/app-rate) * [App Version](https://ionic.io/docs/supported-plugins/app-version) * [Badge](https://ionic.io/docs/supported-plugins/badge) * [Browser](https://ionic.io/docs/supported-plugins/inappbrowser) * [Calendar](https://ionic.io/docs/supported-plugins/calendar) * [Camera](https://ionic.io/docs/supported-plugins/camera) * [Clipboard](https://ionic.io/docs/supported-plugins/clipboard) * [Contacts](https://ionic.io/docs/supported-plugins/contacts) * [Deeplinks](https://ionic.io/docs/supported-plugins/deeplinks) * [Device](https://ionic.io/docs/supported-plugins/device) * [Dialogs](https://ionic.io/docs/supported-plugins/dialogs) * [Email Composer](https://ionic.io/docs/supported-plugins/email-composer) * [Filesystem](https://ionic.io/docs/supported-plugins/filesystem) * [Geolocation](https://ionic.io/docs/supported-plugins/geolocation) * [Globalization](https://ionic.io/docs/supported-plugins/globalization) * [Haptics & Vibration](https://ionic.io/docs/supported-plugins/vibration) * [Keyboard](https://ionic.io/docs/supported-plugins/keyboard) * [Media](https://ionic.io/docs/supported-plugins/media) * [Media Capture](https://ionic.io/docs/supported-plugins/media-capture) * [Native Storage](https://ionic.io/docs/supported-plugins/nativestorage) * [Network Information](https://ionic.io/docs/supported-plugins/network-information) * [Screen Orientation](https://ionic.io/docs/supported-plugins/screen-orientation) * [Social Sharing](https://ionic.io/docs/supported-plugins/social-sharing) * [Splash Screen](https://ionic.io/docs/supported-plugins/splashscreen) * [Status Bar](https://ionic.io/docs/supported-plugins/statusbar) ### Integrated Services[​](https://ionic.io/docs/supported-plugins#integrated-services "Direct link to heading") * [Active Directory](https://ionicframework.com/integrations/ms-activedirectory-ms-adal) * [mParticle](https://ionic.io/docs/supported-plugins/mparticle) Looking for our Native Solutions?[​](https://ionic.io/docs/supported-plugins#looking-for-our-native-solutions "Direct link to heading") ---------------------------------------------------------------------------------------------------------------------------------------- Our Native Solutions go above and beyond our Supported Plugins with advanced Security & Authentication functionality you can trust. [Connect to your authentication providers from any mobile device.](https://ionic.io/docs/auth-connect) [Lock down sensitive data with advanced biometrics.](https://ionic.io/docs/identity-vault) [A flexible mobile storage solution for offline-first experiences.](https://ionic.io/docs/secure-storage) [Collect payment from customers securely and efficiently using Google Pay and Apple Pay.](https://ionic.io/docs/apple-pay) --- # Clipboard - Supported Plugins [Skip to main content](https://ionic.io/docs/supported-plugins/clipboard#) ##### EOL Notice Clipboard will reach its end-of-life on July 1, 2024, and will no longer receive updates or support. Please see [Support Policy](https://ionic.io/docs/supported-plugins/support-policy) for additional information. The Clipboard plugin provides access to the device clipboard, including copy and paste functionality. Installation[​](https://ionic.io/docs/supported-plugins/clipboard#installation "Direct link to heading") --------------------------------------------------------------------------------------------------------- If you have not already setup Ionic Enterprise in your app, [follow the one-time setup steps](https://ionic.io/docs/supported-plugins/setup) . Next, install the plugin: * Capacitor * Cordova npm install @ionic-enterprise/clipboardnpx cap sync Copy ionic cordova plugin add @ionic-enterprise/clipboard Copy Index[​](https://ionic.io/docs/supported-plugins/clipboard#index "Direct link to heading") ------------------------------------------------------------------------------------------- ### Classes[​](https://ionic.io/docs/supported-plugins/clipboard#classes "Direct link to heading") * [Clipboard](https://ionic.io/docs/supported-plugins/clipboard#clipboard) * * * Classes[​](https://ionic.io/docs/supported-plugins/clipboard#classes-1 "Direct link to heading") ------------------------------------------------------------------------------------------------- ### Clipboard[​](https://ionic.io/docs/supported-plugins/clipboard#clipboard "Direct link to heading") _**usage**_: import { Clipboard } from '@ionic-enterprise/clipboard/ngx';constructor(private clipboard: Clipboard) { }...this.clipboard.copy('Hello world');this.clipboard.paste().then( (resolve: string) => { alert(resolve); }, (reject: string) => { alert('Error: ' + reject); } );this.clipboard.clear(); Copy ### clear[​](https://ionic.io/docs/supported-plugins/clipboard#clear "Direct link to heading") ▸ **clear**(): `Promise`<`any`\> Clear the text stored in clipboard **Returns:** `Promise`<`any`\> Returns a promise after the text has been cleaned * * * ### copy[​](https://ionic.io/docs/supported-plugins/clipboard#copy "Direct link to heading") ▸ **copy**(text: _`string`_): `Promise`<`any`\> Copies the given text **Parameters:** | Name | Type | Description | | --- | --- | --- | | text | `string` | Text that gets copied on the system clipboard | **Returns:** `Promise`<`any`\> Returns a promise after the text has been copied * * * ### paste[​](https://ionic.io/docs/supported-plugins/clipboard#paste "Direct link to heading") ▸ **paste**(): `Promise`<`any`\> Pastes the text stored in clipboard **Returns:** `Promise`<`any`\> Returns a promise after the text has been pasted * * * * * * * [Index](https://ionic.io/docs/supported-plugins/clipboard#index) * [Classes](https://ionic.io/docs/supported-plugins/clipboard#classes) * [Classes](https://ionic.io/docs/supported-plugins/clipboard#classes-1) * [Clipboard](https://ionic.io/docs/supported-plugins/clipboard#clipboard) * [clear](https://ionic.io/docs/supported-plugins/clipboard#clear) * [copy](https://ionic.io/docs/supported-plugins/clipboard#copy) * [paste](https://ionic.io/docs/supported-plugins/clipboard#paste) --- # Device - Supported Plugins [Skip to main content](https://ionic.io/docs/supported-plugins/device#) ##### EOL Notice Device will reach its end-of-life on July 1, 2024, and will no longer receive updates or support. Please see [Support Policy](https://ionic.io/docs/supported-plugins/support-policy) for additional information. The Device plugin provides access to information about the underlying device and platform that the app is running on. Installation[​](https://ionic.io/docs/supported-plugins/device#installation "Direct link to heading") ------------------------------------------------------------------------------------------------------ If you have not already setup Ionic Enterprise in your app, [follow the one-time setup steps](https://ionic.io/docs/supported-plugins/setup) . Next, install the plugin: * Capacitor * Cordova npm install @ionic-enterprise/devicenpx cap sync Copy ionic cordova plugin add @ionic-enterprise/device Copy Index[​](https://ionic.io/docs/supported-plugins/device#index "Direct link to heading") ---------------------------------------------------------------------------------------- ### Classes[​](https://ionic.io/docs/supported-plugins/device#classes "Direct link to heading") * [Device](https://ionic.io/docs/supported-plugins/device#device) * * * Classes[​](https://ionic.io/docs/supported-plugins/device#classes-1 "Direct link to heading") ---------------------------------------------------------------------------------------------- ### Device[​](https://ionic.io/docs/supported-plugins/device#device "Direct link to heading") _**usage**_: import { Device } from '@ionic-enterprise/device/ngx';constructor(private device: Device) { }...console.log('Device UUID is: ' + this.device.uuid); Copy ### cordova[​](https://ionic.io/docs/supported-plugins/device#cordova "Direct link to heading") **● cordova**: _`string`_ Get the version of Cordova running on the device. * * * ### isVirtual[​](https://ionic.io/docs/supported-plugins/device#isvirtual "Direct link to heading") **● isVirtual**: _`boolean`_ Whether the device is running on a simulator. * * * ### manufacturer[​](https://ionic.io/docs/supported-plugins/device#manufacturer "Direct link to heading") **● manufacturer**: _`string`_ Get the device's manufacturer. * * * ### model[​](https://ionic.io/docs/supported-plugins/device#model "Direct link to heading") **● model**: _`string`_ The device.model returns the name of the device's model or product. The value is set by the device manufacturer and may be different across versions of the same product. * * * ### platform[​](https://ionic.io/docs/supported-plugins/device#platform "Direct link to heading") **● platform**: _`string`_ Get the device's operating system name. * * * ### serial[​](https://ionic.io/docs/supported-plugins/device#serial "Direct link to heading") **● serial**: _`string`_ Get the device hardware serial number. * * * ### uuid[​](https://ionic.io/docs/supported-plugins/device#uuid "Direct link to heading") **● uuid**: _`string`_ Get the device's Universally Unique Identifier (UUID). * * * ### version[​](https://ionic.io/docs/supported-plugins/device#version "Direct link to heading") **● version**: _`string`_ Get the operating system version. * * * * * * * [Index](https://ionic.io/docs/supported-plugins/device#index) * [Classes](https://ionic.io/docs/supported-plugins/device#classes) * [Classes](https://ionic.io/docs/supported-plugins/device#classes-1) * [Device](https://ionic.io/docs/supported-plugins/device#device) * [cordova](https://ionic.io/docs/supported-plugins/device#cordova) * [isVirtual](https://ionic.io/docs/supported-plugins/device#isvirtual) * [manufacturer](https://ionic.io/docs/supported-plugins/device#manufacturer) * [model](https://ionic.io/docs/supported-plugins/device#model) * [platform](https://ionic.io/docs/supported-plugins/device#platform) * [serial](https://ionic.io/docs/supported-plugins/device#serial) * [uuid](https://ionic.io/docs/supported-plugins/device#uuid) * [version](https://ionic.io/docs/supported-plugins/device#version) --- # Dialogs - Supported Plugins [Skip to main content](https://ionic.io/docs/supported-plugins/dialogs#) ##### EOL Notice Dialogs will reach its end-of-life on July 1, 2024, and will no longer receive updates or support. Please see [Support Policy](https://ionic.io/docs/supported-plugins/support-policy) for additional information. The Dialogs plugin provides access to customize the native device dialogs. Installation[​](https://ionic.io/docs/supported-plugins/dialogs#installation "Direct link to heading") ------------------------------------------------------------------------------------------------------- If you have not already setup Ionic Enterprise in your app, [follow the one-time setup steps](https://ionic.io/docs/supported-plugins/setup) . Next, install the plugin: * Capacitor * Cordova npm install @ionic-enterprise/dialogsnpx cap sync Copy ionic cordova plugin add @ionic-enterprise/dialogs Copy Index[​](https://ionic.io/docs/supported-plugins/dialogs#index "Direct link to heading") ----------------------------------------------------------------------------------------- ### Classes[​](https://ionic.io/docs/supported-plugins/dialogs#classes "Direct link to heading") * [Dialogs](https://ionic.io/docs/supported-plugins/dialogs#dialogs) ### Interfaces[​](https://ionic.io/docs/supported-plugins/dialogs#interfaces "Direct link to heading") * [DialogsPromptCallback](https://ionic.io/docs/supported-plugins/dialogs#dialogspromptcallback) * * * Classes[​](https://ionic.io/docs/supported-plugins/dialogs#classes-1 "Direct link to heading") ----------------------------------------------------------------------------------------------- ### Dialogs[​](https://ionic.io/docs/supported-plugins/dialogs#dialogs "Direct link to heading") _**usage**_: import { Dialogs } from '@ionic-enterprise/dialogs/ngx';constructor(private dialogs: Dialogs) { }...this.dialogs.alert('Hello world') .then(() => console.log('Dialog dismissed')) .catch(e => console.log('Error displaying dialog', e)); Copy _**interfaces**_: DialogsPromptCallback ### alert[​](https://ionic.io/docs/supported-plugins/dialogs#alert "Direct link to heading") ▸ **alert**(message: _`string`_, title?: _`string`_, buttonName?: _`string`_): `Promise`<`any`\> Shows a custom alert or dialog box. **Parameters:** | Name | Type | Description | | --- | --- | --- | | message | `string` | Dialog message. | | `Optional` title | `string` | | | `Optional` buttonName | `string` | | **Returns:** `Promise`<`any`\> Returns a blank promise once the user has dismissed the alert. * * * ### beep[​](https://ionic.io/docs/supported-plugins/dialogs#beep "Direct link to heading") ▸ **beep**(times: _`number`_): `void` The device plays a beep sound. **Parameters:** | Name | Type | Description | | --- | --- | --- | | times | `number` | The number of times to repeat the beep. | **Returns:** `void` * * * ### confirm[​](https://ionic.io/docs/supported-plugins/dialogs#confirm "Direct link to heading") ▸ **confirm**(message: _`string`_, title?: _`string`_, buttonLabels?: _`string`\[\]_): `Promise`<`number`\> Displays a customizable confirmation dialog box. **Parameters:** | Name | Type | Description | | --- | --- | --- | | message | `string` | Dialog message. | | `Optional` title | `string` | | | `Optional` buttonLabels | `string`\[\] | | **Returns:** `Promise`<`number`\> Returns a promise that resolves the button index that was clicked, or 0 if the user has dismissed the dialog by clicking outside the dialog box. Note that the index use one-based indexing. * * * ### prompt[​](https://ionic.io/docs/supported-plugins/dialogs#prompt "Direct link to heading") ▸ **prompt**(message?: _`string`_, title?: _`string`_, buttonLabels?: _`string`\[\]_, defaultText?: _`string`_): `Promise`<[DialogsPromptCallback](https://ionic.io/docs/supported-plugins/dialogs#dialogspromptcallback) \> Displays a native dialog box that is more customizable than the browser's prompt function. **Parameters:** | Name | Type | | --- | --- | | `Optional` message | `string` | | `Optional` title | `string` | | `Optional` buttonLabels | `string`\[\] | | `Optional` defaultText | `string` | **Returns:** `Promise`<[DialogsPromptCallback](https://ionic.io/docs/supported-plugins/dialogs#dialogspromptcallback) \> Returns a promise that resolves an object with the button index clicked and the text entered * * * * * * Interfaces[​](https://ionic.io/docs/supported-plugins/dialogs#interfaces-1 "Direct link to heading") ----------------------------------------------------------------------------------------------------- ### DialogsPromptCallback[​](https://ionic.io/docs/supported-plugins/dialogs#dialogspromptcallback "Direct link to heading") **DialogsPromptCallback**: ### buttonIndex[​](https://ionic.io/docs/supported-plugins/dialogs#buttonindex "Direct link to heading") **● buttonIndex**: _`number`_ The index of the pressed button. (Number) Note that the index uses one-based indexing, so the value is 1, 2, 3, etc. * * * ### input1[​](https://ionic.io/docs/supported-plugins/dialogs#input1 "Direct link to heading") **● input1**: _`string`_ The text entered in the prompt dialog box. (String) * * * * * * * [Index](https://ionic.io/docs/supported-plugins/dialogs#index) * [Classes](https://ionic.io/docs/supported-plugins/dialogs#classes) * [Interfaces](https://ionic.io/docs/supported-plugins/dialogs#interfaces) * [Classes](https://ionic.io/docs/supported-plugins/dialogs#classes-1) * [Dialogs](https://ionic.io/docs/supported-plugins/dialogs#dialogs) * [alert](https://ionic.io/docs/supported-plugins/dialogs#alert) * [beep](https://ionic.io/docs/supported-plugins/dialogs#beep) * [confirm](https://ionic.io/docs/supported-plugins/dialogs#confirm) * [prompt](https://ionic.io/docs/supported-plugins/dialogs#prompt) * [Interfaces](https://ionic.io/docs/supported-plugins/dialogs#interfaces-1) * [DialogsPromptCallback](https://ionic.io/docs/supported-plugins/dialogs#dialogspromptcallback) * [buttonIndex](https://ionic.io/docs/supported-plugins/dialogs#buttonindex) * [input1](https://ionic.io/docs/supported-plugins/dialogs#input1) --- # Cordova and Capacitor Calendar Plugin | Ionic [Skip to main content](https://ionic.io/docs/supported-plugins/calendar#) ##### EOL Notice Calendar will reach its end-of-life on July 1, 2024, and will no longer receive updates or support. Please see [Support Policy](https://ionic.io/docs/supported-plugins/support-policy) for additional information. The Calendar plugin allows you to add events to the system calendar of the mobile device. Installation[​](https://ionic.io/docs/supported-plugins/calendar#installation "Direct link to heading") -------------------------------------------------------------------------------------------------------- If you have not already setup Ionic Enterprise in your app, [follow the one-time setup steps](https://ionic.io/docs/supported-plugins/setup) . Next, install the plugin: * Capacitor * Cordova npm install @ionic-enterprise/calendarnpx cap sync Copy ionic cordova plugin add @ionic-enterprise/calendar Copy Index[​](https://ionic.io/docs/supported-plugins/calendar#index "Direct link to heading") ------------------------------------------------------------------------------------------ ### Classes[​](https://ionic.io/docs/supported-plugins/calendar#classes "Direct link to heading") * [Calendar](https://ionic.io/docs/supported-plugins/calendar#calendar) ### Interfaces[​](https://ionic.io/docs/supported-plugins/calendar#interfaces "Direct link to heading") * [CalendarOptions](https://ionic.io/docs/supported-plugins/calendar#calendaroptions) * [NameOrOptions](https://ionic.io/docs/supported-plugins/calendar#nameoroptions) * * * Classes[​](https://ionic.io/docs/supported-plugins/calendar#classes-1 "Direct link to heading") ------------------------------------------------------------------------------------------------ ### Calendar[​](https://ionic.io/docs/supported-plugins/calendar#calendar "Direct link to heading") **Calendar**: _**name**_: Calendar _**description**_: This plugin allows you to add events to the Calendar of the mobile device. _**usage**_: import { Calendar } from '@ionic-enterprise/calendar/ngx';constructor(private calendar: Calendar) { }this.calendar.createCalendar('MyCalendar').then( (msg) => { console.log(msg); }, (err) => { console.log(err); }); Copy _**interfaces**_: CalendarOptions NameOrOptions ### createCalendar[​](https://ionic.io/docs/supported-plugins/calendar#createcalendar "Direct link to heading") ▸ **createCalendar**(nameOrOptions: _`string` | [NameOrOptions](https://ionic.io/docs/supported-plugins/calendar#nameoroptions) _): `Promise`<`any`\> Create a calendar. (iOS only) **Parameters:** | Name | Type | Description | | --- | --- | --- | | nameOrOptions | `string` \| [NameOrOptions](https://ionic.io/docs/supported-plugins/calendar#nameoroptions) | either a string name or a options object. If string, provide the calendar name. IF an object, provide a calendar name as a string and a calendar color in hex format as a string | **Returns:** `Promise`<`any`\> Returns a Promise * * * ### createEvent[​](https://ionic.io/docs/supported-plugins/calendar#createevent "Direct link to heading") ▸ **createEvent**(title?: _`string`_, location?: _`string`_, notes?: _`string`_, startDate?: _`Date`_, endDate?: _`Date`_): `Promise`<`any`\> Silently create an event. **Parameters:** | Name | Type | | --- | --- | | `Optional` title | `string` | | `Optional` location | `string` | | `Optional` notes | `string` | | `Optional` startDate | `Date` | | `Optional` endDate | `Date` | **Returns:** `Promise`<`any`\> Returns a Promise * * * ### createEventInteractively[​](https://ionic.io/docs/supported-plugins/calendar#createeventinteractively "Direct link to heading") ▸ **createEventInteractively**(title?: _`string`_, location?: _`string`_, notes?: _`string`_, startDate?: _`Date`_, endDate?: _`Date`_): `Promise`<`any`\> Interactively create an event. **Parameters:** | Name | Type | | --- | --- | | `Optional` title | `string` | | `Optional` location | `string` | | `Optional` notes | `string` | | `Optional` startDate | `Date` | | `Optional` endDate | `Date` | **Returns:** `Promise`<`any`\> Returns a Promise * * * ### createEventInteractivelyWithOptions[​](https://ionic.io/docs/supported-plugins/calendar#createeventinteractivelywithoptions "Direct link to heading") ▸ **createEventInteractivelyWithOptions**(title?: _`string`_, location?: _`string`_, notes?: _`string`_, startDate?: _`Date`_, endDate?: _`Date`_, options?: _[CalendarOptions](https://ionic.io/docs/supported-plugins/calendar#calendaroptions) _): `Promise`<`any`\> Interactively create an event with additional options. **Parameters:** | Name | Type | | --- | --- | | `Optional` title | `string` | | `Optional` location | `string` | | `Optional` notes | `string` | | `Optional` startDate | `Date` | | `Optional` endDate | `Date` | | `Optional` options | [CalendarOptions](https://ionic.io/docs/supported-plugins/calendar#calendaroptions) | **Returns:** `Promise`<`any`\> * * * ### createEventWithOptions[​](https://ionic.io/docs/supported-plugins/calendar#createeventwithoptions "Direct link to heading") ▸ **createEventWithOptions**(title?: _`string`_, location?: _`string`_, notes?: _`string`_, startDate?: _`Date`_, endDate?: _`Date`_, options?: _[CalendarOptions](https://ionic.io/docs/supported-plugins/calendar#calendaroptions) _): `Promise`<`any`\> Silently create an event with additional options. **Parameters:** | Name | Type | | --- | --- | | `Optional` title | `string` | | `Optional` location | `string` | | `Optional` notes | `string` | | `Optional` startDate | `Date` | | `Optional` endDate | `Date` | | `Optional` options | [CalendarOptions](https://ionic.io/docs/supported-plugins/calendar#calendaroptions) | **Returns:** `Promise`<`any`\> Returns a Promise * * * ### deleteCalendar[​](https://ionic.io/docs/supported-plugins/calendar#deletecalendar "Direct link to heading") ▸ **deleteCalendar**(name: _`string`_): `Promise`<`any`\> Delete a calendar. (iOS only) **Parameters:** | Name | Type | Description | | --- | --- | --- | | name | `string` | Name of the calendar to delete. | **Returns:** `Promise`<`any`\> Returns a Promise * * * ### deleteEvent[​](https://ionic.io/docs/supported-plugins/calendar#deleteevent "Direct link to heading") ▸ **deleteEvent**(title?: _`string`_, location?: _`string`_, notes?: _`string`_, startDate?: _`Date`_, endDate?: _`Date`_): `Promise`<`any`\> Delete an event. **Parameters:** | Name | Type | | --- | --- | | `Optional` title | `string` | | `Optional` location | `string` | | `Optional` notes | `string` | | `Optional` startDate | `Date` | | `Optional` endDate | `Date` | **Returns:** `Promise`<`any`\> Returns a Promise * * * ### deleteEventById[​](https://ionic.io/docs/supported-plugins/calendar#deleteeventbyid "Direct link to heading") ▸ **deleteEventById**(id: _`string`_, fromDate?: _`Date`_): `Promise`<`any`\> Delete an event by id. **Parameters:** | Name | Type | | --- | --- | | id | `string` | | `Optional` fromDate | `Date` | **Returns:** `Promise`<`any`\> Returns a Promise * * * ### deleteEventFromNamedCalendar[​](https://ionic.io/docs/supported-plugins/calendar#deleteeventfromnamedcalendar "Direct link to heading") ▸ **deleteEventFromNamedCalendar**(title?: _`string`_, location?: _`string`_, notes?: _`string`_, startDate?: _`Date`_, endDate?: _`Date`_, calendarName?: _`string`_): `Promise`<`any`\> Delete an event from the specified Calendar. (iOS only) **Parameters:** | Name | Type | Description | | --- | --- | --- | | `Optional` title | `string` | | | `Optional` location | `string` | | | `Optional` notes | `string` | | | `Optional` startDate | `Date` | | | `Optional` endDate | `Date` | | | `Optional` calendarName | `string` | \- | **Returns:** `Promise`<`any`\> Returns a Promise * * * ### findAllEventsInNamedCalendar[​](https://ionic.io/docs/supported-plugins/calendar#findalleventsinnamedcalendar "Direct link to heading") ▸ **findAllEventsInNamedCalendar**(calendarName: _`string`_): `Promise`<`any`\> Get a list of all future events in the specified calendar. (iOS only) **Parameters:** | Name | Type | | --- | --- | | calendarName | `string` | **Returns:** `Promise`<`any`\> Returns a Promise that resolves with the list of events, or rejects with an error. * * * ### findEvent[​](https://ionic.io/docs/supported-plugins/calendar#findevent "Direct link to heading") ▸ **findEvent**(title?: _`string`_, location?: _`string`_, notes?: _`string`_, startDate?: _`Date`_, endDate?: _`Date`_): `Promise`<`any`\> Find an event. **Parameters:** | Name | Type | | --- | --- | | `Optional` title | `string` | | `Optional` location | `string` | | `Optional` notes | `string` | | `Optional` startDate | `Date` | | `Optional` endDate | `Date` | **Returns:** `Promise`<`any`\> * * * ### findEventWithOptions[​](https://ionic.io/docs/supported-plugins/calendar#findeventwithoptions "Direct link to heading") ▸ **findEventWithOptions**(title?: _`string`_, location?: _`string`_, notes?: _`string`_, startDate?: _`Date`_, endDate?: _`Date`_, options?: _[CalendarOptions](https://ionic.io/docs/supported-plugins/calendar#calendaroptions) _): `Promise`<`any`\> Find an event with additional options. **Parameters:** | Name | Type | | --- | --- | | `Optional` title | `string` | | `Optional` location | `string` | | `Optional` notes | `string` | | `Optional` startDate | `Date` | | `Optional` endDate | `Date` | | `Optional` options | [CalendarOptions](https://ionic.io/docs/supported-plugins/calendar#calendaroptions) | **Returns:** `Promise`<`any`\> Returns a Promise that resolves with the event, or rejects with an error. * * * ### getCalendarOptions[​](https://ionic.io/docs/supported-plugins/calendar#getcalendaroptions "Direct link to heading") ▸ **getCalendarOptions**(): [CalendarOptions](https://ionic.io/docs/supported-plugins/calendar#calendaroptions) Returns the default calendar options. **Returns:** [CalendarOptions](https://ionic.io/docs/supported-plugins/calendar#calendaroptions) Returns an object with the default calendar options * * * ### getCreateCalendarOptions[​](https://ionic.io/docs/supported-plugins/calendar#getcreatecalendaroptions "Direct link to heading") ▸ **getCreateCalendarOptions**(): [NameOrOptions](https://ionic.io/docs/supported-plugins/calendar#nameoroptions) Returns options for a custom calender with specific color **Returns:** [NameOrOptions](https://ionic.io/docs/supported-plugins/calendar#nameoroptions) Returns an object with the default options * * * ### hasReadPermission[​](https://ionic.io/docs/supported-plugins/calendar#hasreadpermission "Direct link to heading") ▸ **hasReadPermission**(): `Promise`<`boolean`\> Check if we have read permission **Returns:** `Promise`<`boolean`\> * * * ### hasReadWritePermission[​](https://ionic.io/docs/supported-plugins/calendar#hasreadwritepermission "Direct link to heading") ▸ **hasReadWritePermission**(): `Promise`<`boolean`\> This function checks if we have permission to read/write from/to the calendar. The promise will resolve with `true` when: * You're running on iOS, or * You're targeting API level lower than 23, or * You're using Android < 6, or * You've already granted permission If this returns false, you should call the `requestReadWritePermission` function **Returns:** `Promise`<`boolean`\> * * * ### hasWritePermission[​](https://ionic.io/docs/supported-plugins/calendar#haswritepermission "Direct link to heading") ▸ **hasWritePermission**(): `Promise`<`boolean`\> Check if we have write permission **Returns:** `Promise`<`boolean`\> * * * ### listCalendars[​](https://ionic.io/docs/supported-plugins/calendar#listcalendars "Direct link to heading") ▸ **listCalendars**(): `Promise`<`any`\> Get a list of all calendars. **Returns:** `Promise`<`any`\> A Promise that resolves with the list of calendars, or rejects with an error. * * * ### listEventsInRange[​](https://ionic.io/docs/supported-plugins/calendar#listeventsinrange "Direct link to heading") ▸ **listEventsInRange**(startDate: _`Date`_, endDate: _`Date`_): `Promise`<`any`\> Find a list of events within the specified date range. (Android only) **Parameters:** | Name | Type | | --- | --- | | startDate | `Date` | | endDate | `Date` | **Returns:** `Promise`<`any`\> Returns a Promise that resolves with the list of events, or rejects with an error. * * * ### modifyEvent[​](https://ionic.io/docs/supported-plugins/calendar#modifyevent "Direct link to heading") ▸ **modifyEvent**(title?: _`string`_, location?: _`string`_, notes?: _`string`_, startDate?: _`Date`_, endDate?: _`Date`_, newTitle?: _`string`_, newLocation?: _`string`_, newNotes?: _`string`_, newStartDate?: _`Date`_, newEndDate?: _`Date`_): `Promise`<`any`\> Modify an event. (iOS only) **Parameters:** | Name | Type | | --- | --- | | `Optional` title | `string` | | `Optional` location | `string` | | `Optional` notes | `string` | | `Optional` startDate | `Date` | | `Optional` endDate | `Date` | | `Optional` newTitle | `string` | | `Optional` newLocation | `string` | | `Optional` newNotes | `string` | | `Optional` newStartDate | `Date` | | `Optional` newEndDate | `Date` | **Returns:** `Promise`<`any`\> Returns a Promise * * * ### modifyEventWithOptions[​](https://ionic.io/docs/supported-plugins/calendar#modifyeventwithoptions "Direct link to heading") ▸ **modifyEventWithOptions**(title?: _`string`_, location?: _`string`_, notes?: _`string`_, startDate?: _`Date`_, endDate?: _`Date`_, newTitle?: _`string`_, newLocation?: _`string`_, newNotes?: _`string`_, newStartDate?: _`Date`_, newEndDate?: _`Date`_, filterOptions?: _[CalendarOptions](https://ionic.io/docs/supported-plugins/calendar#calendaroptions) _, newOptions?: _[CalendarOptions](https://ionic.io/docs/supported-plugins/calendar#calendaroptions) _): `Promise`<`any`\> Modify an event with additional options. (iOS only) **Parameters:** | Name | Type | | --- | --- | | `Optional` title | `string` | | `Optional` location | `string` | | `Optional` notes | `string` | | `Optional` startDate | `Date` | | `Optional` endDate | `Date` | | `Optional` newTitle | `string` | | `Optional` newLocation | `string` | | `Optional` newNotes | `string` | | `Optional` newStartDate | `Date` | | `Optional` newEndDate | `Date` | | `Optional` filterOptions | [CalendarOptions](https://ionic.io/docs/supported-plugins/calendar#calendaroptions) | | `Optional` newOptions | [CalendarOptions](https://ionic.io/docs/supported-plugins/calendar#calendaroptions) | **Returns:** `Promise`<`any`\> Returns a Promise * * * ### openCalendar[​](https://ionic.io/docs/supported-plugins/calendar#opencalendar "Direct link to heading") ▸ **openCalendar**(date: _`Date`_): `Promise`<`any`\> Open the calendar at the specified date. **Parameters:** | Name | Type | Description | | --- | --- | --- | | date | `Date` | The date you want to open the calendar on | **Returns:** `Promise`<`any`\> Promise returns a promise * * * ### requestReadPermission[​](https://ionic.io/docs/supported-plugins/calendar#requestreadpermission "Direct link to heading") ▸ **requestReadPermission**(): `Promise`<`any`\> Request read permission **Returns:** `Promise`<`any`\> * * * ### requestReadWritePermission[​](https://ionic.io/docs/supported-plugins/calendar#requestreadwritepermission "Direct link to heading") ▸ **requestReadWritePermission**(): `Promise`<`any`\> Requests read/write permissions **Returns:** `Promise`<`any`\> * * * ### requestWritePermission[​](https://ionic.io/docs/supported-plugins/calendar#requestwritepermission "Direct link to heading") ▸ **requestWritePermission**(): `Promise`<`any`\> Request write permission **Returns:** `Promise`<`any`\> * * * * * * Interfaces[​](https://ionic.io/docs/supported-plugins/calendar#interfaces-1 "Direct link to heading") ------------------------------------------------------------------------------------------------------ ### CalendarOptions[​](https://ionic.io/docs/supported-plugins/calendar#calendaroptions "Direct link to heading") **CalendarOptions**: ### `` calendarId[​](https://ionic.io/docs/supported-plugins/calendar#optional-calendarid "Direct link to heading") **● calendarId**: _`number`_ Calendar id * * * ### `` calendarName[​](https://ionic.io/docs/supported-plugins/calendar#optional-calendarname "Direct link to heading") **● calendarName**: _`string`_ Calendar name. Ths is supported by `iOS` only. * * * ### `` firstReminderMinutes[​](https://ionic.io/docs/supported-plugins/calendar#optional-firstreminderminutes "Direct link to heading") **● firstReminderMinutes**: _`number`_ * * * ### `` id[​](https://ionic.io/docs/supported-plugins/calendar#optional-id "Direct link to heading") **● id**: _`string`_ Id * * * ### `` recurrence[​](https://ionic.io/docs/supported-plugins/calendar#optional-recurrence "Direct link to heading") **● recurrence**: _`string`_ Recurrence. Can be set to `daily`, `weekly`, `monthly` or `yearly` * * * ### `` recurrenceEndDate[​](https://ionic.io/docs/supported-plugins/calendar#optional-recurrenceenddate "Direct link to heading") **● recurrenceEndDate**: _`Date`_ Recurrence end date. Valid only when `recurrence` option is set. * * * ### `` recurrenceInterval[​](https://ionic.io/docs/supported-plugins/calendar#optional-recurrenceinterval "Direct link to heading") **● recurrenceInterval**: _`number`_ Recurrence interval. Valid only when `recurrence` option is set. * * * ### `` secondReminderMinutes[​](https://ionic.io/docs/supported-plugins/calendar#optional-secondreminderminutes "Direct link to heading") **● secondReminderMinutes**: _`number`_ * * * ### `` url[​](https://ionic.io/docs/supported-plugins/calendar#optional-url "Direct link to heading") **● url**: _`string`_ URL * * * * * * ### NameOrOptions[​](https://ionic.io/docs/supported-plugins/calendar#nameoroptions "Direct link to heading") **NameOrOptions**: ### `` calendarColor[​](https://ionic.io/docs/supported-plugins/calendar#optional-calendarcolor "Direct link to heading") **● calendarColor**: _`string`_ Calendar color as a HEX string * * * ### `` calendarName[​](https://ionic.io/docs/supported-plugins/calendar#optional-calendarname-1 "Direct link to heading") **● calendarName**: _`string`_ Calendar name * * * * * * * [Index](https://ionic.io/docs/supported-plugins/calendar#index) * [Classes](https://ionic.io/docs/supported-plugins/calendar#classes) * [Interfaces](https://ionic.io/docs/supported-plugins/calendar#interfaces) * [Classes](https://ionic.io/docs/supported-plugins/calendar#classes-1) * [Calendar](https://ionic.io/docs/supported-plugins/calendar#calendar) * [createCalendar](https://ionic.io/docs/supported-plugins/calendar#createcalendar) * [createEvent](https://ionic.io/docs/supported-plugins/calendar#createevent) * [createEventInteractively](https://ionic.io/docs/supported-plugins/calendar#createeventinteractively) * [createEventInteractivelyWithOptions](https://ionic.io/docs/supported-plugins/calendar#createeventinteractivelywithoptions) * [createEventWithOptions](https://ionic.io/docs/supported-plugins/calendar#createeventwithoptions) * [deleteCalendar](https://ionic.io/docs/supported-plugins/calendar#deletecalendar) * [deleteEvent](https://ionic.io/docs/supported-plugins/calendar#deleteevent) * [deleteEventById](https://ionic.io/docs/supported-plugins/calendar#deleteeventbyid) * [deleteEventFromNamedCalendar](https://ionic.io/docs/supported-plugins/calendar#deleteeventfromnamedcalendar) * [findAllEventsInNamedCalendar](https://ionic.io/docs/supported-plugins/calendar#findalleventsinnamedcalendar) * [findEvent](https://ionic.io/docs/supported-plugins/calendar#findevent) * [findEventWithOptions](https://ionic.io/docs/supported-plugins/calendar#findeventwithoptions) * [getCalendarOptions](https://ionic.io/docs/supported-plugins/calendar#getcalendaroptions) * [getCreateCalendarOptions](https://ionic.io/docs/supported-plugins/calendar#getcreatecalendaroptions) * [hasReadPermission](https://ionic.io/docs/supported-plugins/calendar#hasreadpermission) * [hasReadWritePermission](https://ionic.io/docs/supported-plugins/calendar#hasreadwritepermission) * [hasWritePermission](https://ionic.io/docs/supported-plugins/calendar#haswritepermission) * [listCalendars](https://ionic.io/docs/supported-plugins/calendar#listcalendars) * [listEventsInRange](https://ionic.io/docs/supported-plugins/calendar#listeventsinrange) * [modifyEvent](https://ionic.io/docs/supported-plugins/calendar#modifyevent) * [modifyEventWithOptions](https://ionic.io/docs/supported-plugins/calendar#modifyeventwithoptions) * [openCalendar](https://ionic.io/docs/supported-plugins/calendar#opencalendar) * [requestReadPermission](https://ionic.io/docs/supported-plugins/calendar#requestreadpermission) * [requestReadWritePermission](https://ionic.io/docs/supported-plugins/calendar#requestreadwritepermission) * [requestWritePermission](https://ionic.io/docs/supported-plugins/calendar#requestwritepermission) * [Interfaces](https://ionic.io/docs/supported-plugins/calendar#interfaces-1) * [CalendarOptions](https://ionic.io/docs/supported-plugins/calendar#calendaroptions) * [`` calendarId](https://ionic.io/docs/supported-plugins/calendar#optional-calendarid) * [`` calendarName](https://ionic.io/docs/supported-plugins/calendar#optional-calendarname) * [`` firstReminderMinutes](https://ionic.io/docs/supported-plugins/calendar#optional-firstreminderminutes) * [`` id](https://ionic.io/docs/supported-plugins/calendar#optional-id) * [`` recurrence](https://ionic.io/docs/supported-plugins/calendar#optional-recurrence) * [`` recurrenceEndDate](https://ionic.io/docs/supported-plugins/calendar#optional-recurrenceenddate) * [`` recurrenceInterval](https://ionic.io/docs/supported-plugins/calendar#optional-recurrenceinterval) * [`` secondReminderMinutes](https://ionic.io/docs/supported-plugins/calendar#optional-secondreminderminutes) * [`` url](https://ionic.io/docs/supported-plugins/calendar#optional-url) * [NameOrOptions](https://ionic.io/docs/supported-plugins/calendar#nameoroptions) * [`` calendarColor](https://ionic.io/docs/supported-plugins/calendar#optional-calendarcolor) * [`` calendarName](https://ionic.io/docs/supported-plugins/calendar#optional-calendarname-1) --- # Deep Links - Supported Plugins [Skip to main content](https://ionic.io/docs/supported-plugins/deeplinks#) ##### EOL Notice Deep Links will reach its end-of-life on July 1, 2024, and will no longer receive updates or support. Please see [Support Policy](https://ionic.io/docs/supported-plugins/support-policy) for additional information. The Deep Links plugin provides deep linking support for both Android App Links and iOS Universal Links. Deep links point to a page inside of a mobile app. For example, if you had an online store selling products, upon navigating to a website link ([https://yoursite.com/product/cool-beans](https://yoursite.com/product/cool-beans) ) the app could open and navigate to display the Cool Beans product. The mobile app can also be opened directly to the Cool Beans product page using a custom URL scheme, like `coolbeans://product/cool-beans`. Installation[​](https://ionic.io/docs/supported-plugins/deeplinks#installation "Direct link to heading") --------------------------------------------------------------------------------------------------------- If you have not already setup Ionic Enterprise in your app, [follow the one-time setup steps](https://ionic.io/docs/supported-plugins/setup) . Next, install the plugin: * Capacitor * Cordova npm install @ionic-enterprise/deeplinksnpx cap sync Copy ionic cordova plugin add @ionic-enterprise/deeplinks Copy Index[​](https://ionic.io/docs/supported-plugins/deeplinks#index "Direct link to heading") ------------------------------------------------------------------------------------------- ### Classes[​](https://ionic.io/docs/supported-plugins/deeplinks#classes "Direct link to heading") * [Deeplinks](https://ionic.io/docs/supported-plugins/deeplinks#deeplinks) ### Interfaces[​](https://ionic.io/docs/supported-plugins/deeplinks#interfaces "Direct link to heading") * [DeeplinkMatch](https://ionic.io/docs/supported-plugins/deeplinks#deeplinkmatch) * [DeeplinkOptions](https://ionic.io/docs/supported-plugins/deeplinks#deeplinkoptions) * * * Classes[​](https://ionic.io/docs/supported-plugins/deeplinks#classes-1 "Direct link to heading") ------------------------------------------------------------------------------------------------- ### Deeplinks[​](https://ionic.io/docs/supported-plugins/deeplinks#deeplinks "Direct link to heading") **Deeplinks**: Please read the [ionic plugin deeplinks docs](https://github.com/ionic-team/ionic-plugin-deeplinks) for iOS and Android integration. You must add `universal-links` to your `config.xml` and set up Apple App Site Association (AASA) for iOS and Asset Links for Android. _**usage**_: import { Deeplinks } from '@ionic-enterprise/deeplinks/ngx';constructor(private deeplinks: Deeplinks) { }this.deeplinks.route({ '/about-us': AboutPage, '/universal-links-test': AboutPage, '/products/:productId': ProductPage }).subscribe(match => { // match.$route - the route we matched, which is the matched entry from the arguments to route() // match.$args - the args passed in the link // match.$link - the full link data console.log('Successfully matched route', match); }, nomatch => { // nomatch.$link - the full link data console.error('Got a deeplink that didn\'t match', nomatch); }); Copy Alternatively, if you're using Ionic, there's a convenience method that takes a reference to a `NavController` and handles the actual navigation for you: this.deeplinks .routeWithNavController(this.navController, { '/about-us': AboutPage, '/products/:productId': ProductPage, }) .subscribe( (match) => { // match.$route - the route we matched, which is the matched entry from the arguments to route() // match.$args - the args passed in the link // match.$link - the full link data console.log('Successfully matched route', match); }, (nomatch) => { // nomatch.$link - the full link data console.error("Got a deeplink that didn't match", nomatch); } ); Copy See the [Ionic Deeplinks Demo](https://github.com/ionic-team/ionic2-deeplinks-demo/blob/master/app/app.ts) for an example of how to retrieve the `NavController` reference at runtime. _**interfaces**_: DeeplinkMatch ### route[​](https://ionic.io/docs/supported-plugins/deeplinks#route "Direct link to heading") ▸ **route**(paths: _`any`_): `Observable`<[DeeplinkMatch](https://ionic.io/docs/supported-plugins/deeplinks#deeplinkmatch) \> Define a set of paths to match against incoming deeplinks. **Parameters:** | Name | Type | Description | | --- | --- | --- | | paths | `any` | Define a set of paths to match against incoming deeplinks. paths takes an object of the form { 'path': data }. If a deeplink matches the path, the resulting path-data pair will be returned in the promise result which you can then use to navigate in the app as you see fit. | **Returns:** `Observable`<[DeeplinkMatch](https://ionic.io/docs/supported-plugins/deeplinks#deeplinkmatch) \> Returns an Observable that is called each time a deeplink comes through, and errors if a deeplink comes through that does not match a given path. * * * ### routeWithNavController[​](https://ionic.io/docs/supported-plugins/deeplinks#routewithnavcontroller "Direct link to heading") ▸ **routeWithNavController**(navController: _`any`_, paths: _`any`_, options?: _[DeeplinkOptions](https://ionic.io/docs/supported-plugins/deeplinks#deeplinkoptions) _): `Observable`<[DeeplinkMatch](https://ionic.io/docs/supported-plugins/deeplinks#deeplinkmatch) \> This is a convenience version of `route` that takes a reference to a NavController from Ionic, or a custom class that conforms to this protocol: NavController.push = function(View, Params){} This handler will automatically navigate when a route matches. If you need finer-grained control over the behavior of a matching deeplink, use the plain `route` method. **Parameters:** | Name | Type | Description | | --- | --- | --- | | navController | `any` | Define a set of paths to match against incoming deeplinks. paths takes an object of the form { 'path': data }. If a deeplink matches the path, the resulting path-data pair will be returned in the promise result which you can then use to navigate in the app as you see fit. | | paths | `any` | | | `Optional` options | [DeeplinkOptions](https://ionic.io/docs/supported-plugins/deeplinks#deeplinkoptions) | | **Returns:** `Observable`<[DeeplinkMatch](https://ionic.io/docs/supported-plugins/deeplinks#deeplinkmatch) \> Returns an Observable that resolves each time a deeplink comes through, and errors if a deeplink comes through that does not match a given path. * * * * * * Interfaces[​](https://ionic.io/docs/supported-plugins/deeplinks#interfaces-1 "Direct link to heading") ------------------------------------------------------------------------------------------------------- ### DeeplinkMatch[​](https://ionic.io/docs/supported-plugins/deeplinks#deeplinkmatch "Direct link to heading") **DeeplinkMatch**: ### $args[​](https://ionic.io/docs/supported-plugins/deeplinks#args "Direct link to heading") **● $args**: _`any`_ Any arguments passed either through route parameters or GET parameters * * * ### $link[​](https://ionic.io/docs/supported-plugins/deeplinks#link "Direct link to heading") **● $link**: _`any`_ The deeplink object processed from the plugin, along with any any internal native data available as "extras" at the time the route was matched (for example, Facebook sometimes adds extra data) * * * ### $route[​](https://ionic.io/docs/supported-plugins/deeplinks#route-1 "Direct link to heading") **● $route**: _`any`_ The route info for the matched route * * * * * * ### DeeplinkOptions[​](https://ionic.io/docs/supported-plugins/deeplinks#deeplinkoptions "Direct link to heading") **DeeplinkOptions**: ### root[​](https://ionic.io/docs/supported-plugins/deeplinks#root "Direct link to heading") **● root**: _`boolean`_ Set the matched route as root page using `navCtrl.setRoot()` method. * * * * * * * [Index](https://ionic.io/docs/supported-plugins/deeplinks#index) * [Classes](https://ionic.io/docs/supported-plugins/deeplinks#classes) * [Interfaces](https://ionic.io/docs/supported-plugins/deeplinks#interfaces) * [Classes](https://ionic.io/docs/supported-plugins/deeplinks#classes-1) * [Deeplinks](https://ionic.io/docs/supported-plugins/deeplinks#deeplinks) * [route](https://ionic.io/docs/supported-plugins/deeplinks#route) * [routeWithNavController](https://ionic.io/docs/supported-plugins/deeplinks#routewithnavcontroller) * [Interfaces](https://ionic.io/docs/supported-plugins/deeplinks#interfaces-1) * [DeeplinkMatch](https://ionic.io/docs/supported-plugins/deeplinks#deeplinkmatch) * [$args](https://ionic.io/docs/supported-plugins/deeplinks#args) * [$link](https://ionic.io/docs/supported-plugins/deeplinks#link) * [$route](https://ionic.io/docs/supported-plugins/deeplinks#route-1) * [DeeplinkOptions](https://ionic.io/docs/supported-plugins/deeplinks#deeplinkoptions) * [root](https://ionic.io/docs/supported-plugins/deeplinks#root) --- # App Rate - Supported Plugins [Skip to main content](https://ionic.io/docs/supported-plugins/app-rate#) ##### EOL Notice App Rate will reach its end-of-life on July 1, 2024, and will no longer receive updates or support. Please see [Support Policy](https://ionic.io/docs/supported-plugins/support-policy) for additional information. The App Rate plugin makes it easy to prompt the user to rate your app - either now, later, or never. Installation[​](https://ionic.io/docs/supported-plugins/app-rate#installation "Direct link to heading") -------------------------------------------------------------------------------------------------------- If you have not already setup Ionic Enterprise in your app, [follow the one-time setup steps](https://ionic.io/docs/supported-plugins/setup) . Next, install the plugin: * Capacitor * Cordova npm install @ionic-enterprise/app-ratenpx cap sync Copy ionic cordova plugin add @ionic-enterprise/app-rate Copy Index[​](https://ionic.io/docs/supported-plugins/app-rate#index "Direct link to heading") ------------------------------------------------------------------------------------------ ### Classes[​](https://ionic.io/docs/supported-plugins/app-rate#classes "Direct link to heading") * [AppRate](https://ionic.io/docs/supported-plugins/app-rate#apprate) ### Interfaces[​](https://ionic.io/docs/supported-plugins/app-rate#interfaces "Direct link to heading") * [AppRateCallbacks](https://ionic.io/docs/supported-plugins/app-rate#appratecallbacks) * [AppRateCustomLocale](https://ionic.io/docs/supported-plugins/app-rate#appratecustomlocale) * [AppRatePreferences](https://ionic.io/docs/supported-plugins/app-rate#appratepreferences) * [AppUrls](https://ionic.io/docs/supported-plugins/app-rate#appurls) * * * Classes[​](https://ionic.io/docs/supported-plugins/app-rate#classes-1 "Direct link to heading") ------------------------------------------------------------------------------------------------ ### AppRate[​](https://ionic.io/docs/supported-plugins/app-rate#apprate "Direct link to heading") **AppRate**: _**name**_: App Rate _**description**_: The AppRate plugin makes it easy to prompt the user to rate your app, either now, later, or never. _**usage**_: import { AppRate } from '@ionic-enterprise/app-rate/ngx';constructor(private appRate: AppRate) { }...// set certain preferencesthis.appRate.preferences.storeAppURL = { ios: '', android: 'market://details?id=', windows: 'ms-windows-store://review/?ProductId='}this.appRate.promptForRating(true);// or, override the whole preferences objectthis.appRate.preferences = { usesUntilPrompt: 3, storeAppURL: { ios: '', android: 'market://details?id=', windows: 'ms-windows-store://review/?ProductId=' }}this.appRate.promptForRating(false); Copy _**interfaces**_: AppRatePreferences AppUrls AppRateCallbacks AppRateCustomLocal ### preferences[​](https://ionic.io/docs/supported-plugins/app-rate#preferences "Direct link to heading") **● preferences**: _[AppRatePreferences](https://ionic.io/docs/supported-plugins/app-rate#appratepreferences) _ Configure various settings for the Rating View. See table below for options * * * ### navigateToAppStore[​](https://ionic.io/docs/supported-plugins/app-rate#navigatetoappstore "Direct link to heading") ▸ **navigateToAppStore**(): `void` Immediately send the user to the app store rating page **Returns:** `void` * * * ### promptForRating[​](https://ionic.io/docs/supported-plugins/app-rate#promptforrating "Direct link to heading") ▸ **promptForRating**(immediately: _`boolean`_): `void` Prompts the user for rating **Parameters:** | Name | Type | Description | | --- | --- | --- | | immediately | `boolean` | Show the rating prompt immediately. | **Returns:** `void` * * * * * * Interfaces[​](https://ionic.io/docs/supported-plugins/app-rate#interfaces-1 "Direct link to heading") ------------------------------------------------------------------------------------------------------ ### AppRateCallbacks[​](https://ionic.io/docs/supported-plugins/app-rate#appratecallbacks "Direct link to heading") **AppRateCallbacks**: ### `` handleNegativeFeedback[​](https://ionic.io/docs/supported-plugins/app-rate#optional-handlenegativefeedback "Direct link to heading") **● handleNegativeFeedback**: _`Function`_ call back function. called when user clicked on negative feedback * * * ### `` onButtonClicked[​](https://ionic.io/docs/supported-plugins/app-rate#optional-onbuttonclicked "Direct link to heading") **● onButtonClicked**: _`Function`_ call back function. called when user clicked on rate-dialog buttons * * * ### `` onRateDialogShow[​](https://ionic.io/docs/supported-plugins/app-rate#optional-onratedialogshow "Direct link to heading") **● onRateDialogShow**: _`Function`_ call back function. called when rate-dialog showing * * * * * * ### AppRateCustomLocale[​](https://ionic.io/docs/supported-plugins/app-rate#appratecustomlocale "Direct link to heading") **AppRateCustomLocale**: ### `` appRatePromptMessage[​](https://ionic.io/docs/supported-plugins/app-rate#optional-appratepromptmessage "Direct link to heading") **● appRatePromptMessage**: _`string`_ Feedback prompt message * * * ### `` appRatePromptTitle[​](https://ionic.io/docs/supported-plugins/app-rate#optional-apprateprompttitle "Direct link to heading") **● appRatePromptTitle**: _`string`_ App rate prompt title * * * ### `` cancelButtonLabel[​](https://ionic.io/docs/supported-plugins/app-rate#optional-cancelbuttonlabel "Direct link to heading") **● cancelButtonLabel**: _`string`_ Cancel button label * * * ### `` feedbackPromptMessage[​](https://ionic.io/docs/supported-plugins/app-rate#optional-feedbackpromptmessage "Direct link to heading") **● feedbackPromptMessage**: _`string`_ Feedback prompt message * * * ### `` feedbackPromptTitle[​](https://ionic.io/docs/supported-plugins/app-rate#optional-feedbackprompttitle "Direct link to heading") **● feedbackPromptTitle**: _`string`_ Feedback prompt title * * * ### `` laterButtonLabel[​](https://ionic.io/docs/supported-plugins/app-rate#optional-laterbuttonlabel "Direct link to heading") **● laterButtonLabel**: _`string`_ Later button label * * * ### `` message[​](https://ionic.io/docs/supported-plugins/app-rate#optional-message "Direct link to heading") **● message**: _`string`_ Message * * * ### `` noButtonLabel[​](https://ionic.io/docs/supported-plugins/app-rate#optional-nobuttonlabel "Direct link to heading") **● noButtonLabel**: _`string`_ No button label * * * ### `` rateButtonLabel[​](https://ionic.io/docs/supported-plugins/app-rate#optional-ratebuttonlabel "Direct link to heading") **● rateButtonLabel**: _`string`_ Rate button label * * * ### `` title[​](https://ionic.io/docs/supported-plugins/app-rate#optional-title "Direct link to heading") **● title**: _`string`_ Title * * * ### `` yesButtonLabel[​](https://ionic.io/docs/supported-plugins/app-rate#optional-yesbuttonlabel "Direct link to heading") **● yesButtonLabel**: _`string`_ Yes button label * * * * * * ### AppRatePreferences[​](https://ionic.io/docs/supported-plugins/app-rate#appratepreferences "Direct link to heading") **AppRatePreferences**: ### `` callbacks[​](https://ionic.io/docs/supported-plugins/app-rate#optional-callbacks "Direct link to heading") **● callbacks**: _[AppRateCallbacks](https://ionic.io/docs/supported-plugins/app-rate#appratecallbacks) _ Callbacks for events * * * ### `` customLocale[​](https://ionic.io/docs/supported-plugins/app-rate#optional-customlocale "Direct link to heading") **● customLocale**: _[AppRateCustomLocale](https://ionic.io/docs/supported-plugins/app-rate#appratecustomlocale) _ Custom locale object * * * ### `` displayAppName[​](https://ionic.io/docs/supported-plugins/app-rate#optional-displayappname "Direct link to heading") **● displayAppName**: _`string`_ Custom application title * * * ### `` inAppReview[​](https://ionic.io/docs/supported-plugins/app-rate#optional-inappreview "Direct link to heading") **● inAppReview**: _`boolean`_ leave app or no when application page opened in app store (now supported only for iOS). Defaults to `false` * * * ### `` promptAgainForEachNewVersion[​](https://ionic.io/docs/supported-plugins/app-rate#optional-promptagainforeachnewversion "Direct link to heading") **● promptAgainForEachNewVersion**: _`boolean`_ Show dialog again when application version will be updated. Defaults to `true` * * * ### `` simpleMode[​](https://ionic.io/docs/supported-plugins/app-rate#optional-simplemode "Direct link to heading") **● simpleMode**: _`boolean`_ Simple Mode to display the rate dialog directly and bypass negative feedback filtering flow * * * ### `` storeAppURL[​](https://ionic.io/docs/supported-plugins/app-rate#optional-storeappurl "Direct link to heading") **● storeAppURL**: _[AppUrls](https://ionic.io/docs/supported-plugins/app-rate#appurls) _ App Store URLS * * * ### `` useCustomRateDialog[​](https://ionic.io/docs/supported-plugins/app-rate#optional-usecustomratedialog "Direct link to heading") **● useCustomRateDialog**: _`boolean`_ use custom view for rate dialog. Defaults to `false` * * * ### `` useLanguage[​](https://ionic.io/docs/supported-plugins/app-rate#optional-uselanguage "Direct link to heading") **● useLanguage**: _`string`_ Custom BCP 47 language tag * * * ### `` usesUntilPrompt[​](https://ionic.io/docs/supported-plugins/app-rate#optional-usesuntilprompt "Direct link to heading") **● usesUntilPrompt**: _`number`_ count of runs of application before dialog will be displayed. Defaults to `3` * * * * * * ### AppUrls[​](https://ionic.io/docs/supported-plugins/app-rate#appurls "Direct link to heading") **AppUrls**: ### `` android[​](https://ionic.io/docs/supported-plugins/app-rate#optional-android "Direct link to heading") **● android**: _`string`_ application URL in GooglePlay * * * ### `` blackberry[​](https://ionic.io/docs/supported-plugins/app-rate#optional-blackberry "Direct link to heading") **● blackberry**: _`string`_ application URL in AppWorld * * * ### `` ios[​](https://ionic.io/docs/supported-plugins/app-rate#optional-ios "Direct link to heading") **● ios**: _`string`_ application id in AppStore * * * ### `` windows[​](https://ionic.io/docs/supported-plugins/app-rate#optional-windows "Direct link to heading") **● windows**: _`string`_ application URL in Windows Store * * * ### `` windows8[​](https://ionic.io/docs/supported-plugins/app-rate#optional-windows8 "Direct link to heading") **● windows8**: _`string`_ application URL in WindowsStore * * * * * * * 1.5.0 * [PR #253](https://github.com/pushandplay/cordova-plugin-apprate/pull/253) - Remove iOS rating counter in favor of native approach * [PR #252](https://github.com/pushandplay/cordova-plugin-apprate/pull/252) - Postpone initial AppRate.init() until `deviceready` * [PR #239](https://github.com/pushandplay/cordova-plugin-apprate/pull/239) - Remove inappbrowser dependency adding support to choose between inappbrowser and safariviewcontroller * [PR #244](https://github.com/pushandplay/cordova-plugin-apprate/pull/244) - Use ES5 var instead of ES6 const for better browser compatibility * [PR #231](https://github.com/pushandplay/cordova-plugin-apprate/pull/231) - Displaying store view page before it loads for improved UX * [PR #228](https://github.com/pushandplay/cordova-plugin-apprate/pull/228) - Add native support for windows platform rating * [PR #220](https://github.com/pushandplay/cordova-plugin-apprate/pull/220) - Remove dependency on deprecated cordova-plugin-globalization in favor of browser `Intl` api * Various language fixes and improvements * [View All Merged PR's](https://github.com/pushandplay/cordova-plugin-apprate/compare/v1.4.0...master) * 1.4.0 * [Merged PR's](https://github.com/pushandplay/cordova-plugin-apprate/pulls?utf8=%E2%9C%93&q=is%3Apr+is%3Aclosed+merged%3A2017-06-24..2018-06-13) * [PR #211](https://github.com/pushandplay/cordova-plugin-apprate/pull/211) - Use NativeStorage for persistance across installs * Breaking Change - Instead of directly asking our users to Rate our app, we now handle this flow much better. The first popup will be "Do you like using appName?" If the user says 'Yes' then we ask the user if they would like take a moment and rate our app. If the user says 'NO', We ask the user another question: "Would you mind providing us feedback?" If the user says yes, then we can run a custom callback to handle this such as sending an email. To revert to previous behaviour you can use `simpleMode: true` * iOS 9+ now redirects directly to write review * iOS 10.3+ now supports In-App Reviews. One limitation to note is you can only prompt the user 3 times per year before it must fallback to the old open review in store. The preference option to disable this feature is called `inAppReview` and defaults to true, this option was previously named `openStoreInApp` and defaulted to false. * 1.3.0 * Added a general done callbacks called once we have completed the job, not showing or showing the popup * Fix %@ with customLocale * Fix bugs with callbacks * Fix deep links on ios 9+ * Locales updates * 1.2.1 * Align the version in the package.json and the plugin.xml * 1.2.0 * Remove coffeescript to remove barrier of entry to contributions * Remove docs generation, just use the readme instead * Improve readme * Add Windows support from PR #120 * Fix JSON parse for Android 2.x as per PR #73 * Remove InAppBrowser dependency * Add/Improve Locales * 1.1.12 * Bump version to be higher than the previous `cordova-plugin-apprate` on the NPM registry * Clean up readme * 1.1.9 * Update id to `cordova-plugin-apprate` and update dependencies * Add finnish locale * [Index](https://ionic.io/docs/supported-plugins/app-rate#index) * [Classes](https://ionic.io/docs/supported-plugins/app-rate#classes) * [Interfaces](https://ionic.io/docs/supported-plugins/app-rate#interfaces) * [Classes](https://ionic.io/docs/supported-plugins/app-rate#classes-1) * [AppRate](https://ionic.io/docs/supported-plugins/app-rate#apprate) * [preferences](https://ionic.io/docs/supported-plugins/app-rate#preferences) * [navigateToAppStore](https://ionic.io/docs/supported-plugins/app-rate#navigatetoappstore) * [promptForRating](https://ionic.io/docs/supported-plugins/app-rate#promptforrating) * [Interfaces](https://ionic.io/docs/supported-plugins/app-rate#interfaces-1) * [AppRateCallbacks](https://ionic.io/docs/supported-plugins/app-rate#appratecallbacks) * [`` handleNegativeFeedback](https://ionic.io/docs/supported-plugins/app-rate#optional-handlenegativefeedback) * [`` onButtonClicked](https://ionic.io/docs/supported-plugins/app-rate#optional-onbuttonclicked) * [`` onRateDialogShow](https://ionic.io/docs/supported-plugins/app-rate#optional-onratedialogshow) * [AppRateCustomLocale](https://ionic.io/docs/supported-plugins/app-rate#appratecustomlocale) * [`` appRatePromptMessage](https://ionic.io/docs/supported-plugins/app-rate#optional-appratepromptmessage) * [`` appRatePromptTitle](https://ionic.io/docs/supported-plugins/app-rate#optional-apprateprompttitle) * [`` cancelButtonLabel](https://ionic.io/docs/supported-plugins/app-rate#optional-cancelbuttonlabel) * [`` feedbackPromptMessage](https://ionic.io/docs/supported-plugins/app-rate#optional-feedbackpromptmessage) * [`` feedbackPromptTitle](https://ionic.io/docs/supported-plugins/app-rate#optional-feedbackprompttitle) * [`` laterButtonLabel](https://ionic.io/docs/supported-plugins/app-rate#optional-laterbuttonlabel) * [`` message](https://ionic.io/docs/supported-plugins/app-rate#optional-message) * [`` noButtonLabel](https://ionic.io/docs/supported-plugins/app-rate#optional-nobuttonlabel) * [`` rateButtonLabel](https://ionic.io/docs/supported-plugins/app-rate#optional-ratebuttonlabel) * [`` title](https://ionic.io/docs/supported-plugins/app-rate#optional-title) * [`` yesButtonLabel](https://ionic.io/docs/supported-plugins/app-rate#optional-yesbuttonlabel) * [AppRatePreferences](https://ionic.io/docs/supported-plugins/app-rate#appratepreferences) * [`` callbacks](https://ionic.io/docs/supported-plugins/app-rate#optional-callbacks) * [`` customLocale](https://ionic.io/docs/supported-plugins/app-rate#optional-customlocale) * [`` displayAppName](https://ionic.io/docs/supported-plugins/app-rate#optional-displayappname) * [`` inAppReview](https://ionic.io/docs/supported-plugins/app-rate#optional-inappreview) * [`` promptAgainForEachNewVersion](https://ionic.io/docs/supported-plugins/app-rate#optional-promptagainforeachnewversion) * [`` simpleMode](https://ionic.io/docs/supported-plugins/app-rate#optional-simplemode) * [`` storeAppURL](https://ionic.io/docs/supported-plugins/app-rate#optional-storeappurl) * [`` useCustomRateDialog](https://ionic.io/docs/supported-plugins/app-rate#optional-usecustomratedialog) * [`` useLanguage](https://ionic.io/docs/supported-plugins/app-rate#optional-uselanguage) * [`` usesUntilPrompt](https://ionic.io/docs/supported-plugins/app-rate#optional-usesuntilprompt) * [AppUrls](https://ionic.io/docs/supported-plugins/app-rate#appurls) * [`` android](https://ionic.io/docs/supported-plugins/app-rate#optional-android) * [`` blackberry](https://ionic.io/docs/supported-plugins/app-rate#optional-blackberry) * [`` ios](https://ionic.io/docs/supported-plugins/app-rate#optional-ios) * [`` windows](https://ionic.io/docs/supported-plugins/app-rate#optional-windows) * [`` windows8](https://ionic.io/docs/supported-plugins/app-rate#optional-windows8) --- # Concurrency limits - Appflow [Skip to main content](https://ionic.io/docs/appflow/concurrency-limits#__docusaurus_skipToContent_fallback) Each account plan has a defined maximum amount of concurrent builds allowed. This limit is enforced at the account level across different apps. When you trigger a build, in the Appflow Dashboard you will notice that a build can have different statuses before it is processed: * **Queued**: this means that your build is queued for the next available runner. Usually your build should not be in this state for more than few seconds. * **Pending**: this means that you have reached your concurrent build limit and your build will continue when your current builds are completed. After the build starts to be processed the statuses are: * **Running**: the build is currently being processed. You can read the logs in the build details. * **Successful**: the build terminated in a correct state. * **Failed**: the build terminated in an incorrect state. --- # Allow Zooming - Accessibility Guide [Skip to main content](https://ionic.io/docs/accessibility/allow-zooming#) Zooming and scaling in an Ionic application is disabled by default which is typical of mobile applications. However when an Ionic application is also deployed to web the expectation is that it can be zoomed/scaled (usually by two fingers sliding away from each other). On a Mac use `CMD` `+` and `-` to zoom in and out. On Windows use `CTRL` `+` and `-`. This feature is important for users with low vision who rely on screen magnifiers. #### Before[​](https://ionic.io/docs/accessibility/allow-zooming#before "Direct link to heading") Copy The above example in `index.html` has the scale fixed to `1.0` and prevents scaling with `user-scalable` set to `no`. #### After[​](https://ionic.io/docs/accessibility/allow-zooming#after "Direct link to heading") Copy The above example allows scaling between `1.0` and `5.0` and allows the user to scale by setting `user-scalable` set to `yes`. ##### note If your application targets native and web then consider programmatically setting scaling on by default for web and off for native. Allowing scaling to be enabled on native as an optional feature can also improve accessibility for users with low vision. --- # Aria Label - Accessibility Guide [Skip to main content](https://ionic.io/docs/accessibility/aria-label#) Buttons should include text explaining their functionality, and if icons are used as buttons, a screen-reader only text or an `aria-label` attribute should be used for that description. #### Before[​](https://ionic.io/docs/accessibility/aria-label#before "Direct link to heading") This example has no indication of what action clicking the image performs. Copy #### After[​](https://ionic.io/docs/accessibility/aria-label#after "Direct link to heading") Copy #### Before[​](https://ionic.io/docs/accessibility/aria-label#before-1 "Direct link to heading") This example has no indication of what the range selection is for. Copy #### After[​](https://ionic.io/docs/accessibility/aria-label#after-1 "Direct link to heading") Copy --- # Alternative Text - Accessibility Guide [Skip to main content](https://ionic.io/docs/accessibility/alt-text#) Images should have an alternative text description that describes both the objects and the embedded text that the image contains, using the "alt" attribute. (See [G94](https://www.w3.org/WAI/WCAG21/Techniques/general/G94.html) ) #### Before[​](https://ionic.io/docs/accessibility/alt-text#before "Direct link to heading") Copy #### After[​](https://ionic.io/docs/accessibility/alt-text#after "Direct link to heading") Search Copy ##### note For clickable elements consider describing the action associated with the image rather a description of the image. In the above example this is why we chose "Search" rather than "Magnifying Glass". Choosing[​](https://ionic.io/docs/accessibility/alt-text#choosing "Direct link to heading") -------------------------------------------------------------------------------------------- Choosing the right alt text for an image is important. Use the following decision tree to help make the right decision. ![Alt Text Decision Tree](https://ionic.io/docs/accessibility/assets/images/alt-text-decision-2598bc20f8ced2abc0889836200e4dd4.png) * Based on [WAI alt text decision tree](https://www.w3.org/WAI/tutorials/images/decision-tree/) * [Choosing](https://ionic.io/docs/accessibility/alt-text#choosing) --- # Email Composer - Capacitor/Cordova In-App Email Plugin | Ionic [Skip to main content](https://ionic.io/docs/supported-plugins/email-composer#) ##### EOL Notice Email Composer will reach its end-of-life on July 1, 2024, and will no longer receive updates or support. Please see [Support Policy](https://ionic.io/docs/supported-plugins/support-policy) for additional information. The Email Composer plugin provides the ability to programmatically create and send emails from within an app. Installation[​](https://ionic.io/docs/supported-plugins/email-composer#installation "Direct link to heading") -------------------------------------------------------------------------------------------------------------- If you have not already setup Ionic Enterprise in your app, [follow the one-time setup steps](https://ionic.io/docs/supported-plugins/setup) . Next, install the plugin: * Capacitor * Cordova npm install @ionic-enterprise/email-composernpx cap sync Copy ionic cordova plugin add @ionic-enterprise/email-composer Copy #### Using with AndroidX Projects (Android)[​](https://ionic.io/docs/supported-plugins/email-composer#using-with-androidx-projects-android "Direct link to heading") This plugin relies on the legacy Android Support libraries and will not work in projects using the newer AndroidX libraries without using the [jetifier](https://www.npmjs.com/package/jetifier) tool to patch them. npm install jetifiernpx jetifier Copy To run it automatically when dependencies are installed, add `"postinstall": "jetifier"` in the `package.json`. Index[​](https://ionic.io/docs/supported-plugins/email-composer#index "Direct link to heading") ------------------------------------------------------------------------------------------------ ### Classes[​](https://ionic.io/docs/supported-plugins/email-composer#classes "Direct link to heading") * [EmailComposer](https://ionic.io/docs/supported-plugins/email-composer#emailcomposer) ### Interfaces[​](https://ionic.io/docs/supported-plugins/email-composer#interfaces "Direct link to heading") * [EmailComposerOptions](https://ionic.io/docs/supported-plugins/email-composer#emailcomposeroptions) * * * Classes[​](https://ionic.io/docs/supported-plugins/email-composer#classes-1 "Direct link to heading") ------------------------------------------------------------------------------------------------------ ### EmailComposer[​](https://ionic.io/docs/supported-plugins/email-composer#emailcomposer "Direct link to heading") _**usage**_: import { EmailComposer } from '@ionic-enterprise/email-composer/ngx';constructor(private emailComposer: EmailComposer) { }...this.emailComposer.isAvailable().then((available: boolean) =>{if(available) { //Now we know we can send}});let email = { to: 'max@mustermann.de', cc: 'erika@mustermann.de', bcc: ['john@doe.com', 'jane@doe.com'], attachments: [ 'file://img/logo.png', 'res://icon.png', 'base64:icon.png//iVBORw0KGgoAAAANSUhEUg...', 'file://README.pdf' ], subject: 'Cordova Icons', body: 'How are you? Nice greetings from Leipzig', isHtml: true}// Send a text message using default optionsthis.emailComposer.open(email); Copy You can also assign aliases to email apps // add aliasthis.email.addAlias('gmail', 'com.google.android.gm');// then use alias when sending emailthis.email.open({ app: 'gmail', ...}); Copy _**interfaces**_: EmailComposerOptions ### addAlias[​](https://ionic.io/docs/supported-plugins/email-composer#addalias "Direct link to heading") ▸ **addAlias**(alias: _`string`_, packageName: _`string`_): `void` Adds a new mail app alias. **Parameters:** | Name | Type | Description | | --- | --- | --- | | alias | `string` | The alias name | | packageName | `string` | The package name | **Returns:** `void` * * * ### getClients[​](https://ionic.io/docs/supported-plugins/email-composer#getclients "Direct link to heading") ▸ **getClients**(): `Promise`<`string`\[\]> Returns an array of email clients installed on the device. **Returns:** `Promise`<`string`\[\]> Resolves if available, rejects if not available * * * ### hasAccount[​](https://ionic.io/docs/supported-plugins/email-composer#hasaccount "Direct link to heading") ▸ **hasAccount**(): `Promise`<`any`\> Verifies if an email account is configured on the device. **Returns:** `Promise`<`any`\> Resolves if available, rejects if not available * * * ### hasClient[​](https://ionic.io/docs/supported-plugins/email-composer#hasclient "Direct link to heading") ▸ **hasClient**(app: _`string`_): `Promise`<`any`\> Verifies if a specific email client is installed on the device. **Parameters:** | Name | Type | | --- | --- | | `Optional` app | `string` | **Returns:** `Promise`<`any`\> Resolves if available, rejects if not available * * * ### hasPermission[​](https://ionic.io/docs/supported-plugins/email-composer#haspermission "Direct link to heading") ▸ **hasPermission**(): `Promise`<`boolean`\> Checks if the app has a permission to access email accounts information **Returns:** `Promise`<`boolean`\> returns a promise that resolves with a boolean that indicates if the permission was granted * * * ### isAvailable[​](https://ionic.io/docs/supported-plugins/email-composer#isavailable "Direct link to heading") ▸ **isAvailable**(app?: _`string`_): `Promise`<`any`\> Verifies if sending emails is supported on the device. **Parameters:** | Name | Type | | --- | --- | | `Optional` app | `string` | **Returns:** `Promise`<`any`\> Resolves if available, rejects if not available * * * ### open[​](https://ionic.io/docs/supported-plugins/email-composer#open "Direct link to heading") ▸ **open**(options: _[EmailComposerOptions](https://ionic.io/docs/supported-plugins/email-composer#emailcomposeroptions) _, scope?: _`any`_): `Promise`<`any`\> Displays the email composer pre-filled with data. **Parameters:** | Name | Type | Description | | --- | --- | --- | | options | [EmailComposerOptions](https://ionic.io/docs/supported-plugins/email-composer#emailcomposeroptions) | Email | | `Optional` scope | `any` | | **Returns:** `Promise`<`any`\> Resolves promise when the EmailComposer has been opened * * * ### requestPermission[​](https://ionic.io/docs/supported-plugins/email-composer#requestpermission "Direct link to heading") ▸ **requestPermission**(): `Promise`<`boolean`\> Request permission to access email accounts information **Returns:** `Promise`<`boolean`\> returns a promise that resolves with a boolean that indicates if the permission was granted * * * * * * Interfaces[​](https://ionic.io/docs/supported-plugins/email-composer#interfaces-1 "Direct link to heading") ------------------------------------------------------------------------------------------------------------ ### EmailComposerOptions[​](https://ionic.io/docs/supported-plugins/email-composer#emailcomposeroptions "Direct link to heading") **EmailComposerOptions**: ### `` app[​](https://ionic.io/docs/supported-plugins/email-composer#optional-app "Direct link to heading") **● app**: _`string`_ App to send the email with * * * ### `` attachments[​](https://ionic.io/docs/supported-plugins/email-composer#optional-attachments "Direct link to heading") **● attachments**: _`string`\[\]_ File paths or base64 data streams * * * ### `` bcc[​](https://ionic.io/docs/supported-plugins/email-composer#optional-bcc "Direct link to heading") **● bcc**: _`string` | `string`\[\]_ Email address(es) for BCC field * * * ### `` body[​](https://ionic.io/docs/supported-plugins/email-composer#optional-body "Direct link to heading") **● body**: _`string`_ Email body (for HTML, set isHtml to true) * * * ### `` cc[​](https://ionic.io/docs/supported-plugins/email-composer#optional-cc "Direct link to heading") **● cc**: _`string` | `string`\[\]_ Email address(es) for CC field * * * ### `` isHtml[​](https://ionic.io/docs/supported-plugins/email-composer#optional-ishtml "Direct link to heading") **● isHtml**: _`boolean`_ Indicates if the body is HTML or plain text * * * ### `` subject[​](https://ionic.io/docs/supported-plugins/email-composer#optional-subject "Direct link to heading") **● subject**: _`string`_ Subject of the email * * * ### `` to[​](https://ionic.io/docs/supported-plugins/email-composer#optional-to "Direct link to heading") **● to**: _`string` | `string`\[\]_ Email address(es) for To field * * * ### `` type[​](https://ionic.io/docs/supported-plugins/email-composer#optional-type "Direct link to heading") **● type**: _`string`_ Content type of the email (Android only) * * * * * * * [Index](https://ionic.io/docs/supported-plugins/email-composer#index) * [Classes](https://ionic.io/docs/supported-plugins/email-composer#classes) * [Interfaces](https://ionic.io/docs/supported-plugins/email-composer#interfaces) * [Classes](https://ionic.io/docs/supported-plugins/email-composer#classes-1) * [EmailComposer](https://ionic.io/docs/supported-plugins/email-composer#emailcomposer) * [addAlias](https://ionic.io/docs/supported-plugins/email-composer#addalias) * [getClients](https://ionic.io/docs/supported-plugins/email-composer#getclients) * [hasAccount](https://ionic.io/docs/supported-plugins/email-composer#hasaccount) * [hasClient](https://ionic.io/docs/supported-plugins/email-composer#hasclient) * [hasPermission](https://ionic.io/docs/supported-plugins/email-composer#haspermission) * [isAvailable](https://ionic.io/docs/supported-plugins/email-composer#isavailable) * [open](https://ionic.io/docs/supported-plugins/email-composer#open) * [requestPermission](https://ionic.io/docs/supported-plugins/email-composer#requestpermission) * [Interfaces](https://ionic.io/docs/supported-plugins/email-composer#interfaces-1) * [EmailComposerOptions](https://ionic.io/docs/supported-plugins/email-composer#emailcomposeroptions) * [`` app](https://ionic.io/docs/supported-plugins/email-composer#optional-app) * [`` attachments](https://ionic.io/docs/supported-plugins/email-composer#optional-attachments) * [`` bcc](https://ionic.io/docs/supported-plugins/email-composer#optional-bcc) * [`` body](https://ionic.io/docs/supported-plugins/email-composer#optional-body) * [`` cc](https://ionic.io/docs/supported-plugins/email-composer#optional-cc) * [`` isHtml](https://ionic.io/docs/supported-plugins/email-composer#optional-ishtml) * [`` subject](https://ionic.io/docs/supported-plugins/email-composer#optional-subject) * [`` to](https://ionic.io/docs/supported-plugins/email-composer#optional-to) * [`` type](https://ionic.io/docs/supported-plugins/email-composer#optional-type) --- # Contact Us - Appflow [Skip to main content](https://ionic.io/docs/appflow/contact-us#__docusaurus_skipToContent_fallback) --- # ARIA - Accessibility Guide [Skip to main content](https://ionic.io/docs/accessibility/aria#) Accessible Rich Internet Applications (ARIA) is a set of HTML [roles](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles) and [attributes](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes) that define ways to make web content and web applications (especially those developed with JavaScript) more accessible to people with disabilities. ##### note HTML5 already contains many accessibility features that can be surfaced by choosing the correct semantic HTML element over using ARIA. In a similar way Ionic Components provide accessibility features through ARIA. If you choose to create components you are responsible for using ARIA roles and attributes to make your application more accessible. Common Uses[​](https://ionic.io/docs/accessibility/aria#common-uses "Direct link to heading") ---------------------------------------------------------------------------------------------- The best advice is to avoid using Aria attributes and instead use [Semantic Elements](https://ionic.io/docs/accessibility/semantic-elements) . Aria attributes are useful when creating your own components but in general you should minimize the usage in your HTML templates. There are a few common use cases for ARIA roles and attributes that you may come across in an Ionic application: * Using [`aria-hidden`](https://ionic.io/docs/accessibility/aria-hidden) to prevent reading of the name of an `ion-icon` to screen readers (SR) and other assistive technologies (AT). * Using [`aria-label`](https://ionic.io/docs/accessibility/aria-label) to read the action associated with clickable images to screen readers and other assistive technologies. * Using [`role`](https://ionic.io/docs/accessibility/role) of `button` to make elements like `a` behave like a button. * Using [`role`](https://ionic.io/docs/accessibility/role) of `heading` to specify a page title. * Using [`role`](https://ionic.io/docs/accessibility/role) of `list` when using the `ul` element. * Using [`role`](https://ionic.io/docs/accessibility/role) of `list` when using the `ul` element. * Using [`aria-level`](https://ionic.io/docs/accessibility/semantic-elements#headings) to create a level 1 heading for each page. * Using `aria-expanded` to indicate when a component is expanded or collapsed. * [Common Uses](https://ionic.io/docs/accessibility/aria#common-uses) --- # Axe Tools - Accessibility Guide [Skip to main content](https://ionic.io/docs/accessibility/axe#) [Axe Tools](https://www.deque.com/axe/) is a free Chrome / Firebox / Edge extension for testing Accessibility. It also has a paid "pro" option. Axe is often used to test accessibility for Ionic applications whether they are targeted for Native or Web. A [Visual Studio Code Extension](https://marketplace.visualstudio.com/items?itemName=deque-systems.vscode-axe-linter) is also available which will highlight issues as you are editing. ### Installing[​](https://ionic.io/docs/accessibility/axe#installing "Direct link to heading") You can [Install](https://chrome.google.com/webstore/detail/axe-devtools-web-accessib/lhdoppojpmngadmnindnejefpokejbdd) the extension in Google Chrome or Microsoft Edge. ### Usage[​](https://ionic.io/docs/accessibility/axe#usage "Direct link to heading") The Axe DevTools can be accessed by: * Pressing F12 in the browser (or pressing `command` + `option` + `i`) to open Dev Tools * Click the `Axe DevTools` tab When viewing your Ionic application in the browser it will report any accessibility issues as shown below. ![Axe screenshot](https://ionic.io/docs/accessibility/assets/images/axe-usage-a1bbb7bc8c2bf9769a53529c88fe63f8.png) This guide contains examples of many fixes for common accessibility issues that are also found with Axe. Keep in mind that not all issues reported by Axe need to be fixed and you should use tools such as [VoiceOver](https://ionic.io/docs/accessibility/voiceover) and [TalkBack](https://ionic.io/docs/accessibility/talkback) to test accessibility to ensure that the issue you are attempting to fix is a real issue. Axe was also found to identify [57% of accessibility issues](https://www.deque.com/blog/automated-testing-study-identifies-57-percent-of-digital-accessibility-issues/) so it is not an all encompassing solution to accessibility. * [Installing](https://ionic.io/docs/accessibility/axe#installing) * [Usage](https://ionic.io/docs/accessibility/axe#usage) --- # Aria Hidden - Accessibility Guide [Skip to main content](https://ionic.io/docs/accessibility/aria-hidden#) When using `ion-icon` the screen reader will read the name of the icon which is usually not required. #### Before[​](https://ionic.io/docs/accessibility/aria-hidden#before "Direct link to heading") Ionic Copy In the example above the screen reader will announce "logo ionic ionic" as it reads the name of the icon and the label. As the `ion-label` provides sufficient information we can hide the reading of the `ion-icon` name by using the `aria-hidden` attribute. #### After[​](https://ionic.io/docs/accessibility/aria-hidden#after "Direct link to heading") Ionic Copy --- # Contrast - Accessibility Guide [Skip to main content](https://ionic.io/docs/accessibility/contrast#) Create sufficient contrast between foreground and background so text is discernible. Use a tool to check the contrast ratio: * [Color Contrast Checker](https://www.tpgi.com/color-contrast-checker/) * [Contrast Checker](https://webaim.org/resources/contrastchecker/) * In Chrome Dev Tools (`Elements` Tab > `Styles` > `Contrast Ratio`) The recommended contrast ratio is 4.5 to 1 (for WCAG AA level) but you should strive to meet WCAG AAA level (7.0 to 1). Brand colors are a common issue. You can use [this tool](https://abc.useallfive.com/) to check for ADA compliance. For "large" text (size 18 point) the recommended contrast ratio is 3 to 1. Contrast Settings[​](https://ionic.io/docs/accessibility/contrast#contrast-settings "Direct link to heading") -------------------------------------------------------------------------------------------------------------- The option to increase contrast is available in: * **iOS** - Settings > Accessibility > Display & Text Size > Increase Contrast The `prefers-contrast` [CSS media feature](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-contrast) is used to detect if the user has requested that an increase in contrast. You can use this property to programmatically increase contrast. For example: a default Ionic application will have a primary color `--ion-color-primary` of `#3880ff`. When used with a white background this equates to a Contrast Ratio of 3.68 which does not meet the WCAG Level AA recommendation of 4.5, so lets increase it: @media (prefers-contrast: more) { :root { --ion-color-primary: #2561c9; }} Copy This contrast ratio of this color compared with white is 5.78 which is great. Dark Mode[​](https://ionic.io/docs/accessibility/contrast#dark-mode "Direct link to heading") ---------------------------------------------------------------------------------------------- Lets not forget that your app can also be used in dark mode, or can be used together with a color other than white. In our case we also need additional contrast in dark mode: @media (prefers-contrast: more) and (prefers-color-scheme: dark) { body { --ion-color-primary: #7c9bd1; }} Copy For dark mode our color scheme may use lighter colors but be sure to look for exceptions in this: For example an iOS check box in dark mode will have a white check icon. It is always important to test! ##### note If you make your changes for contrast in the `variables.scss` file you'll notice that the default theme css variables are applied to `:root` and the dark theme is applied to `body`. * [Contrast Settings](https://ionic.io/docs/accessibility/contrast#contrast-settings) * [Dark Mode](https://ionic.io/docs/accessibility/contrast#dark-mode) --- # Aria Live Regions - Accessibility Guide [Skip to main content](https://ionic.io/docs/accessibility/aria-live#) When content changes after initial load assistive technology users may not "see" the changes. The `aria-live` attribute allows us to inform the user of these changes. Some good use cases for `aria-live` include form validation and live chat. ### Example[​](https://ionic.io/docs/accessibility/aria-live#example "Direct link to heading") In the below example make sure the page starts with an empty element (in this example `message` is undefined):
{{message}}
Copy The value `polite` will ensure that that anything read will not interrupt what is currently being read. You can change this to `assertive` to immediately read the announcement. During form validation the value of `message` will be changed and the screen reader will announce the value when that happens. * [Example](https://ionic.io/docs/accessibility/aria-live#example) --- # Icon - Accessibility Guide [Skip to main content](https://ionic.io/docs/accessibility/ion-icon#) Quite often `ion-icon`s are used as purely decorative content. Its important that these do not affect the navigation of your app when using assistive technology (as the user will have to navigate past each icon). #### Before[​](https://ionic.io/docs/accessibility/ion-icon#before "Direct link to heading") Information Tools Copy In the sample below i'm adding `aria-hidden="true"` to the `ion-icon` because the icon is only presentational (cannot be pressed). #### After[​](https://ionic.io/docs/accessibility/ion-icon#after "Direct link to heading") Information Tools Copy --- # Custom Components - Accessibility Guide [Skip to main content](https://ionic.io/docs/accessibility/custom-components#) If you are creating a custom component, it is useful to follow a set of conventions. A standard set of these can be found in the [ARIA Authoring Practices Guide](https://www.w3.org/WAI/ARIA/apg/patterns/) . --- # Lighthouse - Accessibility Guide [Skip to main content](https://ionic.io/docs/accessibility/lighthouse#) Lighthouse is a tool built into Chrome's DevTools that generates scopes for a page in areas than include Accessibility. * Open Chrome (or Microsoft Edge) * Press `F12` (or choose `Settings` -> `Developer Tools`) * Click the `Lighthouse` tab * Click `Analyze page load` ### Summary[​](https://ionic.io/docs/accessibility/lighthouse#summary "Direct link to heading") A summary of your Accessibility score and opportunities for improvement will be shown. ![Lighthouse screenshot](https://ionic.io/docs/accessibility/assets/images/lighthouse-daff17f973531e9972db2b9e6658d22c.png) * [Summary](https://ionic.io/docs/accessibility/lighthouse#summary) --- # Overview - Accessibility Guide [Skip to main content](https://ionic.io/docs/accessibility/guidelines#) Consider the following guidelines when improving Accessibility in your application. Remember that anything a mouse user (or mobile device user) can do, keyboard and assistive technology users must also be able to do. ##### note There aren't any shortcuts to making your app Accessible. Using an [overlay widget](https://overlayfactsheet.com/) may seem like a quick fix but in practice (and legally) you need to do the work in your application. Semantic Elements[​](https://ionic.io/docs/accessibility/guidelines#semantic-elements "Direct link to heading") ---------------------------------------------------------------------------------------------------------------- Use HTML elements that have semantic meaning rather than `div`: * [Headers](https://ionic.io/docs/accessibility/semantic-elements#headings) * [Landmarks](https://ionic.io/docs/accessibility/semantic-elements#landmarks) * [Other Elements](https://ionic.io/docs/accessibility/semantic-elements#other-elements) Design Considerations[​](https://ionic.io/docs/accessibility/guidelines#design-considerations "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------ * [Layouts should reflow](https://ionic.io/docs/accessibility/guidelines#reflow) * [Accommodate for zooming](https://ionic.io/docs/accessibility/allow-zooming) and variable text sizes * Touch targets should be appropriately sized for human fingers * [Allowing for users to opt-in to motion and animation](https://ionic.io/docs/accessibility/motion) Text Alternatives[​](https://ionic.io/docs/accessibility/guidelines#text-alternatives "Direct link to heading") ---------------------------------------------------------------------------------------------------------------- Graphics and non-text content [needs to be described](https://ionic.io/docs/accessibility/alt-text) so it can be used in formats people need like large print, speech. * Images - `Tall ice cream in a cone`. * Use an empty alt attribute if the image is decorative. * Video - Provide captions, audio descriptions and sign language. Forms[​](https://ionic.io/docs/accessibility/guidelines#forms "Direct link to heading") ---------------------------------------------------------------------------------------- * Often forgotten is adding labels to inputs and text areas (placeholders are not enough as they disappear when a value is present). * If you must hide labels for inputs then you can use an `aria-label` on the input * Semantic structure includes `
`, `
`, `` Reflow[​](https://ionic.io/docs/accessibility/guidelines#reflow "Direct link to heading") ------------------------------------------------------------------------------------------ Your page should reflow (or be responsive) when zoomed requiring that a user only need to scroll in one dimension. This is a [WCAG Level AA success criteria](https://www.w3.org/WAI/WCAG21/Understanding/reflow.html) . You should use [CSS media queries](https://developer.mozilla.org/en-US/docs/Web/CSS/Media_Queries/Using_media_queries) to improve your layouts. Custom Components[​](https://ionic.io/docs/accessibility/guidelines#custom-components "Direct link to heading") ---------------------------------------------------------------------------------------------------------------- Creating a custom component will require you to consider accessibility that would be otherwise handled for you by Ionic components or HTML5 form elements. Interactivity[​](https://ionic.io/docs/accessibility/guidelines#interactivity "Direct link to heading") -------------------------------------------------------------------------------------------------------- Anywhere a mouse user can navigate to should be accessible via Keyboard or screen reader. * An `a` tag needs to have an `href` for it to be accessible via a keyboard * Avoid swipe actions (which will interfere with Screen Reader gestures) or provide an alternative to swiping. Common Issues[​](https://ionic.io/docs/accessibility/guidelines#common-issues "Direct link to heading") -------------------------------------------------------------------------------------------------------- Avoid the following common issues: * Icon buttons without text labels. * 3rd party content from an iFrame is your responsibility for accessibility. Eg questionnaires, chat, shopping carts, video players. * Auto-playing video. * Motion sensitivity. * Non-obvious Interactive controls (eg that require hovering,focusing or touching). * Invisible Keyboard focus indicators. * Touch targets that are less that 24x24 pixels. * Interfaces that expand to show additional controls * Content shown on hover or focus that cannot be dismissed * [Semantic Elements](https://ionic.io/docs/accessibility/guidelines#semantic-elements) * [Design Considerations](https://ionic.io/docs/accessibility/guidelines#design-considerations) * [Text Alternatives](https://ionic.io/docs/accessibility/guidelines#text-alternatives) * [Forms](https://ionic.io/docs/accessibility/guidelines#forms) * [Reflow](https://ionic.io/docs/accessibility/guidelines#reflow) * [Custom Components](https://ionic.io/docs/accessibility/guidelines#custom-components) * [Interactivity](https://ionic.io/docs/accessibility/guidelines#interactivity) * [Common Issues](https://ionic.io/docs/accessibility/guidelines#common-issues) --- # Item - Accessibility Guide [Skip to main content](https://ionic.io/docs/accessibility/ion-item#) Ionic components are smart about accessibility particularly when it comes to associating labels to the associated control. So, consider using a container control like `ion-item` to contain Ionic components. #### Before[​](https://ionic.io/docs/accessibility/ion-item#before "Direct link to heading")
Ice Cream
Copy The above example will read "Ice Cream" as a label, and if you swipe to the next element it will go to the checkbox. With a screen reader it is not obvious that the "Ice Cream" label is associated with the checkbox. #### After[​](https://ionic.io/docs/accessibility/ion-item#after "Direct link to heading") Ice Cream Copy --- # Build Stacks - Appflow [Skip to main content](https://ionic.io/docs/appflow/build-stacks#__docusaurus_skipToContent_fallback) On this page In Appflow, build stacks represent the set of software used to build an app on a given platform (web, iOS, Android). This includes the version of npm, Cordova, Ionic, Xcode, and the OS it is all installed on. In general, the latest build stack is the recommended choice for most apps. Other build stacks are available for scenarios such as when a specific version of a build tool is required (i.e., an older version of Xcode or the Android build tools). Build stacks are available for use with all Appflow plans. After a new build stack becomes available, older build stacks for that platform will be retired approximately two years from their creation date. Retiring build stacks will be labeled with the date they'll no longer be available within the Appflow "Create new build" page and customers will be notified as well. Below are the versions used in Appflow for each build type. Active Stack Versions[​](https://ionic.io/docs/appflow/build-stacks#active-stack-versions "Direct link to Active Stack Versions") ---------------------------------------------------------------------------------------------------------------------------------- ### Active macOS Versions (Used for iOS builds)[​](https://ionic.io/docs/appflow/build-stacks#active-macos-versions-used-for-ios-builds "Direct link to Active macOS Versions (Used for iOS builds)") | Software | macOS - 2023.09 - Apple silicon | macOS - 2023.10 - Apple silicon | macOS - 2024.04 - Apple silicon | macOS - 2024.10 - Apple silicon | macOS - 2024.12 - Apple silicon | macOS - 2025.06 - Apple silicon | | --- | --- | --- | --- | --- | --- | --- | | Cordova CLI | 12.0.0 | 12.0.0 | 12.0.0 | 12.0.0 | 12.0.0 | 12.0.0 | | Ionic CLI | 7.1.1 | 7.1.1 | 7.2.0 | 7.2.0 | 7.2.0 | 7.2.1 | | Node.js | 18.18.0 | 20.9.0 | 20.12.2 | 20.18.0 | 20.18.1 | 20.19.3 | | Node.js versions | 16.20.0 / 18.18.0 | 18.18.2 / 20.9.0 | 18.20.2 / 20.12.2 | 18.20.4 / 20.18.0 / 22.9.0 | 18.20.5 / 20.18.1 / 22.11.0 | 18.20.8 / 20.19.3 / 22.17.0 | | npm | 9.8.1 | 10.1.0 | 10.5.1 | 10.8.0 | 10.8.0 | 10.8.2 | | Yarn | 1.22.19[1](https://ionic.io/docs/appflow/build-stacks#user-content-fn-1) | 1.22.19[1](https://ionic.io/docs/appflow/build-stacks#user-content-fn-1) | 1.22.19[1](https://ionic.io/docs/appflow/build-stacks#user-content-fn-1) | 1.22.19[1](https://ionic.io/docs/appflow/build-stacks#user-content-fn-1) | 1.22.19[1](https://ionic.io/docs/appflow/build-stacks#user-content-fn-1) | 1.22.19[1](https://ionic.io/docs/appflow/build-stacks#user-content-fn-1) | | Python | 3 | 3 | 3 | 3 | 3 | 3 | | Ruby | 3.1.4 | 3.1.4 | 3.3.0 | 3.3.5 | 3.3.6 | 3.4.1 | | macOS | 13.6 | 14.0 | 14.4.1 | 14.6.1 | 14.6.1 | 15.4 | | Carthage | 0.39.0 | 0.39.1 | 0.39.1 | 0.40.0 | 0.40.0 | 0.40.0 | | CocoaPods | 1.13.0 | 1.13.0 | 1.15.2 | 1.15.2 | 1.15.2 | 1.16.2[2](https://ionic.io/docs/appflow/build-stacks#user-content-fn-2) | | Xcode | 15 | 15.0.1 | 15.3 | 16.0 | 16.1 | 16.4 | ### Active Linux Versions (Used for Android and Web builds)[​](https://ionic.io/docs/appflow/build-stacks#active-linux-versions-used-for-android-and-web-builds "Direct link to Active Linux Versions (Used for Android and Web builds)") | Software | Linux - 2023.10 | Linux - 2024.06 | Linux - 2024.10 | Linux - 2025.01 | Linux - 2025.06 | | --- | --- | --- | --- | --- | --- | | Cordova CLI | 12.0.0 | 12.0.0 | 12.0.0 | 12.0.0 | 12.0.0 | | Ionic CLI | 7.1.1 | 7.2.0 | 7.2.0 | 7.2.1 | 7.2.1 | | Node.js | 20.9.0 | 20.12.2 | 20.17.0 | 20.18.2 | 20.19.3 | | Node.js versions | 18.18.2 / 20.9.0 | 18.20.2 / 20.12.2 | 18.20.4 / 20.17.0 / 22.9.0 | 18.20.6 / 20.18.2 / 22.13.1 | 18.20.8 / 20.19.3 / 22.17.0 | | npm | 10.1.1 | 10.5.1 | 10.8.3 | 10.9.0 | 10.9.0 | | Yarn | 1.22.19[3](https://ionic.io/docs/appflow/build-stacks#user-content-fn-3) | 1.22.22[3](https://ionic.io/docs/appflow/build-stacks#user-content-fn-3) | 1.22.22[3](https://ionic.io/docs/appflow/build-stacks#user-content-fn-3) | 1.22.22[3](https://ionic.io/docs/appflow/build-stacks#user-content-fn-3) | 1.22.22[3](https://ionic.io/docs/appflow/build-stacks#user-content-fn-3) | | Python | 3 | 3 | 3 | 3 | 3 | | Ruby | 3.2.2 | 3.2.2 | 3.2.2 | 3.3.7 | 3.3.7 | | Debian | 11.6 | 11.6 | 11.6 | 12.9 | 12.9 | | Gradle | 8.4 | 8.4 | 8.10.2 | 8.10.2 | 8.14.2 | | OpenJDK | 1.8.0\_332 / 11.0.18 / 17.0.6 | 1.8.0\_332 / 11.0.23 / 17.0.11 | 1.8.0\_332 / 11.0.23 / 17.0.11 | 1.8.0\_432 / 11.0.25 / 17.0.13 / 21.0.5 | 1.8.0\_432 / 11.0.25 / 17.0.13 / 21.0.5 | | Android SDK | 27-34 | 27-34 | 27-35 | 27-35 | 27-36 | Footnotes[​](https://ionic.io/docs/appflow/build-stacks#footnote-label "Direct link to Footnotes") --------------------------------------------------------------------------------------------------- 1. Yarn 1.22.19 is the default version. Other versions are supported via [corepack](https://nodejs.org/api/corepack.html) . [↩](https://ionic.io/docs/appflow/build-stacks#user-content-fnref-1) [↩2](https://ionic.io/docs/appflow/build-stacks#user-content-fnref-1-2) [↩3](https://ionic.io/docs/appflow/build-stacks#user-content-fnref-1-3) [↩4](https://ionic.io/docs/appflow/build-stacks#user-content-fnref-1-4) [↩5](https://ionic.io/docs/appflow/build-stacks#user-content-fnref-1-5) [↩6](https://ionic.io/docs/appflow/build-stacks#user-content-fnref-1-6) 2. Cocoapods 1.16.2 will have breaking changes. Make sure to update cocoapods locally to at least that version and re-run `pod install`. [↩](https://ionic.io/docs/appflow/build-stacks#user-content-fnref-2) 3. Yarn 1.22.19 is the default version. Other versions are supported via [corepack](https://nodejs.org/api/corepack.html) . [↩](https://ionic.io/docs/appflow/build-stacks#user-content-fnref-3) [↩2](https://ionic.io/docs/appflow/build-stacks#user-content-fnref-3-2) [↩3](https://ionic.io/docs/appflow/build-stacks#user-content-fnref-3-3) [↩4](https://ionic.io/docs/appflow/build-stacks#user-content-fnref-3-4) [↩5](https://ionic.io/docs/appflow/build-stacks#user-content-fnref-3-5) Contents -------- * [Active Stack Versions](https://ionic.io/docs/appflow/build-stacks#active-stack-versions) * [Active macOS Versions (Used for iOS builds)](https://ionic.io/docs/appflow/build-stacks#active-macos-versions-used-for-ios-builds) * [Active Linux Versions (Used for Android and Web builds)](https://ionic.io/docs/appflow/build-stacks#active-linux-versions-used-for-android-and-web-builds) --- # Introduction - Accessibility Guide [Skip to main content](https://ionic.io/docs/accessibility#) Accessibility means that websites, tools, and technologies are designed and developed so that people with disabilities can use them. More specifically, people can: perceive, understand, navigate, interact with, and contribute to the Web. Accessibility is not a checklist and is not a feature. Accessibility is a part of User Experience, product design, development, and testing that is constantly iterating over time. Accessibility is a process. Quick Start[​](https://ionic.io/docs/accessibility#quick-start "Direct link to heading") ----------------------------------------------------------------------------------------- Get started in understanding Accessibility by opening your app on a mobile device then: 1. Turn on the screen reader ([VoiceOver](https://ionic.io/docs/accessibility/voiceover) for iOS, [TalkBack](https://ionic.io/docs/accessibility/talkback) for Android). 2. Familiarize yourself with navigating around using swipe gestures to empathize with your users. 3. If you are building a web app then attempt to navigate by keyboard (tab to move to the next item). When you "feel" a poor accessibility experience you will want to use this guide to improve it. Why Worry About Accessibility?[​](https://ionic.io/docs/accessibility#why-worry-about-accessibility "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------------ The impact you can have by making your application accessible: * 15% of the worlds population have a recognized disability ([26%](https://www.cdc.gov/ncbddd/disabilityandhealth/disability.html) in the US). * Civil Rights Legislation (Americans with Disabilities Act) prohibits discrimination against people with disabilities. * Caring about accessibility demonstrates good ethics and morals, which improves your public image. * Accessibility improves SEO, which makes your apps more findable. * There were 4055 ADA (Americans Disabilities Act) related lawsuits in 2021. * Practices that improve accessibility also make your site more usable by other groups, such as those on low network speeds or people that do not have the latest mobile devices. ##### note Learn about [Accessibility Laws and standards around the globe](https://www.lflegal.com/2013/05/gaad-legal/) Designing for Accessibility[​](https://ionic.io/docs/accessibility#designing-for-accessibility "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------- Considering Accessibility during design allows you to make architectural choices that will improve accessibility. Making these choices upfront reduces the number of accessibility issues that need to be fixed afterwards and avoids accessibility issues that cannot be fixed without a costly redesign. Accessibility should be part of: * Requirements gathering and planning * UX and content strategy * Design * Development * QA ##### note Work with a company like [Fable Tech Labs](https://makeitfable.com/) or [Access Works](https://access-works.com/) who can provide resources to help test your application for Accessibility. --- # Modals - Accessibility Guide [Skip to main content](https://ionic.io/docs/accessibility/ion-modal#) [Axe](https://www.deque.com/axe/) will throw a critical error: "_ARIA dialog and alertdialog nodes should have an accessible name_". The `ion-modal` has a role of `dialog` and needs an accessible name to describe it. #### Before[​](https://ionic.io/docs/accessibility/ion-modal#before "Direct link to heading") Welcome ... Copy In the above example the logical choice for an accessible name would be the `ion-title` of "Welcome". We can associate the modal with this by setting the `aria-labelled` attribute and giving the `ion-title` an `id`: #### After[​](https://ionic.io/docs/accessibility/ion-modal#after "Direct link to heading") Welcome ... Copy ##### note This technique can be used with Ionic Framework v6.2.4 and above. --- # Role - Accessibility Guide [Skip to main content](https://ionic.io/docs/accessibility/role#) Elements that behave as buttons but are built using other tags such as span, div, a or others, should include a "role" attribute that equals to "button". #### Before[​](https://ionic.io/docs/accessibility/role#before "Direct link to heading") Copy #### After[​](https://ionic.io/docs/accessibility/role#after "Direct link to heading") Copy A similar problem with images that act like buttons: Copy This component is not accessible as it cannot receive keyboard focus when tabbing on the screen. So a better alternative is to wrap in an html button: Copy --- # Radio Groups - Accessibility Guide [Skip to main content](https://ionic.io/docs/accessibility/ion-radio-group#) [Axe](https://www.deque.com/axe/) will throw a critical error: "_Ensures elements with an ARIA role that require child roles contain them_". The `ion-radio-group` has a role of `radio` but its `ion-radio` items need to be associated with the `ion-radio-group`. ### Ionic Framework v7+[​](https://ionic.io/docs/accessibility/ion-radio-group#ionic-framework-v7 "Direct link to heading") #### Before[​](https://ionic.io/docs/accessibility/ion-radio-group#before "Direct link to heading") Toppings Sprinkles Marshmallows Cherries Copy #### After[​](https://ionic.io/docs/accessibility/ion-radio-group#after "Direct link to heading") Toppings Sprinkles Marshmallows Cherries Copy ### Ionic Framework v6[​](https://ionic.io/docs/accessibility/ion-radio-group#ionic-framework-v6 "Direct link to heading") Version 6 of the framework is a little harder to fix accessibility of `ion-radio-group`. To associate the group to the radio buttons we set the `aria-owns` property to the list of `ion-radio` elements. We also need to provide a parent for the list of `ion-item` elements by adding an `ion-list`. #### After[​](https://ionic.io/docs/accessibility/ion-radio-group#after-1 "Direct link to heading") Toppings Sprinkles Marshmallows Cherries Copy * [Ionic Framework v7+](https://ionic.io/docs/accessibility/ion-radio-group#ionic-framework-v7) * [Ionic Framework v6](https://ionic.io/docs/accessibility/ion-radio-group#ionic-framework-v6) --- # Contacts - Supported Plugins [Skip to main content](https://ionic.io/docs/supported-plugins/contacts#) ##### EOL Notice Contacts will reach its end-of-life on July 1, 2024, and will no longer receive updates or support. Please see [Support Policy](https://ionic.io/docs/supported-plugins/support-policy) for additional information. The Contacts plugin provides access to read, write, or select device contacts. Installation[​](https://ionic.io/docs/supported-plugins/contacts#installation "Direct link to heading") -------------------------------------------------------------------------------------------------------- If you have not already setup Ionic Enterprise in your app, [follow the one-time setup steps](https://ionic.io/docs/supported-plugins/setup) . Next, install the plugin: * Capacitor * Cordova npm install @ionic-enterprise/contactsnpx cap sync Copy ionic cordova plugin add @ionic-enterprise/contacts Copy Usage[​](https://ionic.io/docs/supported-plugins/contacts#usage "Direct link to heading") ------------------------------------------------------------------------------------------ The Contacts plugin ship with a native Angular & es2015+/Typescript wrappers as well as being available on window. // Angularimport { Contacts } from '@ionic-enterprise/contacts/ngx';import { Contact, ContactName, ContactField } from '@ionic-enterprise/contacts';...constructor(private contacts: Contacts) { }async createContact() { let contact = this.contacts.create(); contact.name = new ContactName(null, 'Smith', 'John'); contact.phoneNumbers = [new ContactField('mobile', '6471234567')]; contact.save().then( () => console.log('Contact saved!', contact), (error: any) => console.error('Error saving contact.', error) );}...// ES2015+/TypeScriptimport { Contacts, Contact, ContactName, ContactField } from '@ionic-enterprise/contacts';let contact = Contacts.create();contact.name = new ContactName(null, 'Smith', 'John');contact.phoneNumbers = [new ContactField('mobile', '6471234567')];contact.save().then( () => console.log('Contact saved!', contact), (error: any) => console.error('Error saving contact.', error));...// Vanilla JSdocument.addEventListener('deviceready', () => { let contact = IonicContacts.create(); contact.name = {familyName: 'Smith', givenName: 'John'}; contact.phoneNumbers = {type: 'mobile', value: '6471234567'}; contact.save().then( () => console.log('Contact saved!', contact), (error) => console.error('Error saving contact.', error) );}); Copy Index[​](https://ionic.io/docs/supported-plugins/contacts#index "Direct link to heading") ------------------------------------------------------------------------------------------ ### Classes[​](https://ionic.io/docs/supported-plugins/contacts#classes "Direct link to heading") * [Contact](https://ionic.io/docs/supported-plugins/contacts#contact) * [ContactAddress](https://ionic.io/docs/supported-plugins/contacts#contactaddress) * [ContactError](https://ionic.io/docs/supported-plugins/contacts#contacterror) * [ContactField](https://ionic.io/docs/supported-plugins/contacts#contactfield) * [ContactFindOptions](https://ionic.io/docs/supported-plugins/contacts#contactfindoptions) * [ContactName](https://ionic.io/docs/supported-plugins/contacts#contactname) * [ContactOrganization](https://ionic.io/docs/supported-plugins/contacts#contactorganization) * [Contacts](https://ionic.io/docs/supported-plugins/contacts#contacts) ### Type aliases[​](https://ionic.io/docs/supported-plugins/contacts#type-aliases "Direct link to heading") * [ContactFieldType](https://ionic.io/docs/supported-plugins/contacts#contactfieldtype) ### Type aliases[​](https://ionic.io/docs/supported-plugins/contacts#type-aliases-1 "Direct link to heading") ### ContactFieldType[​](https://ionic.io/docs/supported-plugins/contacts#contactfieldtype "Direct link to heading") Ƭ **ContactFieldType**: _"_" | "addresses" | "birthday" | "categories" | "country" | "department" | "displayName" | "emails" | "name.familyName" | "name.formatted" | "name.givenName" | "name.honorificPrefix" | "name.honorificSuffix" | "id" | "ims" | "locality" | "name.middleName" | "name" | "nickname" | "note" | "organizations" | "phoneNumbers" | "photos" | "postalCode" | "region" | "streetAddress" | "title" | "urls"\* Support for searching varies between platforms. iOS only supports the following types for a text search: * 'name' * 'emails' * 'phoneNumbers' In addition, the wildcard '\*' character is required to return all contacts. Android supports all defined fields. ### Contact[​](https://ionic.io/docs/supported-plugins/contacts#contact "Direct link to heading") Contains information about a single contact. ### Constructors[​](https://ionic.io/docs/supported-plugins/contacts#constructors "Direct link to heading") ### constructor[​](https://ionic.io/docs/supported-plugins/contacts#constructor "Direct link to heading") + **new Contact**(`id?`: undefined | string, `displayName?`: undefined | string, `name?`: [ContactName](https://ionic.io/docs/supported-plugins/contacts#contactname) , `nickname?`: undefined | string, `phoneNumbers?`: [ContactField](https://ionic.io/docs/supported-plugins/contacts#contactfield) \[\], `emails?`: [ContactField](https://ionic.io/docs/supported-plugins/contacts#contactfield) \[\], `addresses?`: [ContactAddress](https://ionic.io/docs/supported-plugins/contacts#contactaddress) \[\], `ims?`: [ContactField](https://ionic.io/docs/supported-plugins/contacts#contactfield) \[\], `organizations?`: [ContactOrganization](https://ionic.io/docs/supported-plugins/contacts#contactorganization) \[\], `birthday?`: Date | string | null, `note?`: undefined | string, `photos?`: [ContactField](https://ionic.io/docs/supported-plugins/contacts#contactfield) \[\], `categories?`: [ContactField](https://ionic.io/docs/supported-plugins/contacts#contactfield) \[\], `urls?`: [ContactField](https://ionic.io/docs/supported-plugins/contacts#contactfield) \[\]): _[Contact](https://ionic.io/docs/supported-plugins/contacts#contact) _ **Parameters:** | Name | Type | | --- | --- | | `id?` | undefined \| string | | `displayName?` | undefined \| string | | `name?` | [ContactName](https://ionic.io/docs/supported-plugins/contacts#contactname) | | `nickname?` | undefined \| string | | `phoneNumbers?` | [ContactField](https://ionic.io/docs/supported-plugins/contacts#contactfield)
\[\] | | `emails?` | [ContactField](https://ionic.io/docs/supported-plugins/contacts#contactfield)
\[\] | | `addresses?` | [ContactAddress](https://ionic.io/docs/supported-plugins/contacts#contactaddress)
\[\] | | `ims?` | [ContactField](https://ionic.io/docs/supported-plugins/contacts#contactfield)
\[\] | | `organizations?` | [ContactOrganization](https://ionic.io/docs/supported-plugins/contacts#contactorganization)
\[\] | | `birthday?` | Date \| string \| null | | `note?` | undefined \| string | | `photos?` | [ContactField](https://ionic.io/docs/supported-plugins/contacts#contactfield)
\[\] | | `categories?` | [ContactField](https://ionic.io/docs/supported-plugins/contacts#contactfield)
\[\] | | `urls?` | [ContactField](https://ionic.io/docs/supported-plugins/contacts#contactfield)
\[\] | **Returns:** _[Contact](https://ionic.io/docs/supported-plugins/contacts#contact) _ ### Properties[​](https://ionic.io/docs/supported-plugins/contacts#properties "Direct link to heading") ### `Optional` addresses[​](https://ionic.io/docs/supported-plugins/contacts#optional-addresses "Direct link to heading") • **addresses**? : _[ContactAddress](https://ionic.io/docs/supported-plugins/contacts#contactaddress) \[\] | null_ An array of all the contact's addresses. * * * ### `Optional` birthday[​](https://ionic.io/docs/supported-plugins/contacts#optional-birthday "Direct link to heading") • **birthday**? : _Date | string | null_ The birthday of the contact. * * * ### `Optional` categories[​](https://ionic.io/docs/supported-plugins/contacts#optional-categories "Direct link to heading") • **categories**? : _[ContactField](https://ionic.io/docs/supported-plugins/contacts#contactfield) \[\] | null_ An array of all the user-defined categories associated with the contact. * * * ### `Optional` displayName[​](https://ionic.io/docs/supported-plugins/contacts#optional-displayname "Direct link to heading") • **displayName**? : _string | null_ The name of this Contact, suitable for display to end users. * * * ### `Optional` emails[​](https://ionic.io/docs/supported-plugins/contacts#optional-emails "Direct link to heading") • **emails**? : _[ContactField](https://ionic.io/docs/supported-plugins/contacts#contactfield) \[\] | null_ An array of all the contact's email addresses. * * * ### `Optional` id[​](https://ionic.io/docs/supported-plugins/contacts#optional-id "Direct link to heading") • **id**? : _string | null_ A globally unique identifier. * * * ### `Optional` ims[​](https://ionic.io/docs/supported-plugins/contacts#optional-ims "Direct link to heading") • **ims**? : _[ContactField](https://ionic.io/docs/supported-plugins/contacts#contactfield) \[\] | null_ An array of all the contact's IM addresses. * * * ### `Optional` name[​](https://ionic.io/docs/supported-plugins/contacts#optional-name "Direct link to heading") • **name**? : _[ContactName](https://ionic.io/docs/supported-plugins/contacts#contactname) | null_ An object containing all components of a persons name. * * * ### `Optional` nickname[​](https://ionic.io/docs/supported-plugins/contacts#optional-nickname "Direct link to heading") • **nickname**? : _string | null_ A casual name by which to address the contact. * * * ### `Optional` note[​](https://ionic.io/docs/supported-plugins/contacts#optional-note "Direct link to heading") • **note**? : _string | null_ A note about the contact on Android. * * * ### `Optional` organizations[​](https://ionic.io/docs/supported-plugins/contacts#optional-organizations "Direct link to heading") • **organizations**? : _[ContactOrganization](https://ionic.io/docs/supported-plugins/contacts#contactorganization) \[\] | null_ An array of all the contact's organizations. * * * ### `Optional` phoneNumbers[​](https://ionic.io/docs/supported-plugins/contacts#optional-phonenumbers "Direct link to heading") • **phoneNumbers**? : _[ContactField](https://ionic.io/docs/supported-plugins/contacts#contactfield) \[\] | null_ An array of all the contact's phone numbers. * * * ### `Optional` photos[​](https://ionic.io/docs/supported-plugins/contacts#optional-photos "Direct link to heading") • **photos**? : _[ContactField](https://ionic.io/docs/supported-plugins/contacts#contactfield) \[\] | null_ An array of the contact's photos. * * * ### `Optional` rawId[​](https://ionic.io/docs/supported-plugins/contacts#optional-rawid "Direct link to heading") • **rawId**? : _string | null_ A globally unique identifier on Android. * * * ### `Optional` urls[​](https://ionic.io/docs/supported-plugins/contacts#optional-urls "Direct link to heading") • **urls**? : _[ContactField](https://ionic.io/docs/supported-plugins/contacts#contactfield) \[\] | null_ An array of web pages associated with the contact. ### Methods[​](https://ionic.io/docs/supported-plugins/contacts#methods "Direct link to heading") ### clone[​](https://ionic.io/docs/supported-plugins/contacts#clone "Direct link to heading") ▸ **clone**(): _[Contact](https://ionic.io/docs/supported-plugins/contacts#contact) _ Creates a deep copy of this Contact. With the contact ID set to null. **Returns:** _[Contact](https://ionic.io/docs/supported-plugins/contacts#contact) _ copy of this Contact * * * ### display[​](https://ionic.io/docs/supported-plugins/contacts#display "Direct link to heading") ▸ **display**(`allowEdit?`: undefined | false | true): _Promise‹any›_ iOS only Display a contact in the native Contact Picker UI **Parameters:** | Name | Type | Description | | --- | --- | --- | | `allowEdit?` | undefined \| false \| true | true display the contact and allow editing it false (default) display contact without editing | **Returns:** _Promise‹any›_ * * * ### remove[​](https://ionic.io/docs/supported-plugins/contacts#remove "Direct link to heading") ▸ **remove**(): _Promise‹any›_ Removes contact from device storage. **Returns:** _Promise‹any›_ * * * ### save[​](https://ionic.io/docs/supported-plugins/contacts#save "Direct link to heading") ▸ **save**(): _Promise‹any›_ Persists contact to device storage. **Returns:** _Promise‹any›_ ### Contactaddress[​](https://ionic.io/docs/supported-plugins/contacts#contactaddress "Direct link to heading") Contact address. ### Constructors[​](https://ionic.io/docs/supported-plugins/contacts#constructors-1 "Direct link to heading") ### constructor[​](https://ionic.io/docs/supported-plugins/contacts#constructor-1 "Direct link to heading") + **new ContactAddress**(`pref?`: undefined | false | true, `type?`: undefined | string, `formatted?`: undefined | string, `streetAddress?`: undefined | string, `locality?`: undefined | string, `region?`: undefined | string, `postalCode?`: undefined | string, `country?`: undefined | string): _[ContactAddress](https://ionic.io/docs/supported-plugins/contacts#contactaddress) _ **Parameters:** | Name | Type | | --- | --- | | `pref?` | undefined \| false \| true | | `type?` | undefined \| string | | `formatted?` | undefined \| string | | `streetAddress?` | undefined \| string | | `locality?` | undefined \| string | | `region?` | undefined \| string | | `postalCode?` | undefined \| string | | `country?` | undefined \| string | **Returns:** _[ContactAddress](https://ionic.io/docs/supported-plugins/contacts#contactaddress) _ ### Properties[​](https://ionic.io/docs/supported-plugins/contacts#properties-1 "Direct link to heading") ### `Optional` country[​](https://ionic.io/docs/supported-plugins/contacts#optional-country "Direct link to heading") • **country**? : _string | null_ The country name. * * * ### `Optional` formatted[​](https://ionic.io/docs/supported-plugins/contacts#optional-formatted "Direct link to heading") • **formatted**? : _string | null_ The full address formatted for display. * * * ### `Optional` id[​](https://ionic.io/docs/supported-plugins/contacts#optional-id-1 "Direct link to heading") • **id**? : _string | null_ unique identifier, should only be set by native code * * * ### `Optional` locality[​](https://ionic.io/docs/supported-plugins/contacts#optional-locality "Direct link to heading") • **locality**? : _string | null_ The city or locality. * * * ### `Optional` postalCode[​](https://ionic.io/docs/supported-plugins/contacts#optional-postalcode "Direct link to heading") • **postalCode**? : _string | null_ The zip code or postal code. * * * ### `Optional` pref[​](https://ionic.io/docs/supported-plugins/contacts#optional-pref "Direct link to heading") • **pref**? : _undefined | false | true_ Set to true if this ContactAddress contains the user's preferred value. * * * ### `Optional` region[​](https://ionic.io/docs/supported-plugins/contacts#optional-region "Direct link to heading") • **region**? : _string | null_ The state or region. * * * ### `Optional` streetAddress[​](https://ionic.io/docs/supported-plugins/contacts#optional-streetaddress "Direct link to heading") • **streetAddress**? : _string | null_ The full street address. * * * ### `Optional` type[​](https://ionic.io/docs/supported-plugins/contacts#optional-type "Direct link to heading") • **type**? : _string | null_ A string indicating what type of field this is, home for example. ### Contacterror[​](https://ionic.io/docs/supported-plugins/contacts#contacterror "Direct link to heading") ContactError. An error code assigned by an implementation when an error has occurred ### Constructors[​](https://ionic.io/docs/supported-plugins/contacts#constructors-2 "Direct link to heading") ### constructor[​](https://ionic.io/docs/supported-plugins/contacts#constructor-2 "Direct link to heading") + **new ContactError**(`code`: number): _[ContactError](https://ionic.io/docs/supported-plugins/contacts#contacterror) _ **Parameters:** | Name | Type | | --- | --- | | `code` | number | **Returns:** _[ContactError](https://ionic.io/docs/supported-plugins/contacts#contacterror) _ ### Properties[​](https://ionic.io/docs/supported-plugins/contacts#properties-2 "Direct link to heading") ### code[​](https://ionic.io/docs/supported-plugins/contacts#code "Direct link to heading") • **code**: _number_ Error code * * * ### `Optional` message[​](https://ionic.io/docs/supported-plugins/contacts#optional-message "Direct link to heading") • **message**? : _undefined | string_ Error message * * * ### `Static` INVALID\_ARGUMENT\_ERROR[​](https://ionic.io/docs/supported-plugins/contacts#static-invalid_argument_error "Direct link to heading") ▪ **INVALID\_ARGUMENT\_ERROR**: _number_ = 1 * * * ### `Static` IO\_ERROR[​](https://ionic.io/docs/supported-plugins/contacts#static-io_error "Direct link to heading") ▪ **IO\_ERROR**: _number_ = 4 * * * ### `Static` NOT\_SUPPORTED\_ERROR[​](https://ionic.io/docs/supported-plugins/contacts#static-not_supported_error "Direct link to heading") ▪ **NOT\_SUPPORTED\_ERROR**: _number_ = 5 * * * ### `Static` OPERATION\_CANCELLED\_ERROR[​](https://ionic.io/docs/supported-plugins/contacts#static-operation_cancelled_error "Direct link to heading") ▪ **OPERATION\_CANCELLED\_ERROR**: _number_ = 6 * * * ### `Static` PENDING\_OPERATION\_ERROR[​](https://ionic.io/docs/supported-plugins/contacts#static-pending_operation_error "Direct link to heading") ▪ **PENDING\_OPERATION\_ERROR**: _number_ = 3 * * * ### `Static` PERMISSION\_DENIED\_ERROR[​](https://ionic.io/docs/supported-plugins/contacts#static-permission_denied_error "Direct link to heading") ▪ **PERMISSION\_DENIED\_ERROR**: _number_ = 20 * * * ### `Static` TIMEOUT\_ERROR[​](https://ionic.io/docs/supported-plugins/contacts#static-timeout_error "Direct link to heading") ▪ **TIMEOUT\_ERROR**: _number_ = 2 * * * ### `Static` UNKNOWN\_ERROR[​](https://ionic.io/docs/supported-plugins/contacts#static-unknown_error "Direct link to heading") ▪ **UNKNOWN\_ERROR**: _number_ = 0 Error codes ### Contactfield[​](https://ionic.io/docs/supported-plugins/contacts#contactfield "Direct link to heading") Generic contact field. ### Constructors[​](https://ionic.io/docs/supported-plugins/contacts#constructors-3 "Direct link to heading") ### constructor[​](https://ionic.io/docs/supported-plugins/contacts#constructor-3 "Direct link to heading") + **new ContactField**(`type?`: undefined | string, `value?`: undefined | string, `pref?`: undefined | false | true): _[ContactField](https://ionic.io/docs/supported-plugins/contacts#contactfield) _ **Parameters:** | Name | Type | | --- | --- | | `type?` | undefined \| string | | `value?` | undefined \| string | | `pref?` | undefined \| false \| true | **Returns:** _[ContactField](https://ionic.io/docs/supported-plugins/contacts#contactfield) _ ### Properties[​](https://ionic.io/docs/supported-plugins/contacts#properties-3 "Direct link to heading") ### `Optional` id[​](https://ionic.io/docs/supported-plugins/contacts#optional-id-2 "Direct link to heading") • **id**? : _string | null_ unique identifier, should only be set by native code * * * ### `Optional` pref[​](https://ionic.io/docs/supported-plugins/contacts#optional-pref-1 "Direct link to heading") • **pref**? : _undefined | false | true_ Set to true if this ContactField contains the user's preferred value. * * * ### `Optional` type[​](https://ionic.io/docs/supported-plugins/contacts#optional-type-1 "Direct link to heading") • **type**? : _string | null_ A string that indicates what type of field this is, home for example. * * * ### `Optional` value[​](https://ionic.io/docs/supported-plugins/contacts#optional-value "Direct link to heading") • **value**? : _string | null_ The value of the field, such as a phone number or email address. ### Contactfindoptions[​](https://ionic.io/docs/supported-plugins/contacts#contactfindoptions "Direct link to heading") ContactFindOptions. Search options to filter ### Constructors[​](https://ionic.io/docs/supported-plugins/contacts#constructors-4 "Direct link to heading") ### constructor[​](https://ionic.io/docs/supported-plugins/contacts#constructor-4 "Direct link to heading") + **new ContactFindOptions**(`filter?`: undefined | string, `multiple?`: undefined | false | true, `desiredFields?`: string\[\], `hasPhoneNumber?`: undefined | false | true): _[ContactFindOptions](https://ionic.io/docs/supported-plugins/contacts#contactfindoptions) _ **Parameters:** | Name | Type | | --- | --- | | `filter?` | undefined \| string | | `multiple?` | undefined \| false \| true | | `desiredFields?` | string\[\] | | `hasPhoneNumber?` | undefined \| false \| true | **Returns:** _[ContactFindOptions](https://ionic.io/docs/supported-plugins/contacts#contactfindoptions) _ ### Properties[​](https://ionic.io/docs/supported-plugins/contacts#properties-4 "Direct link to heading") ### `Optional` desiredFields[​](https://ionic.io/docs/supported-plugins/contacts#optional-desiredfields "Direct link to heading") • **desiredFields**? : _string\[\]_ Contact fields to be returned back. If specified, the resulting Contact object only features values for these fields. * * * ### `Optional` filter[​](https://ionic.io/docs/supported-plugins/contacts#optional-filter "Direct link to heading") • **filter**? : _undefined | string_ The search string used to find navigator.contacts. * * * ### `Optional` hasPhoneNumber[​](https://ionic.io/docs/supported-plugins/contacts#optional-hasphonenumber "Direct link to heading") • **hasPhoneNumber**? : _undefined | false | true_ (Android only): Filters the search to only return contacts with a phone number informed. * * * ### `Optional` multiple[​](https://ionic.io/docs/supported-plugins/contacts#optional-multiple "Direct link to heading") • **multiple**? : _undefined | false | true_ Determines if the find operation returns multiple navigator.contacts. Defaults to false. ### Contactname[​](https://ionic.io/docs/supported-plugins/contacts#contactname "Direct link to heading") Contact name. ### Constructors[​](https://ionic.io/docs/supported-plugins/contacts#constructors-5 "Direct link to heading") ### constructor[​](https://ionic.io/docs/supported-plugins/contacts#constructor-5 "Direct link to heading") + **new ContactName**(`formatted?`: undefined | string, `familyName?`: undefined | string, `givenName?`: undefined | string, `middleName?`: undefined | string, `honorificPrefix?`: undefined | string, `honorificSuffix?`: undefined | string): _[ContactName](https://ionic.io/docs/supported-plugins/contacts#contactname) _ **Parameters:** | Name | Type | | --- | --- | | `formatted?` | undefined \| string | | `familyName?` | undefined \| string | | `givenName?` | undefined \| string | | `middleName?` | undefined \| string | | `honorificPrefix?` | undefined \| string | | `honorificSuffix?` | undefined \| string | **Returns:** _[ContactName](https://ionic.io/docs/supported-plugins/contacts#contactname) _ ### Properties[​](https://ionic.io/docs/supported-plugins/contacts#properties-5 "Direct link to heading") ### `Optional` familyName[​](https://ionic.io/docs/supported-plugins/contacts#optional-familyname "Direct link to heading") • **familyName**? : _string | null_ The contact's family name. * * * ### `Optional` formatted[​](https://ionic.io/docs/supported-plugins/contacts#optional-formatted-1 "Direct link to heading") • **formatted**? : _string | null_ The complete name of the contact. * * * ### `Optional` givenName[​](https://ionic.io/docs/supported-plugins/contacts#optional-givenname "Direct link to heading") • **givenName**? : _string | null_ The contact's given name. * * * ### `Optional` honorificPrefix[​](https://ionic.io/docs/supported-plugins/contacts#optional-honorificprefix "Direct link to heading") • **honorificPrefix**? : _string | null_ The contact's prefix (example Mr. or Dr.) * * * ### `Optional` honorificSuffix[​](https://ionic.io/docs/supported-plugins/contacts#optional-honorificsuffix "Direct link to heading") • **honorificSuffix**? : _string | null_ The contact's suffix (example Esq.). * * * ### `Optional` middleName[​](https://ionic.io/docs/supported-plugins/contacts#optional-middlename "Direct link to heading") • **middleName**? : _string | null_ The contact's middle name. ### Contactorganization[​](https://ionic.io/docs/supported-plugins/contacts#contactorganization "Direct link to heading") Contact organization. ### Constructors[​](https://ionic.io/docs/supported-plugins/contacts#constructors-6 "Direct link to heading") ### constructor[​](https://ionic.io/docs/supported-plugins/contacts#constructor-6 "Direct link to heading") + **new ContactOrganization**(`type?`: undefined | string, `name?`: undefined | string, `department?`: undefined | string, `title?`: undefined | string, `pref?`: undefined | false | true): _[ContactOrganization](https://ionic.io/docs/supported-plugins/contacts#contactorganization) _ **Parameters:** | Name | Type | | --- | --- | | `type?` | undefined \| string | | `name?` | undefined \| string | | `department?` | undefined \| string | | `title?` | undefined \| string | | `pref?` | undefined \| false \| true | **Returns:** _[ContactOrganization](https://ionic.io/docs/supported-plugins/contacts#contactorganization) _ ### Properties[​](https://ionic.io/docs/supported-plugins/contacts#properties-6 "Direct link to heading") ### `Optional` department[​](https://ionic.io/docs/supported-plugins/contacts#optional-department "Direct link to heading") • **department**? : _string | null_ The department the contract works for. * * * ### `Optional` id[​](https://ionic.io/docs/supported-plugins/contacts#optional-id-3 "Direct link to heading") • **id**? : _string | null_ unique identifier, should only be set by native code * * * ### `Optional` name[​](https://ionic.io/docs/supported-plugins/contacts#optional-name-1 "Direct link to heading") • **name**? : _string | null_ The name of the organization. * * * ### `Optional` pref[​](https://ionic.io/docs/supported-plugins/contacts#optional-pref-2 "Direct link to heading") • **pref**? : _undefined | false | true_ Set to true if this ContactOrganization contains the user's preferred value. * * * ### `Optional` title[​](https://ionic.io/docs/supported-plugins/contacts#optional-title "Direct link to heading") • **title**? : _string | null_ The contact's title at the organization. * * * ### `Optional` type[​](https://ionic.io/docs/supported-plugins/contacts#optional-type-2 "Direct link to heading") • **type**? : _string | null_ A string that indicates what type of field this is, home for example. ### Contacts[​](https://ionic.io/docs/supported-plugins/contacts#contacts "Direct link to heading") Access and manage Contacts on the device. ### Methods[​](https://ionic.io/docs/supported-plugins/contacts#methods-1 "Direct link to heading") ### create[​](https://ionic.io/docs/supported-plugins/contacts#create "Direct link to heading") ▸ **create**(`properties?`: any): _[Contact](https://ionic.io/docs/supported-plugins/contacts#contact) _ This function creates a new contact, but it does not persist the contact to device storage. To persist the contact to device storage, invoke contact.save(). **Parameters:** | Name | Type | Description | | --- | --- | --- | | `properties?` | any | an object whose properties will be examined to create a new Contact | **Returns:** _[Contact](https://ionic.io/docs/supported-plugins/contacts#contact) _ new Contact object * * * ### find[​](https://ionic.io/docs/supported-plugins/contacts#find "Direct link to heading") ▸ **find**(`fields`: [ContactFieldType](https://ionic.io/docs/supported-plugins/contacts#contactfieldtype) \[\], `options?`: [ContactFindOptions](https://ionic.io/docs/supported-plugins/contacts#contactfindoptions) ): _Promise‹[Contact](https://ionic.io/docs/supported-plugins/contacts#contact) \[\]›_ Returns an array of Contacts matching the search criteria. **Parameters:** | Name | Type | Description | | --- | --- | --- | | `fields` | [ContactFieldType](https://ionic.io/docs/supported-plugins/contacts#contactfieldtype)
\[\] | that should be searched (see platform specific notes) | | `options?` | [ContactFindOptions](https://ionic.io/docs/supported-plugins/contacts#contactfindoptions) | that can be applied to contact searching | **Returns:** _Promise‹[Contact](https://ionic.io/docs/supported-plugins/contacts#contact) \[\]›_ a promise that resolves with the array of Contacts matching search criteria * * * ### newContactUI[​](https://ionic.io/docs/supported-plugins/contacts#newcontactui "Direct link to heading") ▸ **newContactUI**(): _Promise‹string›_ iOS only Create a contact using the iOS Contact Picker UI returns: a promise that resolves with the id of the created contact as param to successCallback **Returns:** _Promise‹string›_ * * * ### pickContact[​](https://ionic.io/docs/supported-plugins/contacts#pickcontact "Direct link to heading") ▸ **pickContact**(): _Promise‹[Contact](https://ionic.io/docs/supported-plugins/contacts#contact) ›_ This function picks contact from phone using contact picker UI **Returns:** _Promise‹[Contact](https://ionic.io/docs/supported-plugins/contacts#contact) ›_ a promise that resolves with the selected Contact object Changelog[​](https://ionic.io/docs/supported-plugins/contacts#changelog "Direct link to heading") -------------------------------------------------------------------------------------------------- ### \[1.1.2\] (2020-06-10)[​](https://ionic.io/docs/supported-plugins/contacts#112-2020-06-10 "Direct link to heading") ### Bug Fixes[​](https://ionic.io/docs/supported-plugins/contacts#bug-fixes "Direct link to heading") * **ios:** Adding additional search predicates on iOS ### \[1.1.1\] (2020-05-28)[​](https://ionic.io/docs/supported-plugins/contacts#111-2020-05-28 "Direct link to heading") ### Bug Fixes[​](https://ionic.io/docs/supported-plugins/contacts#bug-fixes-1 "Direct link to heading") * **ios:** make wildcard return all contacts ### \[1.1.0\] (2020-04-24)[​](https://ionic.io/docs/supported-plugins/contacts#110-2020-04-24 "Direct link to heading") ### Features[​](https://ionic.io/docs/supported-plugins/contacts#features "Direct link to heading") * **ios:** enable wildcard fetch-all contacts ### \[1.0.6\] (2020-02-07)[​](https://ionic.io/docs/supported-plugins/contacts#106-2020-02-07 "Direct link to heading") ### Bug Fixes[​](https://ionic.io/docs/supported-plugins/contacts#bug-fixes-2 "Direct link to heading") * **ios:** make save work on existing contacts ### \[1.0.5\] (2019-11-22)[​](https://ionic.io/docs/supported-plugins/contacts#105-2019-11-22 "Direct link to heading") ### Bug Fixes[​](https://ionic.io/docs/supported-plugins/contacts#bug-fixes-3 "Direct link to heading") * prevent devideready block when package is not installed as plugin ### \[1.0.4\] (2019-11-08)[​](https://ionic.io/docs/supported-plugins/contacts#104-2019-11-08 "Direct link to heading") ### Bug Fixes[​](https://ionic.io/docs/supported-plugins/contacts#bug-fixes-4 "Direct link to heading") * **ios:** make pickContact prompt for permission if not granted ### \[1.0.3\] (2019-11-04)[​](https://ionic.io/docs/supported-plugins/contacts#103-2019-11-04 "Direct link to heading") ### Bug Fixes[​](https://ionic.io/docs/supported-plugins/contacts#bug-fixes-5 "Direct link to heading") * make plugin don't break web context ### \[1.0.2\] (2019-10-02)[​](https://ionic.io/docs/supported-plugins/contacts#102-2019-10-02 "Direct link to heading") ### Bug Fixes[​](https://ionic.io/docs/supported-plugins/contacts#bug-fixes-6 "Direct link to heading") * **ios:** remove contact notes code to work on iOS 13 ### 1.0.1 (2019-09-20)[​](https://ionic.io/docs/supported-plugins/contacts#101-2019-09-20 "Direct link to heading") ### Bug Fixes[​](https://ionic.io/docs/supported-plugins/contacts#bug-fixes-7 "Direct link to heading") * plugin files not included on published package * [Usage](https://ionic.io/docs/supported-plugins/contacts#usage) * [Index](https://ionic.io/docs/supported-plugins/contacts#index) * [Classes](https://ionic.io/docs/supported-plugins/contacts#classes) * [Type aliases](https://ionic.io/docs/supported-plugins/contacts#type-aliases) * [Type aliases](https://ionic.io/docs/supported-plugins/contacts#type-aliases-1) * [ContactFieldType](https://ionic.io/docs/supported-plugins/contacts#contactfieldtype) * [Contact](https://ionic.io/docs/supported-plugins/contacts#contact) * [Constructors](https://ionic.io/docs/supported-plugins/contacts#constructors) * [constructor](https://ionic.io/docs/supported-plugins/contacts#constructor) * [Properties](https://ionic.io/docs/supported-plugins/contacts#properties) * [`Optional` addresses](https://ionic.io/docs/supported-plugins/contacts#optional-addresses) * [`Optional` birthday](https://ionic.io/docs/supported-plugins/contacts#optional-birthday) * [`Optional` categories](https://ionic.io/docs/supported-plugins/contacts#optional-categories) * [`Optional` displayName](https://ionic.io/docs/supported-plugins/contacts#optional-displayname) * [`Optional` emails](https://ionic.io/docs/supported-plugins/contacts#optional-emails) * [`Optional` id](https://ionic.io/docs/supported-plugins/contacts#optional-id) * [`Optional` ims](https://ionic.io/docs/supported-plugins/contacts#optional-ims) * [`Optional` name](https://ionic.io/docs/supported-plugins/contacts#optional-name) * [`Optional` nickname](https://ionic.io/docs/supported-plugins/contacts#optional-nickname) * [`Optional` note](https://ionic.io/docs/supported-plugins/contacts#optional-note) * [`Optional` organizations](https://ionic.io/docs/supported-plugins/contacts#optional-organizations) * [`Optional` phoneNumbers](https://ionic.io/docs/supported-plugins/contacts#optional-phonenumbers) * [`Optional` photos](https://ionic.io/docs/supported-plugins/contacts#optional-photos) * [`Optional` rawId](https://ionic.io/docs/supported-plugins/contacts#optional-rawid) * [`Optional` urls](https://ionic.io/docs/supported-plugins/contacts#optional-urls) * [Methods](https://ionic.io/docs/supported-plugins/contacts#methods) * [clone](https://ionic.io/docs/supported-plugins/contacts#clone) * [display](https://ionic.io/docs/supported-plugins/contacts#display) * [remove](https://ionic.io/docs/supported-plugins/contacts#remove) * [save](https://ionic.io/docs/supported-plugins/contacts#save) * [Contactaddress](https://ionic.io/docs/supported-plugins/contacts#contactaddress) * [Constructors](https://ionic.io/docs/supported-plugins/contacts#constructors-1) * [constructor](https://ionic.io/docs/supported-plugins/contacts#constructor-1) * [Properties](https://ionic.io/docs/supported-plugins/contacts#properties-1) * [`Optional` country](https://ionic.io/docs/supported-plugins/contacts#optional-country) * [`Optional` formatted](https://ionic.io/docs/supported-plugins/contacts#optional-formatted) * [`Optional` id](https://ionic.io/docs/supported-plugins/contacts#optional-id-1) * [`Optional` locality](https://ionic.io/docs/supported-plugins/contacts#optional-locality) * [`Optional` postalCode](https://ionic.io/docs/supported-plugins/contacts#optional-postalcode) * [`Optional` pref](https://ionic.io/docs/supported-plugins/contacts#optional-pref) * [`Optional` region](https://ionic.io/docs/supported-plugins/contacts#optional-region) * [`Optional` streetAddress](https://ionic.io/docs/supported-plugins/contacts#optional-streetaddress) * [`Optional` type](https://ionic.io/docs/supported-plugins/contacts#optional-type) * [Contacterror](https://ionic.io/docs/supported-plugins/contacts#contacterror) * [Constructors](https://ionic.io/docs/supported-plugins/contacts#constructors-2) * [constructor](https://ionic.io/docs/supported-plugins/contacts#constructor-2) * [Properties](https://ionic.io/docs/supported-plugins/contacts#properties-2) * [code](https://ionic.io/docs/supported-plugins/contacts#code) * [`Optional` message](https://ionic.io/docs/supported-plugins/contacts#optional-message) * [`Static` INVALID\_ARGUMENT\_ERROR](https://ionic.io/docs/supported-plugins/contacts#static-invalid_argument_error) * [`Static` IO\_ERROR](https://ionic.io/docs/supported-plugins/contacts#static-io_error) * [`Static` NOT\_SUPPORTED\_ERROR](https://ionic.io/docs/supported-plugins/contacts#static-not_supported_error) * [`Static` OPERATION\_CANCELLED\_ERROR](https://ionic.io/docs/supported-plugins/contacts#static-operation_cancelled_error) * [`Static` PENDING\_OPERATION\_ERROR](https://ionic.io/docs/supported-plugins/contacts#static-pending_operation_error) * [`Static` PERMISSION\_DENIED\_ERROR](https://ionic.io/docs/supported-plugins/contacts#static-permission_denied_error) * [`Static` TIMEOUT\_ERROR](https://ionic.io/docs/supported-plugins/contacts#static-timeout_error) * [`Static` UNKNOWN\_ERROR](https://ionic.io/docs/supported-plugins/contacts#static-unknown_error) * [Contactfield](https://ionic.io/docs/supported-plugins/contacts#contactfield) * [Constructors](https://ionic.io/docs/supported-plugins/contacts#constructors-3) * [constructor](https://ionic.io/docs/supported-plugins/contacts#constructor-3) * [Properties](https://ionic.io/docs/supported-plugins/contacts#properties-3) * [`Optional` id](https://ionic.io/docs/supported-plugins/contacts#optional-id-2) * [`Optional` pref](https://ionic.io/docs/supported-plugins/contacts#optional-pref-1) * [`Optional` type](https://ionic.io/docs/supported-plugins/contacts#optional-type-1) * [`Optional` value](https://ionic.io/docs/supported-plugins/contacts#optional-value) * [Contactfindoptions](https://ionic.io/docs/supported-plugins/contacts#contactfindoptions) * [Constructors](https://ionic.io/docs/supported-plugins/contacts#constructors-4) * [constructor](https://ionic.io/docs/supported-plugins/contacts#constructor-4) * [Properties](https://ionic.io/docs/supported-plugins/contacts#properties-4) * [`Optional` desiredFields](https://ionic.io/docs/supported-plugins/contacts#optional-desiredfields) * [`Optional` filter](https://ionic.io/docs/supported-plugins/contacts#optional-filter) * [`Optional` hasPhoneNumber](https://ionic.io/docs/supported-plugins/contacts#optional-hasphonenumber) * [`Optional` multiple](https://ionic.io/docs/supported-plugins/contacts#optional-multiple) * [Contactname](https://ionic.io/docs/supported-plugins/contacts#contactname) * [Constructors](https://ionic.io/docs/supported-plugins/contacts#constructors-5) * [constructor](https://ionic.io/docs/supported-plugins/contacts#constructor-5) * [Properties](https://ionic.io/docs/supported-plugins/contacts#properties-5) * [`Optional` familyName](https://ionic.io/docs/supported-plugins/contacts#optional-familyname) * [`Optional` formatted](https://ionic.io/docs/supported-plugins/contacts#optional-formatted-1) * [`Optional` givenName](https://ionic.io/docs/supported-plugins/contacts#optional-givenname) * [`Optional` honorificPrefix](https://ionic.io/docs/supported-plugins/contacts#optional-honorificprefix) * [`Optional` honorificSuffix](https://ionic.io/docs/supported-plugins/contacts#optional-honorificsuffix) * [`Optional` middleName](https://ionic.io/docs/supported-plugins/contacts#optional-middlename) * [Contactorganization](https://ionic.io/docs/supported-plugins/contacts#contactorganization) * [Constructors](https://ionic.io/docs/supported-plugins/contacts#constructors-6) * [constructor](https://ionic.io/docs/supported-plugins/contacts#constructor-6) * [Properties](https://ionic.io/docs/supported-plugins/contacts#properties-6) * [`Optional` department](https://ionic.io/docs/supported-plugins/contacts#optional-department) * [`Optional` id](https://ionic.io/docs/supported-plugins/contacts#optional-id-3) * [`Optional` name](https://ionic.io/docs/supported-plugins/contacts#optional-name-1) * [`Optional` pref](https://ionic.io/docs/supported-plugins/contacts#optional-pref-2) * [`Optional` title](https://ionic.io/docs/supported-plugins/contacts#optional-title) * [`Optional` type](https://ionic.io/docs/supported-plugins/contacts#optional-type-2) * [Contacts](https://ionic.io/docs/supported-plugins/contacts#contacts) * [Methods](https://ionic.io/docs/supported-plugins/contacts#methods-1) * [create](https://ionic.io/docs/supported-plugins/contacts#create) * [find](https://ionic.io/docs/supported-plugins/contacts#find) * [newContactUI](https://ionic.io/docs/supported-plugins/contacts#newcontactui) * [pickContact](https://ionic.io/docs/supported-plugins/contacts#pickcontact) * [Changelog](https://ionic.io/docs/supported-plugins/contacts#changelog) * [1.1.2 (2020-06-10)](https://ionic.io/docs/supported-plugins/contacts#112-2020-06-10) * [Bug Fixes](https://ionic.io/docs/supported-plugins/contacts#bug-fixes) * [1.1.1 (2020-05-28)](https://ionic.io/docs/supported-plugins/contacts#111-2020-05-28) * [Bug Fixes](https://ionic.io/docs/supported-plugins/contacts#bug-fixes-1) * [1.1.0 (2020-04-24)](https://ionic.io/docs/supported-plugins/contacts#110-2020-04-24) * [Features](https://ionic.io/docs/supported-plugins/contacts#features) * [1.0.6 (2020-02-07)](https://ionic.io/docs/supported-plugins/contacts#106-2020-02-07) * [Bug Fixes](https://ionic.io/docs/supported-plugins/contacts#bug-fixes-2) * [1.0.5 (2019-11-22)](https://ionic.io/docs/supported-plugins/contacts#105-2019-11-22) * [Bug Fixes](https://ionic.io/docs/supported-plugins/contacts#bug-fixes-3) * [1.0.4 (2019-11-08)](https://ionic.io/docs/supported-plugins/contacts#104-2019-11-08) * [Bug Fixes](https://ionic.io/docs/supported-plugins/contacts#bug-fixes-4) * [1.0.3 (2019-11-04)](https://ionic.io/docs/supported-plugins/contacts#103-2019-11-04) * [Bug Fixes](https://ionic.io/docs/supported-plugins/contacts#bug-fixes-5) * [1.0.2 (2019-10-02)](https://ionic.io/docs/supported-plugins/contacts#102-2019-10-02) * [Bug Fixes](https://ionic.io/docs/supported-plugins/contacts#bug-fixes-6) * [1.0.1 (2019-09-20)](https://ionic.io/docs/supported-plugins/contacts#101-2019-09-20) * [Bug Fixes](https://ionic.io/docs/supported-plugins/contacts#bug-fixes-7) --- # Using Automations - Appflow [Skip to main content](https://ionic.io/docs/appflow/automation/create#__docusaurus_skipToContent_fallback) On this page Managing Automations[​](https://ionic.io/docs/appflow/automation/create#managing-automations "Direct link to Managing Automations") ------------------------------------------------------------------------------------------------------------------------------------ Creating and customizing automations is simple. To get started, navigate to the `Automate` tab within the desired app. To **create a new automation**, click the `New Automation` button on the top right of the `Automate` dashboard. When clicked, the automation customization form will appear, which has several fields available to customize the automation (Read more about these [below](https://ionic.io/docs/appflow/automation/create#customizing-automations) ). To **edit an automation**, click the three dots next to the one you'd like to modify. Customizing Automations[​](https://ionic.io/docs/appflow/automation/create#customizing-automations "Direct link to Customizing Automations") --------------------------------------------------------------------------------------------------------------------------------------------- There are a number of customizations available to specify the specific behavior of a given automation. They are shown on the create/edit automation form below. ### Basic Automation Info[​](https://ionic.io/docs/appflow/automation/create#basic-automation-info "Direct link to Basic Automation Info") All automations need a name and git branch to trigger from. Whenever code is pushed to the selected branch, the automation will run. ![Choosing an Automation Type](https://ionic.io/docs/appflow/assets/images/ss-automation-create-type-63f907596f08b9a2fb93f96dfea13ebd.png) #### Fields[​](https://ionic.io/docs/appflow/automation/create#fields "Direct link to Fields") * **Name:** A name to identify the automation task. * **Git Branch:** The branch which will trigger the automation. This will run a build any time a `git push` is made to the specified branch. * **Target Platform:** The platform of the jobs this automation will run. In addition to name and git branches, automations have a number of customizations available depending on the type of job selected. ##### Note about Git Branch naming[​](https://ionic.io/docs/appflow/automation/create#note-about-git-branch-naming "Direct link to Note about Git Branch naming") It is possible to specify one or multiple `*` wildcards character to match multiple branches within a single automation; for instance: * a branch simply set to `*` will match all the branches and will trigger the automation for any single git push * a branch set to `dev*` will match any branch with a name starting with `dev` including `dev` itself * a branch set to `dev*other` will match any branch with a name starting with `dev` and ending with `other` including `devother` ### iOS and Android Automations[​](https://ionic.io/docs/appflow/automation/create#ios-and-android-automations "Direct link to iOS and Android Automations") iOS and Android automations create native builds which can be downloaded and run on devices. They have the following customizations: ![Creating a ios or android automation](https://ionic.io/docs/appflow/assets/images/ss-automation-create-package-5480d0ca0859a5819cf2586cadda4e23.png) #### Fields[​](https://ionic.io/docs/appflow/automation/create#fields-1 "Direct link to Fields") * **Build Stack:** The [build stack](https://ionic.io/docs/appflow/build-stacks) where the job created by this automation will run. * **Build Type:** The type of build to create. Options depend on the selected platform. * **Signing Certificate:** Which signing certificate to use. Learn more about them [here](https://ionic.io/docs/appflow/package/credentials) . * **Environment:** The [custom build environment](https://ionic.io/docs/appflow/package/environments#custom-environments) (if any) to use when this automation is triggered. * **Native Config:** The [native config](https://ionic.io/docs/appflow/package/intro#native-configs) (if any) to use when this automation is triggered. * **Webhook:** (optional) If enabled, a POST with information about completed builds will be sent to the entered URL. Learn more about their content [here](https://ionic.io/docs/appflow/package/webhooks) . ### Web Automations[​](https://ionic.io/docs/appflow/automation/create#web-automations "Direct link to Web Automations") Web automations build the javascript portion of an application and interface with the [Deploy](https://ionic.io/docs/appflow/deploy/intro) service to enable live app updates. ![Creating a web automation](https://ionic.io/docs/appflow/assets/images/ss-automation-create-web-b4aac571d13b4cc770bb66f578920a8f.png) #### Fields[​](https://ionic.io/docs/appflow/automation/create#fields-2 "Direct link to Fields") * **Environment:** The [custom build environment](https://ionic.io/docs/appflow/package/environments#custom-environments) (if any) to use when this automation is triggered. * **Web preview** (optional) If enabled, a web preview of the app will be published to a public URL. * **Live update:** (optional) The [Deploy Channel](https://ionic.io/docs/appflow/deploy/channels) where web builds from this automation will be assigned. * **Webhook:** (optional) If specified, a POST with information about completed builds will be sent to the entered URL. Learn more about their content [here](https://ionic.io/docs/appflow/package/webhooks) . ##### Note about Build Stacks[​](https://ionic.io/docs/appflow/automation/create#note-about-build-stacks "Direct link to Note about Build Stacks") It is possible to choose one of two different options for the Build Stack: 1. always be on the latest Build Stack 2. always be on a specific Build Stack. If the 1. is chosen, the automation will always create jobs using the latest build stack. When the "latest" build stack is updated to a newer version nothing needs to be done and the automation will keep working. If the 2. is chosen, the automation will always create jobs using the specified build stack until the build stack is deprecated. A clear deprecation date will be shown in the dashboard to give users time to update the automation. If a new build stack has not been chosen by the deprecation date, the automation will be automatically updated to the latest build stack on the deprecation date. Contents -------- * [Managing Automations](https://ionic.io/docs/appflow/automation/create#managing-automations) * [Customizing Automations](https://ionic.io/docs/appflow/automation/create#customizing-automations) * [Basic Automation Info](https://ionic.io/docs/appflow/automation/create#basic-automation-info) * [iOS and Android Automations](https://ionic.io/docs/appflow/automation/create#ios-and-android-automations) * [Web Automations](https://ionic.io/docs/appflow/automation/create#web-automations) --- # Tabs - Accessibility Guide [Skip to main content](https://ionic.io/docs/accessibility/ion-tab-button#) The `ion-tab-button` component requires some qualifying properties to meet accessibility requirements. ##### note [Axe](https://www.deque.com/axe/) will throw an error: "Ensures all page content is contained by landmarks" without these improvements. #### Before[​](https://ionic.io/docs/accessibility/ion-tab-button#before "Direct link to heading") Ionic Copy To correct the problem we set `role="navigation"` for the `ion-label` and give it an `aria-label` to make it unique amongst the other tabs of the `ion-tab-bar`. We also set `aria-hidden="true"` for the `ion-icon` as it does not require reading with the screen reader (and would require a landmark role if not hidden). #### After[​](https://ionic.io/docs/accessibility/ion-tab-button#after "Direct link to heading") Ionic Copy --- # Semantic Elements - Accessibility Guide [Skip to main content](https://ionic.io/docs/accessibility/semantic-elements#) Screen readers will use the semantic meaning of an element to help describe it. An element like a `div` conveys no particular meaning whereas `header`, `button` have meaning. Headings[​](https://ionic.io/docs/accessibility/semantic-elements#headings "Direct link to heading") ----------------------------------------------------------------------------------------------------- Screen readers and assistive technology rely on headers (`

` to `

`) for navigation. Tools like [Web Developer Toolbar](https://chrispederick.com/work/web-developer/) can help you visualize the semantic structure of your page. **There should be a single `h1` per page.** - The first heading of a page provides the best glimpse of what the content of the page is about without reading the whole page. Ionic pages often contain an `ion-title` which is a good element to mark as a level 1 heading using the `role` of `heading` and `aria-level` of `1`. #### Before[​](https://ionic.io/docs/accessibility/semantic-elements#before "Direct link to heading") Food Copy #### After[​](https://ionic.io/docs/accessibility/semantic-elements#after "Direct link to heading") Food Copy Sometimes you will want to provide a single level 1 heading but do not want to visually display it. You can achieve this with css: .screen-reader-only { clip: rect(0 0 0 0); clip-path: inset(50%); height: 1px; position: absolute; white-space: nowrap; overflow: hidden; width: 1px;} Copy Then used on the page in html:

Title for the page

Copy Landmarks[​](https://ionic.io/docs/accessibility/semantic-elements#landmarks "Direct link to heading") ------------------------------------------------------------------------------------------------------- Landmarks wrap content to mark up major semantic sections. All content on a page should be wrapped inside of one of the landmark elements supported by newer browsers: `
`, `