diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 3bcd54da..5be1272e 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,2 +1,2 @@ # https://help.github.com/en/articles/about-code-owners -* @BrianBatchelder @marc-scig @crow @rlepinski \ No newline at end of file +* @urbanairship/mobile \ No newline at end of file diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 49aa94bd..fe1420d0 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -3,4 +3,4 @@ We accept pull requests! If you would like to submit a pull request, please fill out and submit our [Contributor License Agreement](https://docs.google.com/forms/d/e/1FAIpQLScErfiz-fXSPpVZ9r8Di2Tr2xDFxt5MgzUel0__9vqUgvko7Q/viewform). -One of our engineers will verify receipt of the agreement before approving your pull request. +One of our engineers will verify receipt of the agreement before approving your pull request. \ No newline at end of file diff --git a/.github/workflows/CI.yaml b/.github/workflows/CI.yaml index 1e7f8f12..d4e03122 100644 --- a/.github/workflows/CI.yaml +++ b/.github/workflows/CI.yaml @@ -2,30 +2,26 @@ name: CI on: [pull_request] +concurrency: + group: ${{ github.ref }} + cancel-in-progress: true + jobs: android: - runs-on: macos-11 + runs-on: macos-13-xlarge + timeout-minutes: 10 env: - DEVELOPER_DIR: /Applications/Xcode_13.0.app/Contents/Developer + DEVELOPER_DIR: /Applications/Xcode_15.2.app/Contents/Developer steps: - - uses: actions/checkout@v1 - # Build tools 31.0.0 doesn't include dx (only d8), which Cordova expects to find. - # Uninstalling causes automatic build-tools resolution to fall back to an older - # version that does include dx. - - name: Workaround "Build-tool 31.0.0 is missing DX" error - run: bash $ANDROID_SDK_ROOT/tools/bin/sdkmanager --uninstall 'build-tools;31.0.0' - # Build tools 32.0.0 doesn't include dx (only d8), which Cordova expects to find. - # Uninstalling causes automatic build-tools resolution to fall back to an older - # version that does include dx. - - name: Workaround "Build-tool 32.0.0 is missing DX" error - run: bash $ANDROID_SDK_ROOT/tools/bin/sdkmanager --uninstall 'build-tools;32.0.0' + - uses: actions/checkout@v4 - name: Run CI run: bash ./scripts/run_ci_tasks.sh -a ios: - runs-on: macos-11 + runs-on: macos-13-xlarge + timeout-minutes: 10 env: - DEVELOPER_DIR: /Applications/Xcode.app/Contents/Developer + DEVELOPER_DIR: /Applications/Xcode_15.2.app/Contents/Developer steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v4 - name: Run CI run: bash ./scripts/run_ci_tasks.sh -i diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 10650435..39cced94 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -7,36 +7,27 @@ on: jobs: build: - runs-on: macos-11 + runs-on: macos-13-xlarge + timeout-minutes: 20 env: - DEVELOPER_DIR: /Applications/Xcode.app/Contents/Developer + DEVELOPER_DIR: /Applications/Xcode_15.2.app/Contents/Developer steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Check Version run: bash ./scripts/check_version.sh ${GITHUB_REF/refs\/tags\//} - name: Slack Notification - uses: homoluctus/slatify@master + uses: lazy-actions/slatify@master with: type: ${{ job.status }} job_name: "Airship Cordova Plugin Release Started!" url: ${{ secrets.SLACK_WEBHOOK }} - # Build tools 31.0.0 doesn't include dx (only d8), which Cordova expects to find. - # Uninstalling causes automatic build-tools resolution to fall back to an older - # version that does include dx. - - name: Workaround "Build-tool 31.0.0 is missing DX" error - run: bash $ANDROID_SDK_ROOT/tools/bin/sdkmanager --uninstall 'build-tools;31.0.0' - # Build tools 32.0.0 doesn't include dx (only d8), which Cordova expects to find. - # Uninstalling causes automatic build-tools resolution to fall back to an older - # version that does include dx. - - name: Workaround "Build-tool 32.0.0 is missing DX" error - run: bash $ANDROID_SDK_ROOT/tools/bin/sdkmanager --uninstall 'build-tools;32.0.0' - name: Run CI run: | bash ./scripts/run_ci_tasks.sh -a -i - name: Slack Notification - uses: homoluctus/slatify@master + uses: lazy-actions/slatify@master if: failure() with: type: ${{ job.status }} @@ -46,9 +37,11 @@ jobs: deploy: needs: [build] runs-on: ubuntu-latest + permissions: + contents: write steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Get the version id: get_version run: echo ::set-output name=VERSION::${GITHUB_REF/refs\/tags\//} @@ -71,32 +64,33 @@ jobs: with: node-version: 14 registry-url: https://registry.npmjs.org/ - - name: Generate documentation - run: | - yarn install - yarn generate-docs - uses: google-github-actions/setup-gcloud@v0 with: version: '351.0.0' service_account_email: ${{ secrets.GCP_SA_EMAIL }} - service_account_key: ${{ secrets.GCP_SA_KEY }} - - name: Upload docs - run: bash ./scripts/upload_docs.sh ${GITHUB_REF/refs\/tags\//} jsdoc_out - - name: Publish modules + service_account_key: ${{ secrets.GCP_SA_KEY }} + + - name: Docs run: | cd urbanairship-cordova/ - yarn publish + npm install + npm run generate-docs cd - - cd urbanairship-accengage-cordova/ - yarn publish + bash ./scripts/upload_docs.sh ${GITHUB_REF/refs\/tags\//} ./urbanairship-cordova/docs + + - name: Publish modules + run: | + cd cordova-airship/ + npm publish cd - - cd urbanairship-hms-cordova/ - yarn publish + cd cordova-airship-hms/ + npm publish cd - env: NODE_AUTH_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }} - name: Github Release - uses: actions/create-release@v1.0.1 + id: create_release + uses: softprops/action-gh-release@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: @@ -106,13 +100,13 @@ jobs: draft: false prerelease: false - name: Slack Notification - uses: homoluctus/slatify@master + uses: lazy-actions/slatify@master with: type: ${{ job.status }} job_name: "Airship Cordova Plugin Released!" url: ${{ secrets.SLACK_WEBHOOK }} - name: Slack Notification - uses: homoluctus/slatify@master + uses: lazy-actions/slatify@master if: failure() with: type: ${{ job.status }} diff --git a/.gitignore b/.gitignore index 9a386684..0e00f78d 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,5 @@ out/* node_modules/* scripts/update_cordova/node_modules/* config_sample.xml +cordova-airship/docs +google-services.json \ No newline at end of file diff --git a/COPYING b/COPYING index d73830c0..cb937b1e 100644 --- a/COPYING +++ b/COPYING @@ -1,13 +1,13 @@ -Copyright 2010-2019 Urban Airship +Copyright 2010-2024 Airship and Contributors Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 + http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and -limitations under the License. +limitations under the License. \ No newline at end of file diff --git a/Example/index.html b/Example/index.html index f38ab391..79e34235 100644 --- a/Example/index.html +++ b/Example/index.html @@ -17,69 +17,39 @@ var onDeviceReady = function() { console.log("Device ready!") - // Incoming message callback - var onPushReceived = function(event) { - if (event.message) { - console.log("Received push: " + event.message) - } else { - console.log("No incoming message") - } - } + - // Notification opened callback - var notificationOpened = function(event) { - if (event.message) { - console.log("Notification opened: " + event.message) - } else { - console.log("No incoming message") - } - } + Airship.onDeepLink(function(event) { + console.log("onDeepLink: " + JSON.stringify(event)) + }) - // Registration callback - var onRegistration = function(event) { - if (!event.error) { - console.log("Reg Success: " + event.channelID) - $('#id').text(event.channelID) - } else { - console.log(event.error) - } - } + Airship.push.onPushReceived(function(event) { + console.log("onPushReceived: " + JSON.stringify(event)) + }) - // Deep link callback - var handleDeepLink = function(event) { - console.log("Deep link: " + event.deepLink) - } + Airship.push.onNotificationResponse(function(event) { + console.log("onNotificationResponse: " + JSON.stringify(event)) + }) - // Deep link callback - var handleOpenPreferenceCenter = function(event) { - console.log("Open preference Center: " + event.PreferenceCenterLink) - } + Airship.channel.onChannelCreated(function(event) { + console.log("onChannelCreated: " + JSON.stringify(event)) + $('#id').text(event.channelId) + }) - // Register for any urban airship events - document.addEventListener("urbanairship.registration", onRegistration, false) - document.addEventListener("urbanairship.push", onPushReceived, false) - document.addEventListener("urbanairship.notification_opened", notificationOpened, false) - document.addEventListener("urbanairship.deep_link", handleDeepLink, false) - document.addEventListener("urbanairship.open_preference_center", handleOpenPreferenceCenter, false) + Airship.push.onNotificationStatusChanged(function(event) { + console.log("onNotificationStatusChanged: " + JSON.stringify(event)) + }) // Handle resume document.addEventListener("resume", function() { console.log("Device resume!") - UAirship.resetBadge() - - // Reregister for urbanairship events if they were removed in pause event - document.addEventListener("urbanairship.registration", onRegistration, false) - document.addEventListener("urbanairship.push", onPushReceived, false) + Airship.push.ios.resetBadge() }, false) // Handle pause document.addEventListener("pause", function() { console.log("Device pause!") - - // Remove urbanairship events. Important on android to not receive push in the background. - document.removeEventListener("urbanairship.registration", onRegistration, false) - document.removeEventListener("urbanairship.push", onPushReceived, false) }, false) // Initiate the UI @@ -102,10 +72,10 @@ $tag.remove() // Remove the tag from the current list of tags - UAirship.getTags(function(tags) { + Airship.channel.getTags(function(tags) { console.log("Removing tag: " + tag) tags.splice(tags.indexOf(tag), 1) - UAirship.setTags(tags) + Airship.channel.setTags(tags) }) }) } @@ -116,94 +86,113 @@ $("#setNamedUserField").val("") } - // Vibrate and Sound is only available on Android - if (device.platform != "Android") { - $("#soundEnabledSection").hide() - $("#vibrateEnabledSection").hide() + if (device.platform != "iOS") { + $("#quietTimeEnabled").hide() + $("#quietTimeEnabledSection").hide() + } else { + Airship.push.ios.isQuietTimeEnabled(function(isEnabled) { + $('#quietTimeEnabled').val(isEnabled ? 'on' : 'off').change() + }) + + + $('#quietTimeEnabled').change(function() { + var isEnabled = ($('#pushEnabled').val() == "on") + Airship.push.ios.setQuietTimeEnabled(isEnabled) + } + + Airship.push.ios.getQuietTime(function(obj) { + $("#startHour").val(obj.startHour) + $("#startMinute").val(obj.startMinute) + $("#endHour").val(obj.endHour) + $("#endMinute").val(obj.endMinute) + }) + + $("#setQuietTimeButton").click(function(ev) { + var settings = { + "startHour": parseInt($("#startHour").val()), + "startMinute": parseInt($("#startMinute").val()), + "endHour": parseInt($("#endHour").val()), + "endMinute": parseInt($("#endMinute").val()), + } + + Airship.push.ios.setQuietTime(settings, function() { + console.log("Set quiet time from JS") + }) + }) } // Update the interface with the current UA settings - UAirship.isUserNotificationsEnabled(function(isEnabled) { + Airship.push.isUserNotificationsEnabled(function(isEnabled) { $('#pushEnabled').val(isEnabled ? 'on' : 'off').change() }) - UAirship.isFeatureEnabled([UAirship.FEATURE_ALL], function(isEnabled) { + Airship.privacyManager.isFeaturesEnabled(["all"], function(isEnabled) { $('#allFeaturesEnabled').val(isEnabled ? 'on' : 'off').change() }) - UAirship.isQuietTimeEnabled(function(isEnabled) { - $('#quietTimeEnabled').val(isEnabled ? 'on' : 'off').change() - }) - - - UAirship.getChannelID(function(id) { + Airship.channel.getChannelId(function(id) { if(id) { console.log("Got channel ID: " + id) $('#id').text(id) } }) - UAirship.getNamedUser(function(namedUser) { + Airship.contact.getNamedUser(function(namedUser) { if(namedUser) { console.log("Got namedUser: " + namedUser) setNamedUser(namedUser) } }) - UAirship.getTags(function(tags) { + Airship.channel.getTags(function(tags) { tags.forEach(function(tag) { addTag(tag) }) }) - UAirship.getQuietTime(function(obj) { - $("#startHour").val(obj.startHour) - $("#startMinute").val(obj.startMinute) - $("#endHour").val(obj.endHour) - $("#endMinute").val(obj.endMinute) - }) + // Set up change callbacks for the UI elements $('#pushEnabled').change(function() { var isEnabled = ($('#pushEnabled').val() == "on") - UAirship.setUserNotificationsEnabled(isEnabled) + Airship.push.setUserNotificationsEnabled(isEnabled) }) $('#allFeaturesEnabled').change(function() { var isEnabled = ($('#allFeaturesEnabled').val() == "on") if (isEnabled) { console.log("Enables all Features") - UAirship.setEnabledFeatures([UAirship.FEATURE_ALL]) + Airship.privacyManager.setEnabledFeatures(["all"]) } else { console.log("Disables all Features") console.log("Displaying Message Center") - UAirship.setEnabledFeatures([UAirship.FEATURE_NONE]) + Airship.privacyManager.setEnabledFeatures([]) } }) $("#displayMessageCenterButton").click(function(ev) { console.log("Displaying Message Center") - UAirship.displayMessageCenter() - UAirship.trackScreen("Message Center") + Airship.messageCenter.display() + Airship.analytics.trackScreen("Message Center") }) $("#openPreferenceCenterButton").click(function(ev) { console.log("Opening Preference Center") - UAirship.openPreferenceCenter("test") - UAirship.trackScreen("Preference Center") + Airship.preferenceCenter.display("test") + Airship.analytics.trackScreen("Preference Center") }) $("#addTagButton").click(function(ev) { var tag = $("#addTagField").val() console.log("Adding new tag: " + tag) - UAirship.getTags(function(tags) { + Airship.channel.getTags(function(tags) { if(tags.indexOf(tag) == -1) { console.log("Valid tag: " + tag) tags = tags.concat([tag]) - UAirship.setTags(tags, function() { + Airship.channel.setTags(tags, function() { addTag(tag) $("#addTagField").val('') }) @@ -211,20 +200,11 @@ }) }) - $("#setQuietTimeButton").click(function(ev) { - var startHour = parseInt($("#startHour").val()) - var startMinute = parseInt($("#startMinute").val()) - var endHour = parseInt($("#endHour").val()) - var endMinute = parseInt($("#endMinute").val()) - - UAirship.setQuietTime(startHour, startMinute, endHour, endMinute, function() { - console.log("Set quiet time from JS") - }) - }) + $("#setNamedUserButton").click(function(ev) { var namedUser = $("#setNamedUserField").val() - UAirship.setNamedUser(namedUser, function() { + Airship.contact.identify(namedUser, function() { setNamedUser(namedUser) }) }) diff --git a/config_sample.xml b/config_sample.xml index 98a51eb6..c7bffa47 100644 --- a/config_sample.xml +++ b/config_sample.xml @@ -38,39 +38,10 @@ - - - - - - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - + + diff --git a/urbanairship-hms-cordova/README.md b/cordova-airship-hms/README.md similarity index 100% rename from urbanairship-hms-cordova/README.md rename to cordova-airship-hms/README.md diff --git a/urbanairship-hms-cordova/package.json b/cordova-airship-hms/package.json similarity index 78% rename from urbanairship-hms-cordova/package.json rename to cordova-airship-hms/package.json index 1bdb1e14..8ac744fc 100644 --- a/urbanairship-hms-cordova/package.json +++ b/cordova-airship-hms/package.json @@ -1,9 +1,9 @@ { - "name": "urbanairship-hms-cordova", - "version": "14.11.0", - "description": "Urban Airship HMS Cordova plugin", + "name": "@ua/cordova-airship-hms", + "version": "15.0.0", + "description": "Airship HMS Cordova plugin", "cordova": { - "id": "urbanairship-hms-cordova", + "id": "cordova-airship-hms", "platforms": [ "android" ] @@ -22,7 +22,7 @@ "engines": [ { "name": "cordova-android", - "version": ">=10.0.0" + "version": ">=11.0.0" }, { "name": "cordova-plugman", diff --git a/urbanairship-hms-cordova/plugin.xml b/cordova-airship-hms/plugin.xml similarity index 69% rename from urbanairship-hms-cordova/plugin.xml rename to cordova-airship-hms/plugin.xml index 2341038c..1d524d02 100644 --- a/urbanairship-hms-cordova/plugin.xml +++ b/cordova-airship-hms/plugin.xml @@ -1,21 +1,21 @@ - - urbanairship-hms-cordova - Urban Airship HMS Cordova plugin + Airship HMS + Airship HMS Cordova plugin Apache 2.0 cordova,urbanairship https://github.com/urbanairship/urbanairship-hms-cordova.git - + - + diff --git a/urbanairship-hms-cordova/src/android/app-build-extras.gradle b/cordova-airship-hms/src/android/app-build-extras.gradle similarity index 100% rename from urbanairship-hms-cordova/src/android/app-build-extras.gradle rename to cordova-airship-hms/src/android/app-build-extras.gradle diff --git a/urbanairship-hms-cordova/src/android/build-extras.gradle b/cordova-airship-hms/src/android/build-extras.gradle similarity index 85% rename from urbanairship-hms-cordova/src/android/build-extras.gradle rename to cordova-airship-hms/src/android/build-extras.gradle index 655f5f26..08bf60df 100644 --- a/urbanairship-hms-cordova/src/android/build-extras.gradle +++ b/cordova-airship-hms/src/android/build-extras.gradle @@ -5,7 +5,7 @@ repositories { } dependencies { - implementation 'com.urbanairship.android:urbanairship-hms:16.11.1' + implementation 'com.urbanairship.android:urbanairship-hms:17.1.0' implementation 'com.huawei.hms:push:6.3.0.304' } diff --git a/urbanairship-cordova/package.json b/cordova-airship/package.json similarity index 53% rename from urbanairship-cordova/package.json rename to cordova-airship/package.json index b32374bf..5723d7e7 100644 --- a/urbanairship-cordova/package.json +++ b/cordova-airship/package.json @@ -1,9 +1,9 @@ { - "name": "urbanairship-cordova", - "version": "14.11.0", - "description": "Urban Airship Cordova plugin", + "name": "@ua/cordova-airship", + "version": "15.0.0", + "description": "Airship Cordova plugin", "cordova": { - "id": "urbanairship-cordova", + "id": "airship-cordova", "platforms": [ "android", "ios" @@ -16,6 +16,7 @@ "keywords": [ "cordova", "urbanairship", + "airship", "ecosystem:cordova", "cordova-android", "cordova-ios" @@ -23,32 +24,24 @@ "engines": [ { "name": "cordova-android", - "version": ">=10.0.0" + "version": ">=11.0.0" }, { "name": "cordova-ios", - "version": ">=6.2.0" + "version": ">=7.0.0" }, { "name": "cordova-plugman", "version": ">=4.2.0" } ], - "author": "Urban Airship", + "author": "Airship", "license": "Apache 2.0", "homepage": "https://github.com/urbanairship/urbanairship-cordova.git", "devDependencies": { - "adm-zip": "^0.4.16", - "co": "^4.6.0", - "co-prompt": "^1.0.0", - "commander": "^2.20.3", - "fs": "0.0.1-security", - "jsdoc": "^3.6.6", - "minami": "1.2.3", - "semver": "^5.7.1", - "superagent": "^4.1.0" + "typedoc": "0.23.24" }, "scripts": { - "generate-docs": "jsdoc ./www/UrbanAirship.js -t ../node_modules/minami/ -r ../jsdoc_readme.md -d ../jsdoc_out" + "generate-docs": "typedoc types/index.d.ts" } } diff --git a/cordova-airship/plugin.xml b/cordova-airship/plugin.xml new file mode 100644 index 00000000..8a8f31de --- /dev/null +++ b/cordova-airship/plugin.xml @@ -0,0 +1,140 @@ + + + + Airship + Airship Cordova plugin + Apache 2.0 + cordova,urbanairship,airship + https://github.com/urbanairship/urbanairship-cordova.git + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + remote-notification + + + + + 15.0.0 + + + + + + + + + + + development + + + + production + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cordova-airship/src/android/AirshipCordova.kt b/cordova-airship/src/android/AirshipCordova.kt new file mode 100644 index 00000000..ca35f21d --- /dev/null +++ b/cordova-airship/src/android/AirshipCordova.kt @@ -0,0 +1,435 @@ +/* Copyright Urban Airship and Contributors */ + +package com.urbanairship.cordova + +import android.content.Context +import android.os.Build +import com.urbanairship.Autopilot +import com.urbanairship.PendingResult +import com.urbanairship.UALog +import com.urbanairship.actions.ActionResult +import com.urbanairship.android.framework.proxy.EventType +import com.urbanairship.android.framework.proxy.events.EventEmitter +import com.urbanairship.android.framework.proxy.proxies.AirshipProxy +import com.urbanairship.android.framework.proxy.proxies.FeatureFlagProxy +import com.urbanairship.json.JsonList +import com.urbanairship.json.JsonMap +import com.urbanairship.json.JsonSerializable +import com.urbanairship.json.JsonValue +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.launch +import kotlinx.coroutines.plus +import org.apache.cordova.CallbackContext +import org.apache.cordova.CordovaInterface +import org.apache.cordova.CordovaPlugin +import org.apache.cordova.CordovaWebView +import org.apache.cordova.PluginResult +import org.json.JSONArray +import org.json.JSONObject + +class AirshipCordova : CordovaPlugin() { + + internal data class Listener( + val listenerId: Int, + val callbackContext: CallbackContext + ) + + private var listeners: MutableMap> = mutableMapOf() + + companion object { + private val EVENT_NAME_MAP = mapOf( + EventType.BACKGROUND_NOTIFICATION_RESPONSE_RECEIVED to "airship.event.notification_response", + EventType.FOREGROUND_NOTIFICATION_RESPONSE_RECEIVED to "airship.event.notification_response", + EventType.CHANNEL_CREATED to "airship.event.channel_created", + EventType.DEEP_LINK_RECEIVED to "airship.event.deep_link_received", + EventType.DISPLAY_MESSAGE_CENTER to "airship.event.display_message_center", + EventType.DISPLAY_PREFERENCE_CENTER to "airship.event.display_preference_center", + EventType.MESSAGE_CENTER_UPDATED to "airship.event.message_center_updated", + EventType.PUSH_TOKEN_RECEIVED to "airship.event.push_token_received", + EventType.FOREGROUND_PUSH_RECEIVED to "airship.event.push_received", + EventType.BACKGROUND_PUSH_RECEIVED to "airship.event.background_push_received", + EventType.NOTIFICATION_STATUS_CHANGED to "airship.event.notification_status_changed" + ) + } + + private lateinit var applicationContext: Context + private val scope: CoroutineScope = CoroutineScope(Dispatchers.Main) + SupervisorJob() + + override fun execute( + action: String, + args: JSONArray, + callbackContext: CallbackContext + ): Boolean { + try { + when (action) { + "perform" -> perform(args, callbackContext) + "addListener" -> addListener(args, callbackContext) + "removeListener" -> removeListener(args) + else -> return false + } + return true + } catch (exception: java.lang.Exception) { + callbackContext.error(action, exception) + } + return false + } + + override fun initialize(cordova: CordovaInterface, webView: CordovaWebView) { + super.initialize(cordova, webView) + UALog.i { "Initializing Urban Airship cordova plugin." } + applicationContext = cordova.getActivity().applicationContext + Autopilot.automaticTakeOff(applicationContext) + + scope.launch { + EventEmitter.shared().pendingEventListener.collect { + notifyPendingEvents() + } + } + } + + override fun onReset() { + super.onReset() + this.listeners.clear() + } + + override fun onDestroy() { + super.onDestroy() + this.listeners.clear() + } + + private fun addListener(args: JSONArray, callbackContext: CallbackContext) { + val jsonArgs = JsonValue.wrap(args).requireList() + + val eventName = jsonArgs.get(0).requireString() + val event: EventType = EVENT_NAME_MAP.firstNotNullOf { + if (it.value == eventName) { + it.key + } else { + null + } + } + + val listener = Listener( + listenerId = jsonArgs.get(1).requireInt(), + callbackContext = callbackContext + ) + + this.listeners.getOrPut(event) { mutableListOf() }.add(listener) + notifyPendingEvents() + } + + private fun removeListener(args: JSONArray) { + val jsonArgs = JsonValue.wrap(args).requireList() + + val eventName = jsonArgs.get(0).requireString() + val event: EventType = EVENT_NAME_MAP.firstNotNullOf { + if (it.value == eventName) { + it.key + } else { + null + } + } + + val listenerId = jsonArgs.get(1).requireInt() + this.listeners[event]?.removeAll { + it.listenerId == listenerId + } + } + + private fun notifyPendingEvents() { + EventType.values().forEach { eventType -> + val listeners = this.listeners[eventType] + if (listeners?.isNotEmpty() == true) { + EventEmitter.shared().processPending(listOf(eventType)) { event -> + listeners.forEach { listeners -> + val pluginResult = event.body.pluginResult() + pluginResult.keepCallback = true + listeners.callbackContext.sendPluginResult(pluginResult) + } + true + } + } + } + } + + private fun perform(args: JSONArray, callback: CallbackContext) { + val jsonArgs = JsonValue.wrap(args).requireList() + val method = jsonArgs.get(0).requireString() + val arg: JsonValue = if (jsonArgs.size() == 2) { jsonArgs.get(1) } else { JsonValue.NULL } + + val proxy = AirshipProxy.shared(applicationContext) + + when (method) { + // Airship + "takeOff" -> callback.resolveResult(method) { proxy.takeOff(arg) } + "isFlying" -> callback.resolveResult(method) { proxy.isFlying() } + + // Channel + "channel#getChannelId" -> callback.resolveResult(method) { proxy.channel.getChannelId() } + + "channel#editTags" -> callback.resolveResult(method) { proxy.channel.editTags(arg) } + "channel#getTags" -> callback.resolveResult(method) { proxy.channel.getTags().toList() } + "channel#editTagGroups" -> callback.resolveResult(method) { proxy.channel.editTagGroups(arg) } + "channel#editSubscriptionLists" -> callback.resolveResult(method) { proxy.channel.editSubscriptionLists(arg) } + "channel#editAttributes" -> callback.resolveResult(method) { proxy.channel.editAttributes(arg) } + "channel#getSubscriptionLists" -> callback.resolvePending(method) { proxy.channel.getSubscriptionLists() } + "channel#enableChannelCreation" -> callback.resolveResult(method) { proxy.channel.enableChannelCreation() } + + // Contact + "contact#reset" -> callback.resolveResult(method) { proxy.contact.reset() } + "contact#notifyRemoteLogin" -> callback.resolveResult(method) { proxy.contact.notifyRemoteLogin() } + "contact#identify" -> callback.resolveResult(method) { proxy.contact.identify(arg.requireString()) } + "contact#getNamedUserId" -> callback.resolveResult(method) { proxy.contact.getNamedUserId() } + "contact#editTagGroups" -> callback.resolveResult(method) { proxy.contact.editTagGroups(arg) } + "contact#editSubscriptionLists" -> callback.resolveResult(method) { proxy.contact.editSubscriptionLists(arg) } + "contact#editAttributes" -> callback.resolveResult(method) { proxy.contact.editAttributes(arg) } + "contact#getSubscriptionLists" -> callback.resolvePending(method) { proxy.contact.getSubscriptionLists() } + + // Push + "push#setUserNotificationsEnabled" -> callback.resolveResult(method) { proxy.push.setUserNotificationsEnabled(arg.requireBoolean()) } + "push#enableUserNotifications" -> callback.resolvePending(method) { proxy.push.enableUserPushNotifications() } + "push#isUserNotificationsEnabled" -> callback.resolveResult(method) { proxy.push.isUserNotificationsEnabled() } + "push#getNotificationStatus" -> callback.resolveResult(method) { proxy.push.getNotificationStatus() } + "push#getActiveNotifications" -> callback.resolveResult(method) { proxy.push.getActiveNotifications() } + "push#clearNotification" -> callback.resolveResult(method) { proxy.push.clearNotification(arg.requireString()) } + "push#clearNotifications" -> callback.resolveResult(method) { proxy.push.clearNotifications() } + "push#getPushToken" -> callback.resolveResult(method) { proxy.push.getRegistrationToken() } + "push#android#isNotificationChannelEnabled" -> callback.resolveResult(method) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + proxy.push.isNotificationChannelEnabled(arg.requireString()) + } else { + true + } + } + "push#android#setNotificationConfig" -> callback.resolveResult(method) { proxy.push.setNotificationConfig(arg) } + "push#android#setForegroundNotificationsEnabled" -> callback.resolveResult(method) { + proxy.push.isForegroundNotificationsEnabled = arg.requireBoolean() + return@resolveResult Unit + } + "push#android#isForegroundNotificationsEnabled" -> callback.resolveResult(method) { + proxy.push.isForegroundNotificationsEnabled + } + + // In-App + "inApp#setPaused" -> callback.resolveResult(method) { proxy.inApp.setPaused(arg.getBoolean(false)) } + "inApp#isPaused" -> callback.resolveResult(method) { proxy.inApp.isPaused() } + "inApp#setDisplayInterval" -> callback.resolveResult(method) { proxy.inApp.setDisplayInterval(arg.getLong(0)) } + "inApp#getDisplayInterval" -> callback.resolveResult(method) { proxy.inApp.getDisplayInterval() } + + // Analytics + "analytics#trackScreen" -> callback.resolveResult(method) { proxy.analytics.trackScreen(arg.optString()) } + "analytics#addCustomEvent" -> callback.resolveResult(method) { proxy.analytics.addEvent(arg) } + "analytics#associateIdentifier" -> { + val associatedIdentifierArgs = arg.requireStringList() + proxy.analytics.associateIdentifier( + associatedIdentifierArgs[0], + associatedIdentifierArgs.getOrNull(1) + ) + } + + // Message Center + "messageCenter#getMessages" -> callback.resolveResult(method) { + JsonValue.wrapOpt(proxy.messageCenter.getMessages()) + } + "messageCenter#dismiss" -> callback.resolveResult(method) { proxy.messageCenter.dismiss() } + "messageCenter#display" -> callback.resolveResult(method) { proxy.messageCenter.display(arg.optString()) } + "messageCenter#showMessageView" -> callback.resolveResult(method) { proxy.messageCenter.showMessageView(arg.requireString()) } + "messageCenter#markMessageRead" -> callback.resolveResult(method) { proxy.messageCenter.markMessageRead(arg.requireString()) } + "messageCenter#deleteMessage" -> callback.resolveResult(method) { proxy.messageCenter.deleteMessage(arg.requireString()) } + "messageCenter#getUnreadMessageCount" -> callback.resolveResult(method) { proxy.messageCenter.getUnreadMessagesCount() } + "messageCenter#setAutoLaunch" -> callback.resolveResult(method) { proxy.messageCenter.setAutoLaunchDefaultMessageCenter(arg.requireBoolean()) } + "messageCenter#refreshMessages" -> callback.resolveDeferred(method) { resolveCallback -> + proxy.messageCenter.refreshInbox().addResultCallback { + if (it == true) { + resolveCallback(null, null) + } else { + resolveCallback(null, Exception("Failed to refresh")) + } + } + } + + // Preference Center + "preferenceCenter#display" -> callback.resolveResult(method) { proxy.preferenceCenter.displayPreferenceCenter(arg.requireString()) } + "preferenceCenter#getConfig" -> callback.resolvePending(method) { proxy.preferenceCenter.getPreferenceCenterConfig(arg.requireString()) } + "preferenceCenter#setAutoLaunch" -> callback.resolveResult(method) { + val autoLaunchArgs = arg.requireList() + proxy.preferenceCenter.setAutoLaunchPreferenceCenter( + autoLaunchArgs.get(0).requireString(), + autoLaunchArgs.get(1).getBoolean(false) + ) + } + + // Privacy Manager + "privacyManager#setEnabledFeatures" -> callback.resolveResult(method) { proxy.privacyManager.setEnabledFeatures(arg.requireStringList()) } + "privacyManager#getEnabledFeatures" -> callback.resolveResult(method) { proxy.privacyManager.getFeatureNames() } + "privacyManager#enableFeatures" -> callback.resolveResult(method) { proxy.privacyManager.enableFeatures(arg.requireStringList()) } + "privacyManager#disableFeatures" -> callback.resolveResult(method) { proxy.privacyManager.disableFeatures(arg.requireStringList()) } + "privacyManager#isFeaturesEnabled" -> callback.resolveResult(method) { proxy.privacyManager.isFeatureEnabled(arg.requireStringList()) } + + // Locale + "locale#setLocaleOverride" -> callback.resolveResult(method) { proxy.locale.setCurrentLocale(arg.requireString()) } + "locale#getCurrentLocale" -> callback.resolveResult(method) { proxy.locale.getCurrentLocale() } + "locale#clearLocaleOverride" -> callback.resolveResult(method) { proxy.locale.clearLocale() } + + // Actions + "actions#run" -> callback.resolveDeferred(method) { resolveCallback -> + val actionArgs = arg.requireList() + val name= actionArgs.get(0).requireString() + val value: JsonValue? = if (actionArgs.size() == 2) { actionArgs.get(1) } else { null } + + proxy.actions.runAction(name, value) + .addResultCallback { actionResult -> + if (actionResult != null && actionResult.status == ActionResult.STATUS_COMPLETED) { + resolveCallback(actionResult.value, null) + } else { + resolveCallback(null, Exception("Action failed ${actionResult?.status}")) + } + } + } + + // Feature Flag + "featureFlagManager#flag" -> callback.resolveDeferred(method) { resolveCallback -> + scope.launch { + try { + val flag = proxy.featureFlagManager.flag(arg.requireString()) + resolveCallback(flag, null) + } catch (e: Exception) { + resolveCallback(null, e) + } + } + } + + "featureFlagManager#trackInteraction" -> { + callback.resolveDeferred(method) { resolveCallback -> + scope.launch { + try { + val featureFlagProxy = FeatureFlagProxy(arg) + proxy.featureFlagManager.trackInteraction(flag = featureFlagProxy) + resolveCallback(null, null) + } catch (e: Exception) { + resolveCallback(null, e) + } + } + } + } + + else -> callback.error("Not implemented") + } + } +} + + +internal fun CallbackContext.resolveResult(method: String, function: () -> Any?) { + resolveDeferred(method) { callback -> callback(function(), null) } +} + +internal fun CallbackContext.error(method: String, exception: java.lang.Exception) { + this.error("AIRSHIP_ERROR(method=$method, exception=$exception)") +} + +internal fun CallbackContext.resolveDeferred(method: String, function: ((T?, Exception?) -> Unit) -> Unit) { + try { + function { result, error -> + if (error != null) { + this.error(method, error) + } else { + try { + when (result) { + is Unit -> { + this.success() + } + is Int -> { + this.success(result) + } + is String -> { + this.success(result) + } + is Boolean -> { + sendPluginResult( + PluginResult( + PluginResult.Status.OK, + result + ) + ) + } + else -> { + sendPluginResult( + JsonValue.wrap(result).pluginResult() + ) + } + } + } catch (e: Exception) { + this.error(method, e) + } + } + } + } catch (e: Exception) { + this.error(method, e) + } +} + +internal fun CallbackContext.resolvePending(method: String, function: () -> PendingResult) { + resolveDeferred(method) { callback -> + function().addResultCallback { + callback(it, null) + } + } +} + +internal fun JsonValue.requireBoolean(): Boolean { + require(this.isBoolean) + return this.getBoolean(false) +} + +internal fun JsonValue.requireStringList(): List { + return this.requireList().list.map { it.requireString() } +} + +internal fun JsonValue.requireInt(): Int { + require(this.isInteger) + return this.getInt(0) +} + +internal fun JsonSerializable.pluginResult(): PluginResult { + val json = this.toJsonValue() + + return when { + json.isNull -> PluginResult(PluginResult.Status.OK) + json.isString -> PluginResult(PluginResult.Status.OK, json.requireString()) + json.isBoolean -> PluginResult(PluginResult.Status.OK, json.requireBoolean()) + json.isInteger -> PluginResult(PluginResult.Status.OK, json.getInt(0)) + json.isNumber -> PluginResult(PluginResult.Status.OK, json.getFloat(0F)) + json.isJsonList -> { + PluginResult(PluginResult.Status.OK, json.requireList().toJSONArray()) + } + json.isJsonMap -> { + PluginResult(PluginResult.Status.OK, json.requireMap().toJSONObject()) + } + + else -> PluginResult(PluginResult.Status.OK, json.toString()) + } +} + +internal fun JsonList.toJSONArray(): JSONArray { + val array = JSONArray() + this.forEach { + array.put(it.toCordovaJSON()) + } + return array +} + +internal fun JsonMap.toJSONObject(): JSONObject { + return JSONObject(map.mapValues { it.value.toCordovaJSON() }) +} + +internal fun JsonSerializable.toCordovaJSON(): Any? { + val json = this.toJsonValue() + return when { + json.isNull -> null + json.isJsonList -> json.requireList().toJSONArray() + json.isJsonMap -> json.requireMap().toJSONObject() + else -> json.value + } +} diff --git a/cordova-airship/src/android/AirshipCordovaVersion.kt b/cordova-airship/src/android/AirshipCordovaVersion.kt new file mode 100644 index 00000000..ebdb0a3e --- /dev/null +++ b/cordova-airship/src/android/AirshipCordovaVersion.kt @@ -0,0 +1,7 @@ +/* Copyright Urban Airship and Contributors */ + +package com.urbanairship.cordova + +object AirshipCordovaVersion { + var version = "15.0.0" +} \ No newline at end of file diff --git a/cordova-airship/src/android/CordovaAutopilot.kt b/cordova-airship/src/android/CordovaAutopilot.kt new file mode 100644 index 00000000..f21ffbdc --- /dev/null +++ b/cordova-airship/src/android/CordovaAutopilot.kt @@ -0,0 +1,103 @@ +/* Copyright Urban Airship and Contributors */ + +package com.urbanairship.cordova + +import android.content.Context +import android.content.SharedPreferences +import android.util.Log +import androidx.core.app.NotificationManagerCompat +import androidx.core.content.edit +import com.urbanairship.AirshipConfigOptions +import com.urbanairship.UAirship +import com.urbanairship.analytics.Analytics +import com.urbanairship.android.framework.proxy.BaseAutopilot +import com.urbanairship.android.framework.proxy.ProxyStore + +class CordovaAutopilot : BaseAutopilot() { + + companion object { + private const val PREFERENCE_FILE = "com.urbanairship.ua_plugin_shared_preferences" + private const val PROCESSED_NOTIFICATIONS_OPTED_OUT_FLAG = "com.urbanairship.PROCESSED_NOTIFICATIONS_OPTED_OUT_FLAG" + } + + private var _settings: CordovaSettings? = null + private fun settings(context: Context): CordovaSettings { + return _settings ?: CordovaSettings.fromConfig(context).also { _settings = it } + } + + private var _preferences: SharedPreferences? = null + private fun preferences(context: Context): SharedPreferences { + return _preferences ?: context.getSharedPreferences( + PREFERENCE_FILE, + Context.MODE_PRIVATE + ).also { _preferences = it } + } + + override fun onAirshipReady(airship: UAirship) { + super.onAirshipReady(airship) + + val context = UAirship.getApplicationContext() + + Log.i("CordovaAutopilot", "onAirshipReady") + + airship.analytics.registerSDKExtension(Analytics.EXTENSION_CORDOVA, AirshipCordovaVersion.version); + val settings = settings(context) + val preferences = preferences(context) + + settings.disableNotificationsOnOptOut?.let { + if (!NotificationManagerCompat.from(context).areNotificationsEnabled()) { + when (it) { + CordovaSettings.OptOutFrequency.ALWAYS -> { + airship.pushManager.userNotificationsEnabled = false + } + + CordovaSettings.OptOutFrequency.ONCE -> { + if (!preferences.getBoolean(PROCESSED_NOTIFICATIONS_OPTED_OUT_FLAG, false)) { + airship.pushManager.userNotificationsEnabled = false + } + } + } + } + preferences.edit { putBoolean(PROCESSED_NOTIFICATIONS_OPTED_OUT_FLAG, true) } + } + + if (settings.enablePushOnLaunch == true) { + airship.pushManager.userNotificationsEnabled = true + } + } + + override fun onMigrateData(context: Context, proxyStore: ProxyStore) { + val settings = settings(context) + ProxyDataMigrator(preferences(context)).migrate(proxyStore, settings) + proxyStore.defaultAutoLaunchMessageCenter = settings.autoLaunchMessageCenter ?: true + } + + override fun createConfigBuilder(context: Context): AirshipConfigOptions.Builder { + return super.createConfigBuilder(context).also { builder -> + val settings = settings(context) + + if (settings.developmentAppKey != null && settings.developmentAppSecret != null) { + builder.setDevelopmentAppKey(settings.developmentAppKey) + builder.setDevelopmentAppSecret(settings.developmentAppSecret) + } + + if (settings.productionAppKey != null && settings.productionAppSecret != null) { + builder.setProductionAppKey(settings.productionAppKey) + builder.setProductionAppSecret(settings.productionAppSecret) + } + + settings.developmentLogLevel?.apply { builder.setDevelopmentLogLevel(this) } + settings.productionLogLevel?.apply { builder.setProductionLogLevel(this) } + settings.inProduction?.apply { builder.setInProduction(this) } + settings.enableAnalytics?.apply { builder.setAnalyticsEnabled(this) } + settings.cloudSite?.apply { builder.setSite(this) } + settings.defaultChannelId?.apply { builder.setNotificationChannel(this) } + settings.fcmFirebaseAppName?.apply { builder.setFcmFirebaseAppName(this) } + settings.initialConfigUrl?.apply { builder.setInitialConfigUrl(this) } + + settings.notificationIcon?.apply { builder.setNotificationIcon(this) } + settings.notificationLargeIcon?.apply { builder.setNotificationLargeIcon(this) } + settings.notificationAccentColor?.apply { builder.setNotificationAccentColor(this) } + } + } +} \ No newline at end of file diff --git a/cordova-airship/src/android/CordovaSettings.kt b/cordova-airship/src/android/CordovaSettings.kt new file mode 100644 index 00000000..61d54538 --- /dev/null +++ b/cordova-airship/src/android/CordovaSettings.kt @@ -0,0 +1,179 @@ +/* Copyright Urban Airship and Contributors */ + +package com.urbanairship.cordova + +import android.content.Context +import android.content.res.XmlResourceParser +import android.graphics.Color +import android.util.Log +import androidx.annotation.ColorInt +import com.urbanairship.AirshipConfigOptions +import com.urbanairship.UALog + +internal data class CordovaSettings( + val cloudSite: String?, + val productionAppKey: String?, + val productionAppSecret: String?, + val productionLogLevel: Int?, + val developmentAppKey: String?, + val developmentAppSecret: String?, + val developmentLogLevel: Int?, + val autoLaunchMessageCenter: Boolean?, + val enablePushOnLaunch: Boolean?, + val enableAnalytics: Boolean?, + val notificationIcon: Int?, + val notificationLargeIcon: Int?, + val notificationAccentColor: Int?, + val inProduction: Boolean?, + val fcmFirebaseAppName: String?, + val initialConfigUrl: String?, + val defaultChannelId: String?, + val disableNotificationsOnOptOut: OptOutFrequency? +) { + + enum class OptOutFrequency { + ALWAYS, ONCE + } + + companion object { + private const val UA_PREFIX = "com.urbanairship" + + private const val PRODUCTION_KEY = "com.urbanairship.production_app_key" + private const val PRODUCTION_SECRET = "com.urbanairship.production_app_secret" + private const val DEVELOPMENT_KEY = "com.urbanairship.development_app_key" + private const val DEVELOPMENT_SECRET = "com.urbanairship.development_app_secret" + + private const val NOTIFICATION_ICON = "com.urbanairship.notification_icon" + private const val NOTIFICATION_LARGE_ICON = "com.urbanairship.notification_large_icon" + private const val NOTIFICATION_ACCENT_COLOR = "com.urbanairship.notification_accent_color" + private const val DEFAULT_NOTIFICATION_CHANNEL_ID = "com.urbanairship.default_notification_channel_id" + + private const val AUTO_LAUNCH_MESSAGE_CENTER = "com.urbanairship.auto_launch_message_center" + + private const val PRODUCTION_LOG_LEVEL = "com.urbanairship.production_log_level" + private const val DEVELOPMENT_LOG_LEVEL = "com.urbanairship.development_log_level" + private const val IN_PRODUCTION = "com.urbanairship.in_production" + + private const val ENABLE_PUSH_ONLAUNCH = "com.urbanairship.enable_push_onlaunch" + + private const val DISABLE_ANDROID_NOTIFICATIONS_ON_OPT_OUT = "com.urbanairship.android.disable_user_notifications_on_system_opt_out" + + private const val ENABLE_ANALYTICS = "com.urbanairship.enable_analytics" + + private const val CLOUD_SITE = "com.urbanairship.site" + private const val FCM_FIREBASE_APP_NAME = "com.urbanairship.fcm_firebase_app_name" + private const val INITIAL_CONFIG_URL = "com.urbanairship.initial_config_url" + + fun fromConfig(context: Context): CordovaSettings { + val config = parseConfigXml(context) + return CordovaSettings( + cloudSite = parseCloudSite(config[CLOUD_SITE]), + productionAppKey = config[PRODUCTION_KEY], + productionAppSecret = config[PRODUCTION_SECRET], + productionLogLevel = parseLogLevel(config[PRODUCTION_LOG_LEVEL]), + developmentAppKey = config[DEVELOPMENT_KEY], + developmentAppSecret = config[DEVELOPMENT_SECRET], + developmentLogLevel = parseLogLevel(config[DEVELOPMENT_LOG_LEVEL]), + autoLaunchMessageCenter = config[AUTO_LAUNCH_MESSAGE_CENTER]?.toBoolean(), + enablePushOnLaunch = config[ENABLE_PUSH_ONLAUNCH]?.toBoolean(), + enableAnalytics = config[ENABLE_ANALYTICS]?.toBoolean(), + notificationIcon = parseIcon(context, config[NOTIFICATION_ICON]), + notificationLargeIcon = parseIcon(context, config[NOTIFICATION_LARGE_ICON]), + notificationAccentColor = parseColor(config[NOTIFICATION_ACCENT_COLOR]), + inProduction = config[IN_PRODUCTION]?.toBoolean(), + fcmFirebaseAppName = config[FCM_FIREBASE_APP_NAME], + initialConfigUrl = config[INITIAL_CONFIG_URL], + defaultChannelId = config[DEFAULT_NOTIFICATION_CHANNEL_ID], + disableNotificationsOnOptOut = parseFrequency(config[DISABLE_ANDROID_NOTIFICATIONS_ON_OPT_OUT]) + ) + } + + private fun parseFrequency(value: String?): OptOutFrequency? { + if (value.isNullOrEmpty()) { return null } + try { + return OptOutFrequency.valueOf(value.uppercase()) + } catch(e: IllegalArgumentException) { + UALog.e("Invalid frequency $value", e) + return null + } + } + + private fun parseLogLevel(logLevel: String?): Int? { + if (logLevel.isNullOrEmpty()) { return null } + return when (logLevel.lowercase()) { + "verbose" -> Log.VERBOSE + "debug" -> Log.DEBUG + "info" -> Log.INFO + "warn" -> Log.WARN + "error" -> Log.ERROR + "none" -> Log.ASSERT + else -> { + UALog.e("Unexpected log level $logLevel") + null + } + } + } + + @AirshipConfigOptions.Site + private fun parseCloudSite(site: String?): String? { + if (site.isNullOrEmpty()) { return null } + return when (site.uppercase()) { + AirshipConfigOptions.SITE_EU -> AirshipConfigOptions.SITE_EU + AirshipConfigOptions.SITE_US -> AirshipConfigOptions.SITE_US + else -> { + UALog.e("Unexpected site $site") + null + } + } + } + + private fun parseIcon(context: Context, name: String?): Int? { + if (name.isNullOrEmpty()) { return null } + val id = context.resources.getIdentifier(name, "drawable", context.packageName) + return if (id != 0) { + id + } else { + UALog.e("Unable to find drawable with name: $name") + null + } + } + + @ColorInt + private fun parseColor(color: String?): Int? { + if (color.isNullOrEmpty()) { return null } + return try { + Color.parseColor(color) + } catch (e: IllegalArgumentException) { + UALog.e(e) { "Unable to parse color: $color" } + null + } + } + + private fun parseConfigXml(context: Context): Map { + val config: MutableMap = HashMap() + val id = context.resources.getIdentifier("config", "xml", context.packageName) + if (id == 0) { + return config + } + val xml = context.resources.getXml(id) + var eventType = -1 + while (eventType != XmlResourceParser.END_DOCUMENT) { + if (eventType == XmlResourceParser.START_TAG) { + if (xml.name == "preference") { + val name = xml.getAttributeValue(null, "name").lowercase() + val value = xml.getAttributeValue(null, "value") + if (name.startsWith(UA_PREFIX) && value != null) { + config[name] = value.trim() + } + } + } + try { + eventType = xml.next() + } catch (e: Exception) { + UALog.e(e) { "Error parsing config file" } + } + } + return config + } + } +} diff --git a/cordova-airship/src/android/ProxyDataMigrator.kt b/cordova-airship/src/android/ProxyDataMigrator.kt new file mode 100644 index 00000000..29a0687c --- /dev/null +++ b/cordova-airship/src/android/ProxyDataMigrator.kt @@ -0,0 +1,143 @@ +/* Copyright Urban Airship and Contributors */ + +package com.urbanairship.cordova + +import android.content.SharedPreferences +import androidx.core.content.edit +import com.urbanairship.android.framework.proxy.NotificationConfig +import com.urbanairship.android.framework.proxy.ProxyConfig +import com.urbanairship.android.framework.proxy.ProxyStore + +internal class ProxyDataMigrator(private val preferences: SharedPreferences) { + + companion object { + private const val PRODUCTION_KEY = "com.urbanairship.production_app_key" + private const val PRODUCTION_SECRET = "com.urbanairship.production_app_secret" + private const val DEVELOPMENT_KEY = "com.urbanairship.development_app_key" + private const val DEVELOPMENT_SECRET = "com.urbanairship.development_app_secret" + + private const val DEFAULT_NOTIFICATION_CHANNEL_ID = "com.urbanairship.default_notification_channel_id" + private const val AUTO_LAUNCH_MESSAGE_CENTER = "com.urbanairship.auto_launch_message_center" + + private const val NOTIFICATION_ICON = "com.urbanairship.notification_icon" + private const val NOTIFICATION_LARGE_ICON = "com.urbanairship.notification_large_icon" + private const val NOTIFICATION_ACCENT_COLOR = "com.urbanairship.notification_accent_color" + + private const val PREFERENCE_CENTER_PREFIX = "preference_" + private const val PREFERENCE_CENTER_SUFFIX = "_use_custom_ui" + + private const val FOREGROUND_NOTIFICATIONS = "com.urbanairship.foreground_notifications" + + } + + internal fun migrate(store: ProxyStore, settings: CordovaSettings) { + migrateAppConfig(store, settings) + migrateAutoLaunchMessageCenter(store) + migrateShowForegroundNotifications(store) + migrateNotificationConfig(store) + migrateAutoLaunchPreferenceCenter(store) + } + + private fun migrateAppConfig(store: ProxyStore, settings: CordovaSettings) { + val productionAppKey = preferences.getString(PRODUCTION_KEY, null) + val productionAppSecret = preferences.getString(PRODUCTION_SECRET, null) + val developmentAppKey = preferences.getString(DEVELOPMENT_KEY, null) + val developmentAppSecret = preferences.getString(DEVELOPMENT_SECRET, null) + + var production: ProxyConfig.Environment? = null + if (productionAppKey != null && productionAppSecret != null) { + production = ProxyConfig.Environment( + appKey = productionAppKey, + appSecret = productionAppSecret, + logLevel = settings.productionLogLevel + ) + } + + var development: ProxyConfig.Environment? = null + if (developmentAppKey != null && developmentAppSecret != null) { + development = ProxyConfig.Environment( + appKey = productionAppKey, + appSecret = productionAppSecret, + logLevel = settings.productionLogLevel + ) + } + + if (development != null || production != null) { + store.airshipConfig = ProxyConfig( + productionEnvironment = production, + developmentEnvironment = development + ) + + preferences.edit { + this.remove(DEVELOPMENT_KEY) + this.remove(DEVELOPMENT_SECRET) + this.remove(PRODUCTION_KEY) + this.remove(PRODUCTION_SECRET) + } + } + } + + private fun migrateAutoLaunchMessageCenter(store: ProxyStore) { + if (!preferences.contains(AUTO_LAUNCH_MESSAGE_CENTER)) { + return + } + + store.isAutoLaunchMessageCenterEnabled = preferences.getBoolean(AUTO_LAUNCH_MESSAGE_CENTER, true) + preferences.edit { this.remove(AUTO_LAUNCH_MESSAGE_CENTER) } + } + + private fun migrateShowForegroundNotifications(store: ProxyStore) { + if (!preferences.contains(FOREGROUND_NOTIFICATIONS)) { + return + } + + store.isForegroundNotificationsEnabled = preferences.getBoolean(FOREGROUND_NOTIFICATIONS, true) + preferences.edit { this.remove(FOREGROUND_NOTIFICATIONS) } + } + + private fun migrateNotificationConfig(store: ProxyStore) { + val icon = preferences.getString(NOTIFICATION_ICON, null) + val largeIcon = preferences.getString(NOTIFICATION_LARGE_ICON, null) + val accentColor = preferences.getString(NOTIFICATION_ACCENT_COLOR, null) + val defaultChannelId = preferences.getString(DEFAULT_NOTIFICATION_CHANNEL_ID, null) + + if (icon != null || largeIcon != null || accentColor != null || defaultChannelId != null) { + store.notificationConfig = NotificationConfig( + icon = icon, + largeIcon = largeIcon, + accentColor = accentColor, + defaultChannelId = defaultChannelId + ) + } + + preferences.edit { + this.remove(NOTIFICATION_ICON) + this.remove(NOTIFICATION_LARGE_ICON) + this.remove(NOTIFICATION_ACCENT_COLOR) + this.remove(DEFAULT_NOTIFICATION_CHANNEL_ID) + } + } + + private fun migrateAutoLaunchPreferenceCenter(store: ProxyStore) { + val keysToRemove = mutableListOf() + // Preference Center + preferences.all.filter { + it.key.startsWith(PREFERENCE_CENTER_PREFIX) + }.mapValues { + if (it.value is Boolean) { it.value as Boolean } else { false } + }.forEach { + val preferenceCenterId = it.key + .removePrefix(PREFERENCE_CENTER_PREFIX) + .removeSuffix(PREFERENCE_CENTER_SUFFIX) + + store.setAutoLaunchPreferenceCenter(preferenceCenterId, !it.value) + keysToRemove.add(it.key) + } + + if (keysToRemove.isNotEmpty()) { + preferences.edit { + keysToRemove.forEach { this.remove(it) } + } + } + } +} \ No newline at end of file diff --git a/urbanairship-accengage-cordova/src/android/build-extras.gradle b/cordova-airship/src/android/build-extras.gradle similarity index 76% rename from urbanairship-accengage-cordova/src/android/build-extras.gradle rename to cordova-airship/src/android/build-extras.gradle index e992c844..e037ae19 100644 --- a/urbanairship-accengage-cordova/src/android/build-extras.gradle +++ b/cordova-airship/src/android/build-extras.gradle @@ -1,11 +1,11 @@ dependencies { - implementation 'com.urbanairship.android:urbanairship-accengage:16.11.1' + api "com.urbanairship.android:airship-framework-proxy:5.2.1" } cdvPluginPostBuildExtras.push({ android { compileSdkVersion 33 - + compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 diff --git a/cordova-airship/src/ios/AirshipCordova-Bridging-Header.h b/cordova-airship/src/ios/AirshipCordova-Bridging-Header.h new file mode 100644 index 00000000..d63dd7c2 --- /dev/null +++ b/cordova-airship/src/ios/AirshipCordova-Bridging-Header.h @@ -0,0 +1,2 @@ +#import +#import "AirshipCordovaBootstrap.h" diff --git a/cordova-airship/src/ios/AirshipCordova.swift b/cordova-airship/src/ios/AirshipCordova.swift new file mode 100644 index 00000000..79a157ca --- /dev/null +++ b/cordova-airship/src/ios/AirshipCordova.swift @@ -0,0 +1,705 @@ +/* Copyright Airship and Contributors */ + +import Foundation +import AirshipKit +import AirshipFrameworkProxy + +@objc +public final class AirshipCordova: CDVPlugin { + + struct Listener { + let callbackID: String + let listenerID: Int + } + + @MainActor + private var eventListeners: [AirshipProxyEventType: [Listener]] = [:] + + private static let eventNames: [AirshipProxyEventType: String] = [ + .authorizedNotificationSettingsChanged: "airship.event.ios_authorized_notification_settings_changed", + .pushTokenReceived: "airship.event.push_token_received", + .deepLinkReceived: "airship.event.deep_link_received", + .channelCreated: "airship.event.channel_created", + .messageCenterUpdated: "airship.event.message_center_updated", + .displayMessageCenter: "airship.event.display_message_center", + .displayPreferenceCenter: "airship.event.display_preference_center", + .notificationResponseReceived: "airship.event.notification_response", + .pushReceived: "airship.event.push_received", + .notificationStatusChanged: "airship.event.notification_status_changed" + ] + + @MainActor + public override func pluginInitialize() { + let settings = AirshipCordovaPluginSettings.from( + settings: self.commandDelegate.settings + ) + + AirshipCordovaAutopilot.shared.pluginInitialized(settings: settings) + + Task { + for await _ in await AirshipProxyEventEmitter.shared.pendingEventAdded { + await self.notifyPendingEvents() + } + } + } + + @objc + @MainActor + func removeListener(_ command: CDVInvokedUrlCommand) { + guard + command.arguments.count == 2, + let listenerID = command.arguments.last as? NSNumber, + let eventName = command.arguments.first as? String + else { + AirshipLogger.error("Failed to add listener, invalid command \(command)") + return + } + + guard + let eventType = Self.eventNames.first(where: { key, value in + value == eventName + })?.key + else { + AirshipLogger.error("Failed to add listener, invalid name \(eventName)") + return + } + + self.eventListeners[eventType]?.removeAll(where: { listener in + listener.listenerID == listenerID.intValue + }) + } + + @objc + @MainActor + func addListener(_ command: CDVInvokedUrlCommand) { + guard + let callbackID = command.callbackId, + command.arguments.count == 2, + let listenerID = command.arguments.last as? NSNumber, + let eventName = command.arguments.first as? String + else { + AirshipLogger.error("Failed to add listener, invalid command \(command)") + return + } + + guard + let eventType = Self.eventNames.first(where: { key, value in + value == eventName + })?.key + else { + AirshipLogger.error("Failed to add listener, invalid name \(eventName)") + return + } + + if self.eventListeners[eventType] == nil { + self.eventListeners[eventType] = [] + } + + self.eventListeners[eventType]?.append( + Listener(callbackID: callbackID, listenerID: listenerID.intValue) + ) + + Task { + await notifyPendingEvents() + } + } + + @MainActor + private func notifyPendingEvents() async { + let listeners = self.eventListeners + + for eventType in AirshipProxyEventType.allCases { + await AirshipProxyEventEmitter.shared.sendPendingEvents( + eventType: eventType, + listeners: listeners[eventType], + commandDelegate: self.commandDelegate + ) + } + } + + @objc + func perform(_ command: CDVInvokedUrlCommand) { + Task { + do { + let result = try await self.handle(command: command) + let pluginResult = try self.successResult(value: result) + self.commandDelegate?.send(pluginResult, callbackId: command.callbackId) + } catch { + let pluginResult = CDVPluginResult(status: CDVCommandStatus_ERROR, messageAs: error.localizedDescription) + self.commandDelegate?.send(pluginResult, callbackId: command.callbackId) + } + } + } + + private func successResult(value: Any?, fallbackJSON: Bool = true) throws -> CDVPluginResult { + guard let value = value else { + return CDVPluginResult(status: CDVCommandStatus_OK) + } + + if let string = value as? String { + return CDVPluginResult(status: CDVCommandStatus_OK, messageAs: string) + } + + if let bool = value as? Bool { + return CDVPluginResult(status: CDVCommandStatus_OK, messageAs: bool) + } + + if let int = value as? Int { + return CDVPluginResult(status: CDVCommandStatus_OK, messageAs: int) + } + + if let int = value as? UInt { + return CDVPluginResult(status: CDVCommandStatus_OK, messageAs: int) + } + + if let number = value as? NSNumber { + return CDVPluginResult(status: CDVCommandStatus_OK, messageAs: number.doubleValue) + } + + if let array = value as? Array { + return CDVPluginResult( + status: CDVCommandStatus_OK, + messageAs: try AirshipJSON.wrap(array).unWrap() as? Array + ) + } + + if let dictionary = value as? [String: Any] { + return CDVPluginResult( + status: CDVCommandStatus_OK, + messageAs: try AirshipJSON.wrap(dictionary).unWrap() as? [String: Any] + ) + } + + if fallbackJSON { + return try successResult(value: try AirshipJSON.wrap(value).unWrap(), fallbackJSON: false) + } else { + throw AirshipErrors.error("Invalid result \(value)") + } + } + + @MainActor + private func handle(command: CDVInvokedUrlCommand) async throws -> Any? { + guard let method = command.arguments[0] as? String else { + throw AirshipErrors.error("Invalid command \(command)") + } + + switch method { + + // Airship + case "takeOff": + return try AirshipCordovaAutopilot.shared.attemptTakeOff( + json: try command.requireAnyArg() + ) + + case "isFlying": + return AirshipProxy.shared.isFlying() + + // Channel + case "channel#getChannelId": + return try AirshipProxy.shared.channel.getChannelId() + + case "channel#editTags": + try AirshipProxy.shared.channel.editTags( + json: try command.requireAnyArg() + ) + return nil + + case "channel#getTags": + return try AirshipProxy.shared.channel.getTags() + + case "channel#editTagGroups": + try AirshipProxy.shared.channel.editTagGroups( + json: try command.requireAnyArg() + ) + return nil + + case "channel#editSubscriptionLists": + try AirshipProxy.shared.channel.editSubscriptionLists( + json: try command.requireAnyArg() + ) + return nil + + case "channel#editAttributes": + try AirshipProxy.shared.channel.editAttributes( + json: try command.requireAnyArg() + ) + return nil + + case "channel#getSubscriptionLists": + return try await AirshipProxy.shared.channel.getSubscriptionLists() + + case "channel#enableChannelCreation": + return try AirshipProxy.shared.channel.enableChannelCreation() + return nil + + // Contact + case "contact#editTagGroups": + try AirshipProxy.shared.contact.editTagGroups( + json: try command.requireAnyArg() + ) + return nil + + case "contact#editSubscriptionLists": + try AirshipProxy.shared.contact.editSubscriptionLists( + json: try command.requireAnyArg() + ) + return nil + + case "contact#editAttributes": + try AirshipProxy.shared.contact.editAttributes( + json: try command.requireAnyArg() + ) + return nil + + case "contact#getSubscriptionLists": + return try await AirshipProxy.shared.contact.getSubscriptionLists() + + case "contact#identify": + try AirshipProxy.shared.contact.identify( + try command.requireStringArg() + ) + return nil + + case "contact#reset": + try AirshipProxy.shared.contact.reset() + return nil + + case "contact#notifyRemoteLogin": + try AirshipProxy.shared.contact.notifyRemoteLogin() + return nil + + case "contact#getNamedUserId": + return try await AirshipProxy.shared.contact.getNamedUser() + + + // Push + case "push#getPushToken": + return try AirshipProxy.shared.push.getRegistrationToken() + + case "push#setUserNotificationsEnabled": + try AirshipProxy.shared.push.setUserNotificationsEnabled( + try command.requireBooleanArg() + ) + return nil + + case "push#enableUserNotifications": + return try await AirshipProxy.shared.push.enableUserPushNotifications() + + case "push#isUserNotificationsEnabled": + return try AirshipProxy.shared.push.isUserNotificationsEnabled() + + case "push#getNotificationStatus": + return try await AirshipProxy.shared.push.getNotificationStatus() + + case "push#getActiveNotifications": + return await AirshipProxy.shared.push.getActiveNotifications() + + case "push#clearNotification": + AirshipProxy.shared.push.clearNotification( + try command.requireStringArg() + ) + return nil + + case "push#clearNotifications": + AirshipProxy.shared.push.clearNotifications() + return nil + + case "push#ios#getBadgeNumber": + return try AirshipProxy.shared.push.getBadgeNumber() + + case "push#ios#setBadgeNumber": + try AirshipProxy.shared.push.setBadgeNumber( + try command.requireIntArg() + ) + return nil + + case "push#ios#setAutobadgeEnabled": + try AirshipProxy.shared.push.setAutobadgeEnabled( + try command.requireBooleanArg() + ) + return nil + + case "push#ios#isAutobadgeEnabled": + return try AirshipProxy.shared.push.isAutobadgeEnabled() + + case "push#ios#resetBadgeNumber": + try AirshipProxy.shared.push.setBadgeNumber(0) + return nil + + case "push#ios#setNotificationOptions": + try AirshipProxy.shared.push.setNotificationOptions( + names: try command.requireStringArrayArg() + ) + return nil + + case "push#ios#setForegroundPresentationOptions": + try AirshipProxy.shared.push.setForegroundPresentationOptions( + names: try command.requireStringArrayArg() + ) + return nil + + case "push#ios#getAuthorizedNotificationStatus": + return try AirshipProxy.shared.push.getAuthroizedNotificationStatus() + + case "push#ios#getAuthorizedNotificationSettings": + return try AirshipProxy.shared.push.getAuthorizedNotificationSettings() + + case "push#ios#setQuietTimeEnabled": + try AirshipProxy.shared.push.setQuietTimeEnabled( + try command.requireBooleanArg() + ) + return nil + + case "push#ios#isQuietTimeEnabled": + return try AirshipProxy.shared.push.isQuietTimeEnabled() + + case "push#ios#setQuietTime": + try AirshipProxy.shared.push.setQuietTime( + try command.requireCodableArg() + ) + return nil + + case "push#ios#getQuietTime": + return try AirshipProxy.shared.push.getQuietTime() + + // In-App + case "inApp#setPaused": + try AirshipProxy.shared.inApp.setPaused( + try command.requireBooleanArg() + ) + return nil + + case "inApp#isPaused": + return try AirshipProxy.shared.inApp.isPaused() + + case "inApp#setDisplayInterval": + try AirshipProxy.shared.inApp.setDisplayInterval( + try command.requireIntArg() + ) + return nil + + case "inApp#getDisplayInterval": + return try AirshipProxy.shared.inApp.getDisplayInterval() + + // Analytics + case "analytics#trackScreen": + try AirshipProxy.shared.analytics.trackScreen( + try? command.requireStringArg() + ) + return nil + + case "analytics#addCustomEvent": + try AirshipProxy.shared.analytics.addEvent( + command.requireAnyArg() + ) + return nil + + case "analytics#associateIdentifier": + let args = try command.requireStringArrayArg() + guard args.count == 1 || args.count == 2 else { + throw AirshipErrors.error("Call requires 1 to 2 strings.") + } + try AirshipProxy.shared.analytics.associateIdentifier( + identifier: args.count == 2 ? args[1] : nil, + key: args[0] + ) + return nil + + // Message Center + case "messageCenter#getMessages": + return try? await AirshipProxy.shared.messageCenter.getMessages() + + case "messageCenter#display": + try AirshipProxy.shared.messageCenter.display( + messageID: try? command.requireStringArg() + ) + return nil + + case "messageCenter#showMessageView": + try AirshipProxy.shared.messageCenter.showMessageView( + messageID: try command.requireStringArg() + ) + return nil + + case "messageCenter#dismiss": + try AirshipProxy.shared.messageCenter.dismiss() + return nil + + case "messageCenter#markMessageRead": + try await AirshipProxy.shared.messageCenter.markMessageRead( + messageID: command.requireStringArg() + ) + return nil + + case "messageCenter#deleteMessage": + try await AirshipProxy.shared.messageCenter.deleteMessage( + messageID: command.requireStringArg() + ) + return nil + + case "messageCenter#getUnreadMessageCount": + return try await AirshipProxy.shared.messageCenter.getUnreadCount() + + case "messageCenter#refreshMessages": + try await AirshipProxy.shared.messageCenter.refresh() + return nil + + case "messageCenter#setAutoLaunch": + AirshipProxy.shared.messageCenter.setAutoLaunchDefaultMessageCenter( + try command.requireBooleanArg() + ) + return nil + + // Preference Center + case "preferenceCenter#display": + try AirshipProxy.shared.preferenceCenter.displayPreferenceCenter( + preferenceCenterID: try command.requireStringArg() + ) + return nil + + case "preferenceCenter#getConfig": + return try await AirshipProxy.shared.preferenceCenter.getPreferenceCenterConfig( + preferenceCenterID: try command.requireStringArg() + ) + + case "preferenceCenter#setAutoLaunch": + let args = try command.requireArrayArg() + guard + args.count == 2, + let identifier = args[0] as? String, + let autoLaunch = args[1] as? Bool + else { + throw AirshipErrors.error("Call requires [String, Bool]") + } + + AirshipProxy.shared.preferenceCenter.setAutoLaunchPreferenceCenter( + autoLaunch, + preferenceCenterID: identifier + ) + return nil + + // Privacy Manager + case "privacyManager#setEnabledFeatures": + try AirshipProxy.shared.privacyManager.setEnabled( + featureNames: try command.requireStringArrayArg() + ) + return nil + + case "privacyManager#getEnabledFeatures": + return try AirshipProxy.shared.privacyManager.getEnabledNames() + + case "privacyManager#enableFeatures": + try AirshipProxy.shared.privacyManager.enable( + featureNames: try command.requireStringArrayArg() + ) + return nil + + case "privacyManager#disableFeatures": + try AirshipProxy.shared.privacyManager.disable( + featureNames: try command.requireStringArrayArg() + ) + return nil + + case "privacyManager#isFeaturesEnabled": + return try AirshipProxy.shared.privacyManager.isEnabled( + featuresNames: try command.requireStringArrayArg() + ) + + // Locale + case "locale#setLocaleOverride": + try AirshipProxy.shared.locale.setCurrentLocale( + try command.requireStringArg() + ) + return nil + + case "locale#clearLocaleOverride": + try AirshipProxy.shared.locale.clearLocale() + return nil + + case "locale#getCurrentLocale": + return try AirshipProxy.shared.locale.getCurrentLocale() + + // Actions + case "actions#run": + let args = try command.requireArrayArg() + guard + args.count == 1 || args.count == 2, + let actionName = args[0] as? String + else { + throw AirshipErrors.error("Call requires [String, Any?]") + } + + let arg = try? AirshipJSON.wrap(args[1]) + let result = try await AirshipProxy.shared.action.runAction( + actionName, + value: args.count == 2 ? arg : nil + ) as? AirshipJSON + return result?.unWrap() + + // Feature Flag + case "featureFlagManager#flag": + return try await AirshipProxy.shared.featureFlagManager.flag( + name: try command.requireStringArg() + ) + + case "featureFlagManager#trackInteraction": + try AirshipProxy.shared.featureFlagManager.trackInteraction( + flag: command.requireCodableArg() + ) + + return nil + default: + throw AirshipErrors.error("Unavailable command \(method)") + } + } +} + + +extension CDVInvokedUrlCommand { + + func requireCodableArg() throws -> T { + guard + self.arguments.count >= 2 + else { + throw AirshipErrors.error("Missing argument") + } + + return try AirshipJSON.wrap(self.arguments[1]).decode() + } + + func requireArrayArg() throws -> [Any] { + guard + self.arguments.count >= 2, + let args = self.arguments[1] as? [Any] + else { + throw AirshipErrors.error("Argument must be an array") + } + + return args + } + + func requireArrayArg(count: UInt, parse: (Any) throws -> T) throws -> [T] { + guard + self.arguments.count >= 2, + let args = self.arguments[1] as? [Any], + args.count == count + else { + throw AirshipErrors.error("Invalid argument array") + } + + return try args.map { try parse($0) } + } + + + func requireStringArrayArg() throws -> [String] { + guard + self.arguments.count >= 2, + let args = self.arguments[1] as? [String] + else { + throw AirshipErrors.error("Argument must be a string array") + } + + return args + } + + func requireAnyArg() throws -> Any { + guard + self.arguments.count >= 2 + else { + throw AirshipErrors.error("Argument must not be null") + } + + return self.arguments[1] + } + + func requireBooleanArg() throws -> Bool { + guard + self.arguments.count >= 2, + let args = self.arguments[1] as? Bool + else { + throw AirshipErrors.error("Argument must be a boolean") + } + + return args + } + + func requireStringArg() throws -> String { + + guard + self.arguments.count >= 2, + let args = self.arguments[1] as? String + else { + throw AirshipErrors.error("Argument must be a string") + } + + return args + } + + func requireIntArg() throws -> Int { + let value = try requireAnyArg() + + if let int = value as? Int { + return int + } + + if let double = value as? Double { + return Int(double) + } + + if let number = value as? NSNumber { + return number.intValue + } + + throw AirshipErrors.error("Argument must be an int") + } + + func requireDoubleArg() throws -> Double { + let value = try requireAnyArg() + + + if let double = value as? Double { + return double + } + + if let int = value as? Int { + return Double(int) + } + + if let number = value as? NSNumber { + return number.doubleValue + } + + + throw AirshipErrors.error("Argument must be a double") + } +} + +extension AirshipProxyEventEmitter { + func sendPendingEvents( + eventType: AirshipProxyEventType, + listeners: [AirshipCordova.Listener]?, + commandDelegate: CDVCommandDelegate? + ) { + guard + let commandDelegate = commandDelegate, + let listeners = listeners, + listeners.count > 0 + else { + return + } + + self.processPendingEvents(type: eventType) { event in + let result = CDVPluginResult( + status: CDVCommandStatus_OK, + messageAs: event.body + ) + result?.keepCallback = true + + listeners.forEach { listener in + commandDelegate.send(result, callbackId: listener.callbackID) + } + + return true + } + } +} diff --git a/cordova-airship/src/ios/AirshipCordovaAutopilot.swift b/cordova-airship/src/ios/AirshipCordovaAutopilot.swift new file mode 100644 index 00000000..954b395d --- /dev/null +++ b/cordova-airship/src/ios/AirshipCordovaAutopilot.swift @@ -0,0 +1,62 @@ +/* Copyright Airship and Contributors */ + +import AirshipKit +import AirshipFrameworkProxy + +final class AirshipCordovaAutopilot { + + public static let shared: AirshipCordovaAutopilot = AirshipCordovaAutopilot() + private var launchOptions: [UIApplication.LaunchOptionsKey : Any]? + private var settings: AirshipCordovaPluginSettings? + + @MainActor + func pluginInitialized(settings: AirshipCordovaPluginSettings?) { + self.settings = settings + AirshipProxy.shared.delegate = self + AirshipCordovaBootstrap.onLaunch = { launchOptions in + self.launchOptions = launchOptions as? [UIApplication.LaunchOptionsKey : Any] + try? AirshipProxy.shared.attemptTakeOff(launchOptions: self.launchOptions) + } + } + + @MainActor + func attemptTakeOff(json: Any) throws -> Bool { + return try AirshipProxy.shared.takeOff( + json: json, + launchOptions: self.launchOptions + ) + } + +} + +extension AirshipCordovaAutopilot: AirshipProxyDelegate { + public func migrateData(store: AirshipFrameworkProxy.ProxyStore) { + AirshipCordovaProxyDataMigrator().migrateData(store: store) + store.defaultPresentationOptions = settings?.presentationOptions ?? [] + store.defaultAutoDisplayMessageCenter = settings?.autoLaunchMessageCenter ?? true + } + + public func loadDefaultConfig() -> AirshipConfig { + let config = AirshipConfig.default() + settings?.apply(config: config) + return config + } + + @MainActor + public func onAirshipReady() { + Airship.analytics.registerSDKExtension( + AirshipSDKExtension.cordova, + version: AirshipCordovaVersion.version + ) + + if settings?.clearBadgeOnLaunch == true { + Airship.push.resetBadge() + } + + if settings?.enablePushOnLaunch == true { + Airship.push.userPushNotificationsEnabled = true + } + } +} + + diff --git a/cordova-airship/src/ios/AirshipCordovaBootstrap.h b/cordova-airship/src/ios/AirshipCordovaBootstrap.h new file mode 100644 index 00000000..a4a1c704 --- /dev/null +++ b/cordova-airship/src/ios/AirshipCordovaBootstrap.h @@ -0,0 +1,14 @@ +/* Copyright Airship and Contributors */ + +@import Foundation; + + +/** + * Handles takeOff for the Airship SDK. + */ +@interface AirshipCordovaBootstrap: NSObject + +typedef void (^UALaunchBlock)(NSDictionary * _Nullable); + +@property (class, nonatomic, copy, nullable) UALaunchBlock onLaunch; +@end diff --git a/cordova-airship/src/ios/AirshipCordovaBootstrap.m b/cordova-airship/src/ios/AirshipCordovaBootstrap.m new file mode 100644 index 00000000..7197267e --- /dev/null +++ b/cordova-airship/src/ios/AirshipCordovaBootstrap.m @@ -0,0 +1,42 @@ +/* Copyright Airship and Contributors */ + +#import "AirshipCordovaBootstrap.h" + +@implementation AirshipCordovaBootstrap + + +static UALaunchBlock _launchBlock = nil; + ++ (void)setOnLaunch:(UALaunchBlock)onLaunch { + _launchBlock = onLaunch; + + if (_didLaunch) { + onLaunch(_launchOptions); + } else { + _launchBlock = onLaunch; + } +} + ++ (UALaunchBlock)onLaunch { + return _launchBlock; +} + +static BOOL _didLaunch = false; +static NSDictionary *_launchOptions = nil; + ++ (void)load { + NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; + [center addObserverForName:UIApplicationDidFinishLaunchingNotification + object:nil + queue:nil usingBlock:^(NSNotification * _Nonnull note) { + + _didLaunch = YES; + _launchOptions = note.userInfo.copy; + if (_launchBlock) { + _launchBlock(_launchOptions); + _launchBlock = nil; + } + }]; +} + +@end diff --git a/cordova-airship/src/ios/AirshipCordovaPluginSettings.swift b/cordova-airship/src/ios/AirshipCordovaPluginSettings.swift new file mode 100644 index 00000000..329ad709 --- /dev/null +++ b/cordova-airship/src/ios/AirshipCordovaPluginSettings.swift @@ -0,0 +1,230 @@ +/* Copyright Airship and Contributors */ + +import Foundation +import AirshipKit +import AirshipFrameworkProxy + +enum AirshipCordovaSite: String, Decodable, Sendable { + case us = "US" + case eu = "EU" + + var airshipValue: CloudSite { + switch(self) { + case .us: + return .us + case .eu: + return .eu + } + } + + var proxyValue: ProxyConfig.Site { + switch(self) { + case .us: + return .us + case .eu: + return .eu + } + } +} + +struct AirshipCordovaPluginSettings: Decodable, Sendable { + + enum LogLevel: String, Decodable, Sendable { + case none + case error + case warn + case info + case debug + case verbose + } + + var productionAppKey: String? + var productionAppSecret: String? + var productionLogLevel: LogLevel? + + var developmentAppKey: String? + var developmentAppSecret: String? + var developmentLogLevel: LogLevel? + + var inProduction: Bool? + var site: AirshipCordovaSite? + + var clearBadgeOnLaunch: Bool? + var enablePushOnLaunch: Bool? + var analyticsEnabled: Bool? + + var initialConfigURL: String? + var presentationOptions: UNNotificationPresentationOptions + var autoLaunchMessageCenter: Bool? + var messageCenterStyleConfig: String? + + enum CodingKeys: String, CodingKey, CaseIterable { + case productionAppKey = "com.urbanairship.production_app_key" + case productionAppSecret = "com.urbanairship.production_app_secret" + case productionLogLevel = "com.urbanairship.production_log_level" + case developmentAppKey = "com.urbanairship.development_app_key" + case developmentAppSecret = "com.urbanairship.development_app_secret" + case developmentLogLevel = "com.urbanairship.development_log_level" + case inProduction = "com.urbanairship.in_production" + case site = "com.urbanairship.site" + case clearBadgeOnLaunch = "com.urbanairship.clear_badge_onlaunch" + case enablePushOnLaunch = "com.urbanairship.enable_push_onlaunch" + case initialConfigURL = "com.urbanairship.initial_config_url" + case analyticsEnabled = "com.urbanairship.enable_analytic" + case alertPresentationOption = "com.urbanairship.ios_foreground_notification_presentation_alert" + case badgePresentationOption = "com.urbanairship.ios_foreground_notification_presentation_badge" + case soundPresentationOption = "com.urbanairship.ios_foreground_notification_presentation_sound" + case autoLaunchMessageCenter = "com.urbanairship.auto_launch_message_center" + case messageCenterStyleConfig = "com.urbanairship.message.center.style.file" + } + + static func from(settings: [AnyHashable: Any]?) -> AirshipCordovaPluginSettings? { + guard let settings = settings else { return nil } + let knownKeys = CodingKeys.allCases.map { $0.rawValue } + let filtered = settings.filter { key, value in + guard let key = key as? String else { return false } + guard (value as? String) != nil else { return false } + return knownKeys.contains(key) + } + + do { + return try AirshipJSON.wrap(filtered).decode() + } catch { + AirshipLogger.error("Failed to parse cordova settings \(filtered) error \(error)") + return nil + } + } + + init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + self.productionAppKey = try container.decodeIfPresent(String.self, forKey: .productionAppKey) + self.productionAppSecret = try container.decodeIfPresent(String.self, forKey: .productionAppSecret) + self.productionLogLevel = try container.decodeIfPresent(AirshipCordovaPluginSettings.LogLevel.self, forKey: .productionLogLevel) + self.developmentAppKey = try container.decodeIfPresent(String.self, forKey: .developmentAppKey) + self.developmentAppSecret = try container.decodeIfPresent(String.self, forKey: .developmentAppSecret) + self.developmentLogLevel = try container.decodeIfPresent(AirshipCordovaPluginSettings.LogLevel.self, forKey: .developmentLogLevel) + self.inProduction = try container.decodeIfPresent(String.self, forKey: .inProduction)?.asBool + self.site = try container.decodeIfPresent(AirshipCordovaSite.self, forKey: .site) + self.clearBadgeOnLaunch = try container.decodeIfPresent(String.self, forKey: .clearBadgeOnLaunch)?.asBool + self.enablePushOnLaunch = try container.decodeIfPresent(String.self, forKey: .enablePushOnLaunch)?.asBool + self.initialConfigURL = try container.decodeIfPresent(String.self, forKey: .initialConfigURL) + self.analyticsEnabled = try container.decodeIfPresent(String.self, forKey: .analyticsEnabled)?.asBool + self.autoLaunchMessageCenter = try container.decodeIfPresent(String.self, forKey: .autoLaunchMessageCenter)?.asBool + self.messageCenterStyleConfig = try container.decodeIfPresent(String.self, forKey: .messageCenterStyleConfig) + + + let alert = try container.decodeIfPresent(String.self, forKey: .alertPresentationOption)?.asBool + let badge = try container.decodeIfPresent(String.self, forKey: .badgePresentationOption)?.asBool + let sound = try container.decodeIfPresent(String.self, forKey: .soundPresentationOption)?.asBool + + var presentationOptions: UNNotificationPresentationOptions = [] + if alert == true { + presentationOptions.insert(.list) + presentationOptions.insert(.banner) + } + + if badge == true { + presentationOptions.insert(.badge) + } + + if sound == true { + presentationOptions.insert(.sound) + } + + self.presentationOptions = presentationOptions + } + + func apply(config: AirshipConfig) { + if let appSecret = self.developmentAppSecret { + config.developmentAppSecret = appSecret + } + + if let appKey = self.developmentAppKey { + config.developmentAppKey = appKey + } + + if let logLevel = self.developmentLogLevel { + config.developmentLogLevel = logLevel.airshipValue + } + + if let appSecret = self.productionAppSecret { + config.productionAppSecret = appSecret + } + + if let appKey = self.productionAppKey { + config.productionAppKey = appKey + } + + if let logLevel = self.productionLogLevel { + config.productionLogLevel = logLevel.airshipValue + } + + if let site = self.site { + config.site = site.airshipValue + } + + if let inProduction = self.inProduction { + config.inProduction = inProduction + } + + if let initialConfigURL = self.initialConfigURL { + config.initialConfigURL = initialConfigURL + } + + if let analyticsEnabled = self.analyticsEnabled { + config.isAnalyticsEnabled = analyticsEnabled + } + + if let messageCenterStyleConfig = self.messageCenterStyleConfig { + config.messageCenterStyleConfig = messageCenterStyleConfig + } + } +} + +extension String { + var asBool: Bool { + get throws { + guard let bool = Bool(self.lowercased()) else { + throw AirshipErrors.error("Failed to parse bool \(self)") + } + return bool + } + } +} + + +extension AirshipCordovaPluginSettings.LogLevel { + var airshipValue: AirshipLogLevel { + switch(self) { + case .none: + return .none + case .error: + return .error + case .warn: + return .warn + case .info: + return .info + case .debug: + return .debug + case .verbose: + return .verbose + } + } + + var proxyValue: ProxyConfig.LogLevel { + switch(self) { + case .none: + return .none + case .error: + return .error + case .warn: + return .warning + case .info: + return .info + case .debug: + return .debug + case .verbose: + return .verbose + } + } +} diff --git a/cordova-airship/src/ios/AirshipCordovaProxyDataMigrator.swift b/cordova-airship/src/ios/AirshipCordovaProxyDataMigrator.swift new file mode 100644 index 00000000..43b7d8fc --- /dev/null +++ b/cordova-airship/src/ios/AirshipCordovaProxyDataMigrator.swift @@ -0,0 +1,162 @@ +/* Copyright Airship and Contributors */ + +import Foundation +import AirshipFrameworkProxy +import UserNotifications +import AirshipKit + +struct AirshipCordovaProxyDataMigrator { + + private let defaults = UserDefaults.standard + + private static let productionAppKey = "com.urbanairship.production_app_key" + private static let productionAppSecret = "com.urbanairship.production_app_secret" + private static let site = "com.urbanairship.site" + private static let developmentAppKey = "com.urbanairship.development_app_key" + private static let developmentAppSecret = "com.urbanairship.development_app_secret" + + private static let messageCenterStyleConfigKey = "com.urbanairship.message.center.style.file" + private static let autoLaunchMessageCenterKey = "com.urbanairship.auto_launch_message_center" + + private static let autoLaunchPreferenceCenterPrefix = "com.urbanairship.preference_" + private static let autoLaunchPreferenceCenterSuffix = "_custom_ui" + + private static let notificationPresentationAlertKey = "com.urbanairship.ios_foreground_notification_presentation_alert" + private static let notificationPresentationBadgeKey = "com.urbanairship.ios_foreground_notification_presentation_badge" + private static let notificationPresentationSoundKey = "com.urbanairship.ios_foreground_notification_presentation_sound" + + + func migrateData(store: ProxyStore) { + migrateConfig(store: store) + migrateAutoLaunchMessageCenter(store: store) + migrateAutoLaunchPreferenceCenter(store: store) + migratePresentationOptions(store: store) + } + + private func migrateConfig(store: ProxyStore) { + + let productionAppKey = defaults.string(forKey: Self.productionAppKey) + let productionAppSecret = defaults.string(forKey: Self.productionAppSecret) + let developmentAppKey = defaults.string(forKey: Self.developmentAppKey) + let developmentAppSecret = defaults.string(forKey: Self.developmentAppSecret) + let messageCenterStyleConfig = defaults.string(forKey: Self.messageCenterStyleConfigKey) + + let site: ProxyConfig.Site? = if let string = defaults.string(forKey: Self.site) { + AirshipCordovaSite(rawValue: string)?.proxyValue + } else { + nil + } + + var production: ProxyConfig.Environment? + if let productionAppKey, let productionAppSecret { + production = ProxyConfig.Environment( + logLevel: nil, + appKey: productionAppKey, + appSecret: productionAppSecret + ) + } + + var development: ProxyConfig.Environment? + if let developmentAppKey, let developmentAppSecret { + development = ProxyConfig.Environment( + logLevel: nil, + appKey: developmentAppKey, + appSecret: developmentAppSecret + ) + } + + if (production != nil || development != nil ) { + store.config = ProxyConfig( + productionEnvironment: production, + developmentEnvironment: development, + ios: ProxyConfig.PlatformConfig( + messageCenterStyleConfig: messageCenterStyleConfig + ), + site: site + ) + } + + [ + Self.messageCenterStyleConfigKey, + Self.productionAppKey, + Self.productionAppSecret, + Self.developmentAppKey, + Self.developmentAppSecret, + Self.site, + ].forEach { + defaults.removeObject(forKey: $0) + } + } + + private func migrateAutoLaunchMessageCenter(store: ProxyStore) { + guard + let autoLaunchMessageCenter = defaults.object( + forKey: Self.autoLaunchMessageCenterKey + ) as? Bool + else { + return + } + + store.autoDisplayMessageCenter = autoLaunchMessageCenter + defaults.removeObject(forKey: Self.autoLaunchMessageCenterKey) + } + + private func migrateAutoLaunchPreferenceCenter(store: ProxyStore) { + // Preference center + defaults.dictionaryRepresentation().keys.forEach { key in + if key.hasPrefix(Self.autoLaunchPreferenceCenterPrefix), + key.hasSuffix(Self.autoLaunchPreferenceCenterSuffix) + { + var preferenceCenterID = String( + key.dropFirst("Self.autoLaunchPreferenceCenterPrefix".count) + ) + + preferenceCenterID = String( + preferenceCenterID.dropLast(Self.autoLaunchPreferenceCenterSuffix.count) + ) + + store.setAutoLaunchPreferenceCenter( + preferenceCenterID, + autoLaunch: defaults.bool(forKey: key) + ) + + defaults.removeObject( + forKey: key + ) + } + } + } + + private func migratePresentationOptions(store: ProxyStore) { + let alert = defaults.object(forKey: Self.notificationPresentationAlertKey) as? Bool + let badge = defaults.object(forKey: Self.notificationPresentationBadgeKey) as? Bool + let sound = defaults.object(forKey: Self.notificationPresentationSoundKey) as? Bool + + guard alert != nil || badge != nil || sound != nil else { return } + + var presentationOptions: UNNotificationPresentationOptions = [] + + if alert == true { + presentationOptions.insert(.list) + presentationOptions.insert(.banner) + } + + if badge == true { + presentationOptions.insert(.badge) + } + + if sound == true { + presentationOptions.insert(.sound) + } + + store.foregroundPresentationOptions = presentationOptions + + [ + Self.notificationPresentationAlertKey, + Self.notificationPresentationBadgeKey, + Self.notificationPresentationSoundKey + ].forEach { + defaults.removeObject(forKey: $0) + } + } +} diff --git a/cordova-airship/src/ios/AirshipCordovaVersion.swift b/cordova-airship/src/ios/AirshipCordovaVersion.swift new file mode 100644 index 00000000..f51f16d5 --- /dev/null +++ b/cordova-airship/src/ios/AirshipCordovaVersion.swift @@ -0,0 +1,7 @@ +/* Copyright Airship and Contributors */ + +import Foundation + +class AirshipCordovaVersion { + static let version = "15.0.0" +} diff --git a/cordova-airship/types/index.d.ts b/cordova-airship/types/index.d.ts new file mode 100644 index 00000000..40bd1ff8 --- /dev/null +++ b/cordova-airship/types/index.d.ts @@ -0,0 +1,1935 @@ +export type JsonValue = + | string + | number + | boolean + | null + | JsonObject + | JsonArray; + +export type JsonObject = { + [key: string]: JsonValue; +}; + +export type JsonArray = JsonValue[]; + +export interface ChannelCreatedEvent { + /** + * The channel ID. + */ + channelId: string; +} + +export interface PushTokenReceivedEvent { + /** + * The push token. + */ + pushToken: string; +} + +/** + * Event fired when a push is received. + */ +export interface PushReceivedEvent { + pushPayload: PushPayload; +} + +/** + * The push payload. + */ +export interface PushPayload { + /** + * The alert. + */ + alert?: string; + /** + * The title. + */ + title?: string; + /** + * The subtitle. + */ + subtitle?: string; + /** + * The notification ID. + */ + notificationId?: string; + /** + * The notification extras. + */ + extras: JsonObject; +} + +/** + * Event fired when the user initiates a notification response. + */ +export interface NotificationResponseEvent { + /** + * The push notification. + */ + pushPayload: PushPayload; + + /** + * The action button ID, if available. + */ + actionId?: string; + + /** + * Indicates whether the response was a foreground action. + * This value is always if the user taps the main notification, + * otherwise it is defined by the notification action button. + */ + isForeground: boolean; +} + +/** + * Push notification status. + */ +export interface PushNotificationStatus { + /** + * If user notifications are enabled on [Airship.push]. + */ + isUserNotificationsEnabled: boolean; + + /** + * If notifications are allowed at the system level for the application. + */ + areNotificationsAllowed: boolean; + + /** + * If the push feature is enabled on [Airship.privacyManager]. + */ + isPushPrivacyFeatureEnabled: boolean; + + /* + * If push registration was able to generate a token. + */ + isPushTokenRegistered: boolean; + + /* + * If Airship is able to send and display a push notification. + */ + isOptedIn: boolean; + + /* + * Checks for isUserNotificationsEnabled, areNotificationsAllowed, and isPushPrivacyFeatureEnabled. If this flag + * is true but `isOptedIn` is false, that means push token was not able to be registered. + */ + isUserOptedIn: boolean; +} + +/** + * Event fired when the notification status changes. + */ +export interface PushNotificationStatusChangedEvent { + /** + * The push notification status. + */ + status: PushNotificationStatus +} + +/** + * Event fired when the Message Center is updated. + */ +export interface MessageCenterUpdatedEvent { + /** + * The unread message count. + */ + messageUnreadCount: number; + /** + * The total message count. + */ + messageCount: number; +} + +/** + * Event fired when the Message Center is requested to be displayed. + */ +export interface DisplayMessageCenterEvent { + /** + * The message ID, if available. + */ + messageId?: string; +} + +/** + * Event fired when a deep link is opened. + */ +export interface DeepLinkEvent { + /** + * The deep link string. + */ + deepLink: string; +} + +/** + * Event fired when a preference center is requested to be displayed. + */ +export interface DisplayPreferenceCenterEvent { + /** + * The preference center Id. + */ + preferenceCenterId: string; +} + +/** + * iOS options + */ +export namespace iOS { + + /** + * Quiet time + */ + export interface QuietTime { + /** + * Start hour. Must be 0-23. + */ + startHour: number, + + /** + * Start minute. Must be 0-59. + */ + startMinute: number, + + /** + * End hour. Must be 0-23. + */ + endHour: number, + + /** + * End minute. Must be 0-59. + */ + endMinute: number + } + + /** + * Enum of notification options. iOS only. + */ + export enum NotificationOption { + /** + * Alerts. + */ + Alert = 'alert', + /** + * Sounds. + */ + Sound = 'sound', + /** + * Badges. + */ + Badge = 'badge', + /** + * Car play. + */ + CarPlay = 'car_play', + /** + * Critical Alert. + */ + CriticalAlert = 'critical_alert', + /** + * Provides app notification settings. + */ + ProvidesAppNotificationSettings = 'provides_app_notification_settings', + /** + * Provisional. + */ + Provisional = 'provisional', + } + + /** + * Enum of foreground notification options. + */ + export enum ForegroundPresentationOption { + /** + * Play the sound associated with the notification. + */ + Sound = 'sound', + /** + * Apply the notification's badge value to the app’s icon. + */ + Badge = 'badge', + + /** + * Show the notification in Notification Center. On iOS 13 an older, + * this will also show the notification as a banner. + */ + List = 'list', + + /** + * Present the notification as a banner. On iOS 13 an older, + * this will also show the notification in the Notification Center. + */ + Banner = 'banner', + } + + /** + * Enum of authorized notification options. + */ + export enum AuthorizedNotificationSetting { + /** + * Alerts. + */ + Alert = 'alert', + /** + * Sounds. + */ + Sound = 'sound', + /** + * Badges. + */ + Badge = 'badge', + /** + * CarPlay. + */ + CarPlay = 'car_play', + /** + * Lock screen. + */ + LockScreen = 'lock_screen', + /** + * Notification center. + */ + NotificationCenter = 'notification_center', + /** + * Critical alert. + */ + CriticalAlert = 'critical_alert', + /** + * Announcement. + */ + Announcement = 'announcement', + /** + * Scheduled delivery. + */ + ScheduledDelivery = 'scheduled_delivery', + /** + * Time sensitive. + */ + TimeSensitive = 'time_sensitive', + } + + /** + * Enum of authorized status. + */ + export enum AuthorizedNotificationStatus { + /** + * Not determined. + */ + NotDetermined = 'not_determined', + + /** + * Denied. + */ + Denied = 'denied', + + /** + * Authorized. + */ + Authorized = 'authorized', + + /** + * Provisional. + */ + Provisional = 'provisional', + + /** + * Ephemeral. + */ + Ephemeral = 'ephemeral', + } + + export interface AuthorizedNotificationSettingsChangedEvent { + /** + * Authorized settings. + */ + authorizedSettings: AuthorizedNotificationSetting[]; + } +} + +/** + * Airship config environment + */ +export interface ConfigEnvironment { + /** + * App key. + */ + appKey: string; + + /** + * App secret. + */ + appSecret: string; + + /** + * Optional log level. + */ + logLevel?: LogLevel; +} + +/** + * Cancellable + */ +export interface Cancellable { + /** + * Cancels + */ + cancel(): void +} + +/** + * Possible sites. + */ +export type Site = 'us' | 'eu'; + +/** + * Log levels. + */ +export type LogLevel = + | 'verbose' + | 'debug' + | 'info' + | 'warning' + | 'error' + | 'none'; + +/** + * Airship config + */ +export interface AirshipConfig { + /** + * Default environment. + */ + default?: ConfigEnvironment; + + /** + * Development environment. Overrides default environment if inProduction is false. + */ + development?: ConfigEnvironment; + + /** + * Production environment. Overrides default environment if inProduction is true. + */ + production?: ConfigEnvironment; + + /** + * Cloud site. + */ + site?: Site; + + /** + * Switches the environment from development or production. If the value is not + * set, Airship will determine the value at runtime. + */ + inProduction?: boolean; + + /** + * URL allow list. + */ + urlAllowList?: string[]; + + /** + * URL allow list for open URL scope. + */ + urlAllowListScopeOpenUrl?: string[]; + + /** + * URL allow list for JS bridge injection. + */ + urlAllowListScopeJavaScriptInterface?: string[]; + + /** + * Enables delayed channel creation. + * Deprecated. Use the Private Manager to disable all features instead. + */ + isChannelCreationDelayEnabled?: boolean; + + /** + * Initial config URL for custom Airship domains. The URL + * should also be added to the urlAllowList. + */ + initialConfigUrl?: string; + + /** + * Enabled features. Defaults to all. + */ + enabledFeatures?: Feature[]; + + /** + * Enables channel capture feature. + * This config is enabled by default. + */ + isChannelCaptureEnabled?: boolean; + + /** + * Whether to suppress console error messages about missing allow list entries during takeOff. + * This config is disabled by default. + */ + suppressAllowListError?: boolean; + + /** + * Pauses In-App Automation on launch. + */ + autoPauseInAppAutomationOnLaunch?: boolean; + + /** + * iOS config. + */ + ios?: { + /** + * itunesId for rate app and app store deep links. + */ + itunesId?: string; + + /** + * The message center style plist path. + */ + messageCenterStyleConfig?: string; + }; + + /** + * Android config. + */ + android?: { + /** + * App store URI + */ + appStoreUri?: string; + + /** + * Fcm app name if using multiple FCM projects. + */ + fcmFirebaseAppName?: string; + + /** + * Notification config. + */ + notificationConfig?: Android.NotificationConfig; + }; +} + +export namespace Android { + /** + * Android notification config. + */ + export interface NotificationConfig { + /** + * The icon resource name. + */ + icon?: string; + /** + * The large icon resource name. + */ + largeIcon?: string; + /** + * The default android notification channel ID. + */ + defaultChannelId?: string; + /** + * The accent color. Must be a hex value #AARRGGBB. + */ + accentColor?: string; + } +} + +/** + * Enum of authorized Features. + */ +export enum Feature { + InAppAutomation = 'in_app_automation', + MessageCenter = 'message_center', + Push = 'push', + Analytics = 'analytics', + TagsAndAttributes = 'tags_and_attributes', + Contacts = 'contacts', +} + +/** + * All available features. + */ +export const FEATURES_ALL = Object.values(Feature); + +/** + * Custom event + */ +export interface CustomEvent { + /** + * Event name + */ + eventName: string; + /** + * Event value + */ + eventValue?: number; + /** + * Event properties + */ + properties: JsonObject; + /** + * Transaction ID + */ + transactionId?: string; + /** + * Interaction ID + */ + interactionId?: string; + /** + * Interaction type + */ + interactionType?: string; +} + +/** + * Subscription Scope types. + */ +export enum SubscriptionScope { + App = 'app', + Web = 'web', + Sms = 'sms', + Email = 'email', +} + +export interface InboxMessage { + /** + * The message ID. Needed to display, mark as read, or delete the message. + */ + id: string; + /** + * The message title. + */ + title: string; + /** + * The message sent date in milliseconds. + */ + sentDate: number; + /** + * Optional - The icon url for the message. + */ + listIconUrl: string; + /** + * The unread / read status of the message. + */ + isRead: boolean; + /** + * String to String map of any message extras. + */ + extras: Record; +} + +// --- +// See: https://github.com/urbanairship/web-push-sdk/blob/master/src/remote-data/preference-center.ts +// --- + +/** + * A preference center definition. + * + * @typedef {object} PreferenceCenter + * @property {string} id the ID of the preference center + * @property {Array} sections a list of sections + * @property {?CommonDisplay} display display information + */ +export type PreferenceCenter = { + id: string; + sections: Section[]; + display?: CommonDisplay; +}; + +/** + * Preference center display information. + * @typedef {object} CommonDisplay + * @property {string} name + * @property {?string} description + */ +export type CommonDisplay = { + name: string; + description?: string; +}; + +export type Icon = { + icon: string; +}; + +export type IconDisplay = CommonDisplay & Partial; + +export interface ItemBase { + type: unknown; + id: string; + display: CommonDisplay; + conditions?: Condition[]; +} + +/** + * A channel subscription item. + * @typedef {object} ChannelSubscriptionItem + * @memberof PreferenceCenter + * @property {"channel_subscription"} type + * @property {string} id the item identifier + * @property {?CommonDisplay} display display information + * @property {string} subscription_id the subscription list id + */ +export interface ChannelSubscriptionItem extends ItemBase { + type: 'channel_subscription'; + subscription_id: string; +} + +export interface ContactSubscriptionGroupItem extends ItemBase { + type: 'contact_subscription_group'; + id: string; + subscription_id: string; + components: ContactSubscriptionGroupItemComponent[]; +} + +export interface ContactSubscriptionGroupItemComponent { + scopes: SubscriptionScope[]; + display: Omit; +} + +export interface ContactSubscriptionItem extends ItemBase { + type: 'contact_subscription'; + scopes: SubscriptionScope[]; + subscription_id: string; +} + +export interface AlertItem extends ItemBase { + type: 'alert'; + display: IconDisplay; + button?: Button; +} + +export interface ConditionBase { + type: unknown; +} + +export interface NotificationOptInCondition extends ConditionBase { + type: 'notification_opt_in'; + when_status: 'opt_in' | 'opt_out'; +} + +export type Condition = NotificationOptInCondition; + +// Changed from `unknown` in spec +export type Actions = { + [key: string]: JsonValue; +}; + +export interface Button { + text: string; + content_description?: string; + actions: Actions; +} + +export interface SectionBase { + type: unknown; + id: string; + display?: CommonDisplay; + items: Item[]; +} + +/** + * @typedef {object} CommonSection + * @memberof PreferenceCenter + * @property {"section"} type + * @property {string} id the section identifier + * @property {?CommonDisplay} display display information + * @property {Array} items list of + * section items + */ +export interface CommonSection extends SectionBase { + type: 'section'; +} + +export interface LabeledSectionBreak extends SectionBase { + type: 'labeled_section_break'; + items: never; +} + +export type Item = + | ChannelSubscriptionItem + | ContactSubscriptionGroupItem + | ContactSubscriptionItem + | AlertItem; + +export type Section = CommonSection | LabeledSectionBreak; + +/** + * An interface representing the eligibility status of a flag, and optional + * variables associated with the flag. + */ +export interface FeatureFlag { + /** + * A boolean representing flag eligibility; will be `true` if the current + * contact is eligible for the flag. + */ + readonly isEligible: boolean + /** + * A variables associated with the flag, if any. Will be `null` if no data + * is associated with the flag, or if the flag does not exist. + */ + readonly variables: unknown | null + /** + * A boolean representing if the flag exists or not. For ease of use and + * deployment, asking for a flag by any name will return a `FeatureFlag` + * interface, even if the flag was not found to exist. However this property + * may be checked to determine if the flag was actually resolved to a known + * flag name. + */ + readonly exists: boolean + + /** + * Reporting Metadata, the shape of which is private and not to be relied + * upon. When not provided, an interaction cannot be tracked on the flag. + * @ignore + */ + readonly _internal: unknown +} + + +/** + * Editor for tag groups. + */ +export interface TagGroupEditor { + + /** + * Adds tags to a tag group. + * + * @param tagGroup The tag group. + * @param tags Tags to add. + * @return The tag group editor instance. + */ + addTags(group: string, tags: string[]): TagGroupEditor + + /** + * Removes tags from the tag group. + * + * @param tagGroup The tag group. + * @param tags Tags to remove. + * @return The tag group editor instance. + */ + removeTags(group: string, tags: string[]): TagGroupEditor + + /** + * Overwrite the current set of tags on the Tag Group. + * + * @param tagGroup The tag group. + * @param tags Tags to set. + * @return The tag group editor instance. + */ + setTags(group: string, tags: Array): TagGroupEditor + + /** + * Applies the tag changes. + * @param success Success callback. + * @param error Error callback. + */ + apply(success?: () => void, error?: (err: string) => void): void +} + + +/** + * Editor for device tags. + */ +export interface TagEditor { + /** + * Adds tags to a channel. + * + * @param tags Tags to add. + * @return The tag editor instance. + */ + addTags(tags: string[]): TagEditor + + /** + * Removes tags from the channel. + * + * @param tags Tags to remove. + * @return The tag editor instance. + */ + removeTags(tags: string[]): TagEditor + + /** + * Applies the tag changes. + * @param success Success callback. + * @param error Error callback. + */ + apply(success?: () => void, error?: (err: string) => void): void +} + + +/** + * Subscription list editor. + */ +export interface SubscriptionListEditor { + + /** + * Subscribes to a list. + * + * @param listId The subscription list identifier. + * @return The editor. + */ + subscribe(listId: string): SubscriptionListEditor + + /** + * Unsubscribe from a list. + * + * @param listId The subscription list identifier. + * @return The editor. + */ + unsubscribe(listId: string): SubscriptionListEditor + + /** + * Applies the subscription list changes. + * @param success Success callback. + * @param error Error callback. + */ + apply(success?: () => void, error?: (err: string) => void): void +} + + +/** + * Scoped subscription list editor. + */ +export interface ScopedSubscriptionListEditor { + + /** + * Subscribes to a list in the given scope. + * + * @param listId The subscription list identifier. + * @param scope The subscription scope to subscribe. + */ + subscribe(listId: string, scope: SubscriptionScope): ScopedSubscriptionListEditor + + /** + * Unsubscribe from a list. + * + * @param listId The subscription list identifier. + * @param scope The subscription scope to unsubscribe. + */ + unsubscribe(listId: string, scope: SubscriptionScope): ScopedSubscriptionListEditor + + /** + * Applies the subscription list changes. + * @param success Success callback. + * @param error Error callback. + */ + apply(success?: () => void, error?: (err: string) => void): void +} + +/** + * Editor for attributes. + */ +export interface AttributeEditor { + + /** + * Adds an attribute. + * + * @param value The attribute value. + * @param name The attribute name. + * @return The attribute editor instance. + */ + setAttribute( + name: string, + value: string | number | boolean | Date + ): AttributeEditor + + /** + * Removes an attribute. + * @param name The name of the attribute to remove. + * @return The attribute editor instance. + */ + removeAttribute(name: string): AttributeEditor + + /** + * Applies the attribute operations. + * @param success Success callback. + * @param error Error callback. + */ + apply(success?: () => void, error?: (err: string) => void): void +} + +/** + * Airship Push. + */ +export interface AirshipPush { + /** + * iOS only push methods. + */ + readonly iOS: AirshipPushIOS; + + + /** + * Android only push methods. + */ + readonly android: AirshipPushAndroid; + + /** + * Enables/disables notifications on Airship. + * + * When enabled, it will cause the user to be prompted for + * the permission on platforms that support it. + * To get the result of the prompt, use `enableUserNotifications`. + * @param enabled true to enable, false to disable + * @param success Success callback. + * @param error Error callback. + */ + setUserNotificationsEnabled( + enabled: boolean, + success?: () => void, + error?: (err: string) => void + ): void + + /** + * Checks if user notifications are enabled or not on Airship. + * @param success Success callback. + * @param error Error callback. + */ + isUserNotificationsEnabled( + success: (enabled: boolean) => void, + error?: (err: string) => void + ): void + + /** + * Enables user notifications. + * @param success Success callback. + * @param error Error callback. + */ + enableUserNotifications( + success: (enabled: boolean) => void, + error?: (err: string) => void + ): void + + /** + * Gets the notification status. + * @param success Success callback. + * @param error Error callback. + */ + getNotificationStatus( + success: (enabled: PushNotificationStatus) => void, + error?: (err: string) => void + ): void + + /** + * Event when the notification status has changed. + * + * @param callback The callback. + * @return A cancellable that can be used to cancel the listener. + */ + onNotificationStatusChanged( + callback: (event: PushNotificationStatusChangedEvent) => void + ): Cancellable + + /** + * Gets the push token if generated. + * Use the event listener `onPushTokenReceived` to be notified when its available. + * @param success Success callback. + * @param error Error callback. + */ + getPushToken( + success: (token: string | null | undefined) => void, + error?: (err: string) => void + ): void + + /** + * Gets the list of active notifications. + * + * On Android, this list only includes notifications + * sent through Airship. + * @param success Success callback. + * @param error Error callback. + */ + getActiveNotifications( + success: (payloads: PushPayload[]) => void, + error?: (err: string) => void + ): void + + /** + * Clears all notifications for the app. + * @param success Success callback. + * @param error Error callback. + */ + clearNotifications( + success?: () => void, + error?: (err: string) => void + ): void + + /** + * Clears a specific notification. + * + * On Android, you can use this method to clear + * notifications outside of Airship, The identifier is in + * the format of :. + * @param identifier The identifier. + * @param success Success callback. + * @param error Error callback. + */ + clearNotification( + identifier: string, + success?: () => void, + error?: (err: string) => void + ): void + + /** + * Push received listener. + * + * @param callback The callback. + * @return A cancellable that can be used to cancel the listener. + */ + onPushReceived( + callback: (event: PushReceivedEvent) => void + ): Cancellable + + /** + * Notification response listener. + * + * @param callback The callback. + * @return A cancellable that can be used to cancel the listener. + */ + onNotificationResponse( + callback: (event: NotificationResponseEvent) => void + ): Cancellable + + /** + * Push token listener. + * + * @param callback The callback. + * @return A cancellable that can be used to cancel the listener. + */ + onPushTokenReceived( + callback: (event: PushTokenReceivedEvent) => void + ): Cancellable +} + +/** + * iOS Push. + */ +export interface AirshipPushIOS { + + /** + * Sets the foreground presentation options. + * @param options The foreground options. + * @param success Success callback. + * @param error Error callback. + */ + setForegroundPresentationOptions( + options: iOS.ForegroundPresentationOption[], + success?: () => void, + error?: (err: string) => void + ): void + + /** + * Sets the notification options. + * @param options The notification options. + * @param success Success callback. + * @param error Error callback. + */ + setNotificationOptions( + options: iOS.NotificationOption[], + success?: () => void, + error?: (err: string) => void + ): void + + /** + * Checks if autobadge is enabled. + * @param success Success callback. + * @param error Error callback. + */ + isAutobadgeEnabled( + success: (enabled: boolean) => void, + error?: (err: string) => void + ): void + + /** + * Enables/disables autobadge. + * @param enabled true to enable, false to disable. + * @param success Success callback. + * @param error Error callback. + */ + setAutobadgeEnabled( + enabled: boolean, + success?: () => void, + error?: (err: string) => void + ): void + + /** + * Set the badge number. + * @param badge The badge number. + * @param success Success callback. + * @param error Error callback. + */ + setBadgeNumber( + badge: number, + success?: () => void, + error?: (err: string) => void + ): void + + /** + * Gets the badge number. + * @param success Success callback. + * @param error Error callback. + */ + getBadgeNumber( + success: (badge: number) => void, + error?: (err: string) => void + ): void + + /** + * Gets the list of authorized notification settings. + * @param success Success callback. + * @param error Error callback. + */ + getAuthorizedNotificationSettings( + success: (settings: iOS.AuthorizedNotificationSetting[]) => void, + error?: (err: string) => void + ): void + + /** + * Gets the authorized notification status. + * @param success Success callback. + * @param error Error callback. + */ + getAuthorizedNotificationStatus( + success: (status: iOS.AuthorizedNotificationStatus) => void, + error?: (err: string) => void + ): void + + /** + * Enables/disables quiet time. + * + * @param enabled true to enable, false to disable + * @param success Success callback. + * @param error Error callback. + */ + setQuietTimeEnabled( + enabled: boolean, + success?: () => void, + error?: (err: string) => void + ): void + + /** + * Checks if quiet time is enabled or not. + * @param success Success callback. + * @param error Error callback. + */ + isQuietTimeEnabled( + success: (enabled: boolean) => void, + error?: (err: string) => void + ): void + + /** + * Sets quiet time. + * + * @param quietTime The quiet time. + * @param success Success callback. + * @param error Error callback. + */ + setQuietTimeEnabled( + quietTime: iOS.QuietTime, + success?: () => void, + error?: (err: string) => void + ): void + + /** + * Gets the quiet time settings. + * @param success Success callback. + * @param error Error callback. + */ + getQuietTime( + success: (quietTime?: iOS.QuietTime) => void, + error?: (err: string) => void + ): void + + /** + * An event when the authorized push settings changed. + * + * @param callback The callback. + * @return A cancellable that can be used to cancel the listener. + */ + onAuthorizedSettingsChanged( + callback: (event: iOS.AuthorizedNotificationSettingsChangedEvent) => void + ): Cancellable +} + +/** + * Android Push. + */ +export interface AirshipPushAndroid { + + /** + * Checks if a notification category/channel is enabled. + * @param channel The channel name. + * @param success Success callback. + * @param error Error callback. + */ + isNotificationChannelEnabled( + channel: string, + success: (enabled: boolean) => void, + error?: (err: string) => void + ): void + + /** + * Sets the notification config. + * @param config The notification config. + * @param success Success callback. + * @param error Error callback. + */ + setNotificationConfig( + config: Android.NotificationConfig, + success?: () => void, + error?: (err: string) => void + ): void + + /** + * Enables/disables showing notifications in the foreground. + * @param enabled true to enable, false to disable. + * @param success Success callback. + * @param error Error callback. + */ + setForegroundNotificationsEnabled( + enabled: boolean, + success?: () => void, + error?: (err: string) => void + ): void + + /** + * Checks if foreground notifications are enabled. + * @param success Success callback. + * @param error Error callback. + */ + setForegroundNotificationsEnabled( + success: (enabled: boolean) => void, + error?: (err: string) => void + ): void +} +/** + * Airship Privacy Manager. + */ +export interface AirshipPrivacyManager { + + /** + * Sets the current set of enabled features. + * @param features The features to set. + * @param success Success callback. + * @param error Error callback. + */ + setEnabledFeatures( + features: Feature[], + success?: () => void, + error?: (err: string) => void + ): void + + /** + * Gets the current enabled features. + * @param success Success callback. + * @param error Error callback. + */ + getEnabledFeatures( + success: (features: Feature[]) => void, + error?: (err: string) => void + ): void + + /** + * Enables additional features. + * @param features The features to enable. + * @param success Success callback. + * @param error Error callback. + */ + enableFeatures( + features: Feature[], + success?: () => void, + error?: (err: string) => void + ): void + + /** + * Disable features. + * @param features The features to disable. + * @param success Success callback. + * @param error Error callback. + */ + disableFeatures( + features: Feature[], + success?: () => void, + error?: (err: string) => void + ): void + + /** + * Checks if the features are enabled or not. + * @param features The features to check. + * @param success Success callback to receive the check result. + * @param error Error callback. + */ + isFeaturesEnabled( + features: Feature[], + success: (isEnabled: boolean) => void, + error?: (err: string) => void + ): void +} + +/** + * Airship Preference Center. + */ +export interface AirshipPreferenceCenter { + + /** + * Requests to display a preference center. + * + * Will either emit an event to display the + * Preference Center if auto launch is disabled, + * or display the OOTB UI. + * @param preferenceCenterId The preference center Id. + * @param success Success callback. + * @param error Error callback. + */ + display( + preferenceCenterId: string, + success?: () => void, + error?: (err: string) => void + ): void + + /** + * Gets the preference center config. + * @param preferenceCenterId The preference center Id. + * @param success Success callback. + * @param error Error callback. + */ + getConfig( + preferenceCenterId: string, + success: (config: PreferenceCenter) => void, + error?: (err: string) => void + ): void + + /** + * Enables or disables showing the OOTB UI when requested to display by either + * `display` or by a notification with some other action. + * @param preferenceCenterId The preference center Id. + * @param autoLaunch true to show OOTB UI, false to emit events. + */ + setAutoLaunchDefaultPreferenceCenter( + preferenceCenterId: string, + autoLaunch: boolean + ): void + + /** + * Event when the message center a preference center is requested to display. + * + * @param callback The callback. + * @return A cancellable that can be used to cancel the listener. + */ + onDisplay( + callback: (event: DisplayPreferenceCenterEvent) => void + ): Cancellable +} +/** + * Airship Message Center + */ +export interface AirshipMessageCenter { + + /** + * Gets the unread count. + * @param success Success callback. + * @param error Error callback. + */ + getUnreadCount( + success: (count: number) => void, + error?: (err: string) => void + ): void + + /** + * Gets the inbox messages. + * @param success Success callback. + * @param error Error callback. + */ + getMessages( + success: (messages: InboxMessage[]) => void, + error?: (err: string) => void + ): void + + /** + * Marks a message as read. + * @param messageId The message Id. + * @param success Success callback. + * @param error Error callback. + */ + markMessageRead( + messageId: string, + success?: () => void, + error?: (err: string) => void + ): void + + /** + * Deletes a message. + * @param messageId The message Id. + * @param success Success callback. + * @param error Error callback. + */ + deleteMessage( + messageId: string, + success?: () => void, + error?: (err: string) => void + ): void + + /** + * Dismisses the OOTB message center if displayed. + * @param success Success callback. + * @param error Error callback. + */ + dismiss( + success?: () => void, + error?: (err: string) => void + ): void + + /** + * Requests to display the Message Center. + * + * Will either emit an event to display the + * Message Center if auto launch message center + * is disabled, or display the OOTB message center. + * @param messageId Optional message Id. + * @param success Success callback. + * @param error Error callback. + */ + display( + messageId?: string, + success?: () => void, + error?: (err: string) => void + ): void + + /** + * Overlays the message view. Should be used to display the actual + * message body in a custom Message Center. + * + * @param messageId The message Id. + * @param success Success callback. + * @param error Error callback. + */ + showMessageView( + messageId: string, + success?: () => void, + error?: (err: string) => void + ): void + + /** + * Refreshes the messages. + * @param success Success callback. + * @param error Error callback. + */ + refreshMessages( + success?: () => void, + error?: (err: string) => void + ): void + + /** + * Enables or disables showing the OOTB UI when requested to display by either + * `display` or by a notification with a Message Center action. + * @param autoLaunch true to show OOTB UI, false to emit events. + */ + setAutoLaunchDefaultMessageCenter(autoLaunch: boolean): void + + /** + * Event when the message center is requested to be displayed. + * + * @param callback The callback. + * @return A cancellable that can be used to cancel the listener. + */ + onDisplay( + callback: (event: DisplayMessageCenterEvent) => void + ): Cancellable + + /** + * Event when the message list is updated. + * + * @param callback The callback. + * @return A cancellable that can be used to cancel the listener. + */ + onUpdated( + callback: (event: MessageCenterUpdatedEvent) => void + ): Cancellable +} + +/** +* Manages locale used by Airship messaging. +*/ +export interface AirshipLocale { + /** + * Sets the locale override. + * @param localeIdentifier The locale identifier. + * @param success Success callback. + * @param error Error callback. + */ + setLocaleOverride( + localeIdentifier: string, + success?: () => void, + error?: (err: string) => void + ): void + + /** + * Clears the locale override. + * @param success Success callback. + * @param error Error callback. + */ + clearLocaleOverride( + success?: () => void, + error?: (err: string) => void + ): void + + /** + * Gets the current locale. + * @param success Success callback. + * @param error Error callback. + */ + getLocale( + success: (locale: string) => void, + error?: (err: string) => void + ): void +} +/** +* Airship InApp Experiences. +*/ +export interface AirshipInApp { + + /** + * Pauses messages. + * @param paused `true` to pause, `false` to resume. + * @param success Success callback. + * @param error Error callback. + */ + setPaused( + paused: boolean, + success?: () => void, + error?: (err: string) => void + ): void + + /** + * Checks if messages are paused. + * @param success Success callback. + * @param error Error callback. + */ + isPaused( + success: (paused: boolean) => void, + error?: (err: string) => void + ): void + + /** + * Sets the display interval for messages. + * @param milliseconds Display interval. + * @param success Success callback. + * @param error Error callback. + */ + setDisplayInterval( + milliseconds: number, + success?: () => void, + error?: (err: string) => void + ): void + + /** + * Gets the display interval. + * @param success Success callback. + * @param error Error callback. + */ + getDisplayInterval( + success: (milliseconds: number) => void, + error?: (err: string) => void + ): void +} + + +/** + * Airship feature flag manager. + */ +export interface AirshipFeatureFlagManager { + + /** + * Retrieve a given flag's status and associated data by its name. + * @param flagName The flag name + * @param success Success callback. + * @param error Error callback. + */ + flag( + flagName: string, + success: (flag: FeatureFlag) => void, + error?: (err: string) => void + ): void + + /** + * Tracks a feature flag interaction event. + * @param flag The flag + * @param success Success callback. + * @param error Error callback. + */ + trackInteraction( + flag: FeatureFlag, + success?: () => void, + error?: (err: string) => void + ): void +} + +/** + * Airship contact. + */ +export interface AirshipContact { + + /** + * Identifies the contact with a named user Id. + * @param namedUser The named user Id. + * @param success Success callback. + * @param error Error callback. + */ + identify( + namedUser: string, + success?: () => void, + error?: (err: string) => void + ): void + + /** + * Resets the contact. + * @param success Success callback. + * @param error Error callback. + */ + reset( + success?: () => void, + error?: (err: string) => void + ): void + + /** + * Notifies the contact of a remote login. + * @param success Success callback. + * @param error Error callback. + */ + notifyRemoteLogin( + success?: () => void, + error?: (err: string) => void + ): void + + /** + * Gets the named user Id. + * @param success Success callback. + * @param error Error callback. + */ + getNamedUserId( + success: (namedUserId: string | null | undefined) => void, + error?: (err: string) => void + ): void + + /** + * Gets the contacts subscription lists. + * @param success Success callback. + * @param error Error callback. + */ + getSubscriptionLists( + success: (subscriptionLists: Record) => void, + error?: (err: string) => void + ): void + + /** + * Edits tag groups. + * @returns A tag group editor. + */ + editTagGroups(): TagGroupEditor + + /** + * Edits attributes. + * @returns An attribute editor. + */ + editAttributes(): AttributeEditor + + /** + * Edits subscription lists. + * @returns A subscription list editor. + */ + editSubscriptionLists(): ScopedSubscriptionListEditor +} +/** + * Airship channel. + */ +export interface AirshipChannel { + + /** + * Enables channel creation if channel creation has been delayed. + * It is only necessary to call this when isChannelCreationDelayEnabled + * has been set to `true` in the airship config. + * Deprecated. Use the Private Manager to disable all features instead. + * @param success Success callback. + * @param error Error callback. + */ + enableChannelCreation( + success?: () => void, + error?: (err: string) => void + ): void + + /** + * Edits device tags. + * @returns A tag editor. + */ + editTags(): TagEditor + + /** + * Gets the device tags. + * @param success Success callback. + * @param error Error callback. + */ + getTags( + success: (tags: string[]) => void, + error?: (err: string) => void + ): void + + /** + * Gets the channel Id. + * @param success Success callback. + * @param error Error callback. + */ + getChannelId( + success: (channelId: string | null | undefined) => void, + error?: (err: string) => void + ): void + + /** + * Gets a list of the channel's subscriptions. + * @param success Success callback. + * @param error Error callback. + */ + getSubscriptionLists( + success: (subscriptionLists: string[]) => void, + error?: (err: string) => void + ): void + + /** + * Edits tag groups. + * @returns A tag group editor. + */ + editTagGroups(): TagGroupEditor + + /** + * Edits attributes. + * @returns An attribute editor. + */ + editAttributes(): AttributeEditor + + /** + * Edits subscription lists. + * @returns A subscription list editor. + */ + editSubscriptionLists(): SubscriptionListEditor + + /** + * Event when the channel (and channel Id) is created. + * + * @param callback The callback. + * @return A cancellable that can be used to cancel the listener. + */ + onChannelCreated( + callback: (event: ChannelCreatedEvent) => void + ): Cancellable +} +/** + * Airship analytics. + */ +export interface AirshipAnalytics { + + /** + * Associates an identifier. + * + * @param key The key. + * @param identifier The identifier. `null` to remove. + * @param success Success callback. + * @param error Error callback. + */ + associateIdentifier( + key: string, + identifier?: string, + success?: () => void, + error?: (err: string) => void + ): void + + /** + * Tracks a screen. + * @param screen The screen. `null` to stop tracking. + * @param success Success callback. + * @param error Error callback. + */ + trackScreen( + screen?: string, + success?: () => void, + error?: (err: string) => void + ): void + + /** + * Adds a custom event. + * @param event The custom event. + * @param success Success callback. + * @param error Error callback. + */ + addCustomEvent( + event: CustomEvent, + success?: () => void, + error?: (err: string) => void + ): void +} + +/** + * Airship actions. + */ +export interface AirshipActions { + + /** + * Runs an Airship action. + * + * @param name The name of the action. + * @param value The action's value. + * @param success Success callback with the action result. + * @param error Error callback. + */ + run( + actionName: string, + actionValue?: JsonValue, + success?: (result: JsonValue | null | undefined) => void, + error?: (err: string) => void + ): void +} + +export interface Airship { + readonly actions: AirshipActions; + readonly analytics: AirshipAnalytics; + readonly channel: AirshipChannel; + readonly contact: AirshipContact; + readonly inApp: AirshipInApp; + readonly locale: AirshipLocale; + readonly messageCenter: AirshipMessageCenter; + readonly preferenceCenter: AirshipPreferenceCenter; + readonly privacyManager: AirshipPrivacyManager; + readonly push: AirshipPush; + readonly featureFlagManager: AirshipFeatureFlagManager; + + /** + * Calls takeOff. If Airship is already configured for + * the app session, the new config will be applied on the next + * app init. + * @param config The config. + * @param success Success callback with the result. `true` if airship is ready. + * @param error Error callback. + */ + takeOff( + config: AirshipConfig, + success?: (isReady: boolean) => void, + error?: (err: string) => void + ): void + + /** + * Checks if Airship is ready. + * @param success Success callback with the result. + * @param error Error callback. + */ + isFlying( + success: (isFlying: boolean) => void, + error?: (err: string) => void + ): void + + /** + * Event when a deep link is received. + * + * @param callback The callback. + * @return A cancellable that can be used to cancel the listener. + */ + onDeepLink( + callback: (event: DeepLinkEvent) => void + ): Cancellable +} + + +declare global { + const Airship: Airship; +} diff --git a/cordova-airship/www/Airship.js b/cordova-airship/www/Airship.js new file mode 100644 index 00000000..a41b7159 --- /dev/null +++ b/cordova-airship/www/Airship.js @@ -0,0 +1,668 @@ +/* Copyright Airship and Contributors */ + +var cordova = require("cordova"), + exec = require("cordova/exec"), + argscheck = require('cordova/argscheck'), + airship = { + contact: {}, + channel: {}, + analytics: {}, + locale: {}, + messageCenter: {}, + featureFlagManager: {}, + preferenceCenter: {}, + push: { + ios: {}, + android: {} + }, + privacyManager: {}, + actions: {}, + inApp: {} + } + +// Argcheck values: +// * : allow anything,  +// f : function +// a : array +// d : date +// n : number +// s : string +// o : object +// lowercase = required, uppercase = optional + +function perform(name, args, success, failure) { + exec(success, failure, "AirshipCordova", "perform", [name, args]) +} + +var callbackId = 0 +function registerListener(name, callback) { + var isCancelled = false + let subCallbackId = callbackId + callbackId += 1 + + exec(function (event) { + if (!isCancelled) { + callback(event) + } + }, {}, "AirshipCordova", "addListener", [name, subCallbackId]) + + let subscription = {} + subscription.cancel = function () { + isCancelled = true + exec({}, {}, "AirshipCordova", "removeListener", [name, subCallbackId]) + } + return subscription +} + +function TagEditor(methodPrefix, nativeMethod) { + var operations = [] + var editor = {} + + editor.addTags = function (tags) { + argscheck.checkArgs('a', methodPrefix + "#addTags", arguments) + var operation = { "operationType": "add", "tags": tags } + operations.push(operation) + return editor + } + + editor.removeTags = function (tags) { + argscheck.checkArgs('a', methodPrefix + "#removeTags", arguments) + var operation = { "operationType": "remove", "tags": tags } + operations.push(operation) + return editor + } + + editor.apply = function (success, failure) { + argscheck.checkArgs('FF', methodPrefix + "#apply", arguments) + perform(nativeMethod, operations, success, failure) + operations = [] + return editor + } + + return editor +} + +function TagGroupEditor(methodPrefix, nativeMethod) { + var operations = [] + var editor = {} + + editor.addTags = function (tagGroup, tags) { + argscheck.checkArgs('sa', methodPrefix + "#addTags", arguments) + var operation = { "operationType": "add", "group": tagGroup, "tags": tags } + operations.push(operation) + return editor + } + + editor.removeTags = function (tagGroup, tags) { + argscheck.checkArgs('sa', methodPrefix + "#removeTags", arguments) + var operation = { "operationType": "remove", "group": tagGroup, "tags": tags } + operations.push(operation) + return editor + } + + editor.setTags = function (tagGroup, tags) { + argscheck.checkArgs('sa', methodPrefix + "#setTags", arguments) + var operation = { "operationType": "set", "group": tagGroup, "tags": tags } + operations.push(operation) + return editor + } + + editor.apply = function (success, failure) { + argscheck.checkArgs('FF', methodPrefix + "#apply", arguments) + perform(nativeMethod, operations, success, failure) + operations = [] + return editor + } + + return editor +} + +function ScopedSubscriptionListEditor(methodPrefix, nativeMethod) { + var operations = [] + var editor = {} + + editor.subscribe = function (listId, scope) { + argscheck.checkArgs('ss', methodPrefix + "#subscribe", arguments) + var operation = { "action": "subscribe", "listId": listId, "scope": scope } + operations.push(operation) + return editor + } + + editor.unsubscribe = function (listId, scope) { + argscheck.checkArgs('ss', methodPrefix + "#unsubscribe", arguments) + var operation = { "action": "unsubscribe", "listId": listId, "scope": scope } + operations.push(operation) + return editor + } + + editor.apply = function (success, failure) { + argscheck.checkArgs('FF', methodPrefix + "#apply", arguments) + perform(nativeMethod, operations, success, failure) + operations = [] + return editor + } + + return editor +} + +function SubscriptionListEditor(methodPrefix, nativeMethod) { + // Store the raw operations and let the SDK combine them + var operations = [] + var editor = {} + + editor.subscribe = function (listId) { + argscheck.checkArgs('s', methodPrefix + "#subscribe", arguments) + var operation = { "action": "subscribe", "listId": listId } + operations.push(operation) + return editor + } + + editor.unsubscribe = function (listId) { + argscheck.checkArgs('s', methodPrefix + "#unsubscribe", arguments) + var operation = { "action": "unsubscribe", "listId": listId } + operations.push(operation) + return editor + } + + editor.apply = function (success, failure) { + argscheck.checkArgs('FF', methodPrefix + "#apply", arguments) + perform(nativeMethod, operations, success, failure) + operations = [] + return editor + } + + return editor +} + +function AttributesEditor(methodPrefix, nativeMethod) { + var operations = []; + var editor = {}; + + editor.setAttribute = function (name, value) { + argscheck.checkArgs('s*', methodPrefix + "#setAttribute", arguments) + + var operation = { "action": "set", "value": value, "key": name } + + if (typeof value === "string") { + operation["type"] = "string" + } else if (typeof value === "number") { + operation["type"] = "number" + } else if (typeof value === "boolean") { + // No boolean attribute type. Convert value to string. + operation["type"] = "string" + operation["value"] = value.toString(); + } else if (value instanceof Date) { + // JavaScript's date type doesn't pass through the JS to native bridge. Dates are instead serialized as milliseconds since epoch. + operation["type"] = "date" + operation["value"] = value.getTime() + } else { + throw ("Unsupported attribute type: " + typeof value) + } + + operations.push(operation) + + return editor + } + + editor.removeAttribute = function (name) { + argscheck.checkArgs('s', methodPrefix + "#removeAttribute", arguments) + var operation = { "action": "remove", "key": name } + operations.push(operation) + return editor + } + + editor.apply = function (success, failure) { + argscheck.checkArgs('FF', methodPrefix + "#apply", arguments) + perform(nativeMethod, operations, success, failure) + operations = [] + return editor + } + + return editor +} + + +airship.takeOff = function (config, success, failure) { + argscheck.checkArgs("*FF", "Airship.takeOff", arguments); + perform("takeOff", config, success, failure) +} + +airship.isFlying = function (success, failure) { + argscheck.checkArgs("fF", "Airship.isFlying", arguments); + perform("isFlying", null, success, failure) +} + +airship.onDeepLink = function (callback) { + argscheck.checkArgs('F', 'Airship.onDeepLink', arguments) + return registerListener("airship.event.deep_link_received", callback) +} + +// Channel + +airship.channel.getChannelId = function (success, failure) { + argscheck.checkArgs('fF', 'Airship.channel.getChannelId', arguments) + perform("channel#getChannelId", null, success, failure) +} + +airship.channel.getSubscriptionLists = function (success, failure) { + argscheck.checkArgs('fF', 'Airship.channel.getSubscriptionLists', arguments) + perform("channel#getSubscriptionLists", null, success, failure) +} + +airship.channel.getTags = function (success, failure) { + argscheck.checkArgs('fF', 'Airship.channel.getTags', arguments) + perform("channel#getTags", null, success, failure) +} + +airship.channel.setTags = function (tags, success, failure) { + argscheck.checkArgs('aFF', 'Airship.channel.setTags', arguments) + perform("channel#setTags", tags, success, failure) +} + +airship.channel.editTags = function () { + return new TagEditor('Airship.channel.editTags', 'channel#editTags') +} + +airship.channel.editTagGroups = function () { + return new TagGroupEditor('Airship.channel.editTagGroups', 'channel#editTagGroups') +} + +airship.channel.editAttributes = function () { + return new AttributesEditor('Airship.channel.editAttributes', 'channel#editAttributes') +} + +airship.channel.editSubscriptionLists = function () { + return new SubscriptionListEditor('Airship.channel.editSubscriptionLists', 'channel#editSubscriptionLists') +} + +airship.channel.onChannelCreated = function (callback) { + argscheck.checkArgs('F', 'Airship.channel.channel_created', arguments) + return registerListener("airship.event.channel_created", callback) +} + +airship.channel.enableChannelCreation = function () { + argscheck.checkArgs('FF', 'Airship.channel.enableChannelCreation', arguments) + perform("channel#enableChannelCreation", null, success, failure) +} + +// Contact + +airship.contact.getNamedUser = function (success, failure) { + argscheck.checkArgs('fF', 'Airship.contact.getNamedUser', arguments) + perform("contact#getNamedUser", null, success, failure) +} + +airship.contact.identify = function (namedUserId, success, failure) { + argscheck.checkArgs('SFF', 'Airship.contact.getNamedUser', arguments) + perform("contact#identify", namedUserId, success, failure) +} + +airship.contact.reset = function (success, failure) { + argscheck.checkArgs('FF', 'Airship.contact.reset', arguments) + perform("contact#reset", null, success, failure) +} + +airship.contact.notifyRemoteLogin = function (success, failure) { + argscheck.checkArgs('FF', 'Airship.contact.notifyRemoteLogin', arguments) + perform("contact#notifyRemoteLogin", null, success, failure) +} + +airship.contact.getSubscriptionLists = function (success, failure) { + argscheck.checkArgs('fF', 'Airship.contact.getSubscriptionLists', arguments) + perform("contact#getSubscriptionLists", null, success, failure) +} + +airship.contact.editTagGroups = function () { + return new TagGroupEditor('Airship.contact.editTagGroups', 'contact#editTagGroups') +} + +airship.contact.editAttributes = function () { + return new AttributesEditor('Airship.contact.editAttributes', 'contact#editAttributes') +} + +airship.contact.editSubscriptionLists = function () { + return new ScopedSubscriptionListEditor('Airship.contact.editSubscriptionLists', 'contact#editSubscriptionLists') +} + +// Push + +airship.push.enableUserNotifications = function (success, failure) { + argscheck.checkArgs('fF', 'Airship.push.enableUserNotifications', arguments) + perform("push#enableUserNotifications", null, success, failure) +} + +airship.push.isUserNotificationsEnabled = function (success, failure) { + argscheck.checkArgs('fF', 'Airship.push.isUserNotificationsEnabled', arguments) + perform("push#isUserNotificationsEnabled", null, success, failure) +} + +airship.push.setUserNotificationsEnabled = function (enabled, success, failure) { + argscheck.checkArgs('*FF', 'Airship.push.setUserNotificationsEnabled', arguments) + perform("push#setUserNotificationsEnabled", !!enabled, success, failure) +} + +airship.push.getNotificationStatus = function (success, failure) { + argscheck.checkArgs('fF', 'Airship.push.getNotificationStatus', arguments) + perform("push#getNotificationStatus", null, success, failure) +} + +airship.push.getPushToken = function (success, failure) { + argscheck.checkArgs('fF', 'Airship.push.getPushToken', arguments) + perform("push#getPushToken", null, success, failure) +} + +airship.push.clearNotifications = function (success, failure) { + argscheck.checkArgs('FF', 'Airship.push.clearNotifications', arguments) + perform("push#clearNotifications", null, success, failure) +} + +airship.push.clearNotification = function (id, success, failure) { + argscheck.checkArgs('sFF', 'Airship.push.clearNotification', arguments) + perform("push#clearNotification", id, success, failure) +} + +airship.push.getActiveNotifications = function (success, failure) { + argscheck.checkArgs('fF', 'Airship.push.getActiveNotifications', arguments) + perform("push#getActiveNotifications", null, success, failure) +} + +airship.push.onNotificationStatusChanged = function (callback) { + argscheck.checkArgs('F', 'Airship.push.onNotificationStatusChanged', arguments) + return registerListener("airship.event.notification_status_changed", callback) +} + +airship.push.onPushTokenReceived = function (callback) { + argscheck.checkArgs('F', 'Airship.push.onPushTokenReceived', arguments) + return registerListener("airship.event.push_token_received", callback) +} + +airship.push.onPushReceived = function (callback) { + argscheck.checkArgs('F', 'Airship.push.onPushReceived', arguments) + return registerListener("airship.event.push_received", callback) +} + +airship.push.onNotificationResponse = function (callback) { + argscheck.checkArgs('F', 'Airship.push.onNotificationResponse', arguments) + return registerListener("airship.event.notification_response", callback) +} + +// Push Android + +airship.push.android.setForegroundNotificationsEnabled = function (enabled, success, failure) { + argscheck.checkArgs('*FF', 'Airship.push.android.setForegroundNotificationsEnabled', arguments) + perform("push#android#setForegroundNotificationsEnabled", !!enabled, success, failure) +} + +airship.push.android.isForegroundNotificationsEnabled = function (success, failure) { + argscheck.checkArgs('fF', 'Airship.push.android.isForegroundNotificationsEnabled', arguments) + perform("push#android#isForegroundNotificationsEnabled", null, success, failure) +} + +airship.push.android.isNotificationChannelEnabled = function (channel, success, failure) { + argscheck.checkArgs('sfF', 'Airship.push.android.isNotificationChannelEnabled', arguments) + perform("push#android#isNotificationChannelEnabled", channel, success, failure) +} + +airship.push.android.setNotificationConfig = function (config, success, failure) { + argscheck.checkArgs('*FF', 'Airship.push.android.isNotificationChannelEnabled', arguments) + perform("push#android#setNotificationConfig", config, success, failure) +} + +// Push iOS + +airship.push.ios.setQuietTimeEnabled = function(enabled, success, failure) { + argscheck.checkArgs('*FF', 'Airship.push.ios.setQuietTimeEnabled', arguments) + perform("push#ios#setQuietTimeEnabled", !!enabled, success, failure) +} + +airship.push.ios.isQuietTimeEnabled = function(success, failure) { + argscheck.checkArgs('fF', 'Airship.push.ios.isQuietTimeEnabled', arguments) + perform("push#ios#isQuietTimeEnabled", null, success, failure) +} + +airship.push.ios.setQuietTime =function(quietTime, success, failure) { + argscheck.checkArgs('*FF', 'Airship.push.ios.setQuietTime', arguments) + perform("push#ios#setQuietTime", quietTime, success, failure) +} + +airship.push.ios.getQuietTime = function(success, failure) { + argscheck.checkArgs('fF', 'Airship.push.ios.getQuietTime', arguments) + perform("push#ios#getQuietTime", null, success, failure) +} + +airship.push.ios.isAutobadgeEnabled = function (success, failure) { + argscheck.checkArgs('fF', 'Airship.push.ios.isAutobadgeEnabled', arguments) + perform("push#ios#isAutobadgeEnabled", null, success, failure) +} + +airship.push.ios.setAutobadgeEnabled = function (enabled, success, failure) { + argscheck.checkArgs('*FF', 'Airship.push.ios.setAutobadgeEnabled', arguments) + perform("push#ios#setAutobadgeEnabled", !!enabled, success, failure) +} + +airship.push.ios.setForegroundPresentationOptions = function (options, success, failure) { + argscheck.checkArgs('*FF', 'Airship.push.ios.setForegroundPresentationOptions', arguments) + perform("push#ios#setForegroundPresentationOptions", options, success, failure) +} + +airship.push.ios.setNotificationOptions = function (options, success, failure) { + argscheck.checkArgs('*FF', 'Airship.push.ios.setNotificationOptions', arguments) + perform("push#ios#setNotificationOptions", options, success, failure) +} + +airship.push.ios.setBadgeNumber = function (badge, success, failure) { + argscheck.checkArgs('nFF', 'Airship.push.ios.setBadgeNumber', arguments) + perform("push#ios#setBadgeNumber", badge, success, failure) +} + +airship.push.ios.getBadgeNumber = function (success, failure) { + argscheck.checkArgs('fF', 'Airship.push.ios.getBadgeNumber', arguments) + perform("push#ios#getBadgeNumber", null, success, failure) +} + +airship.push.ios.getAuthorizedNotificationSettings = function (success, failure) { + argscheck.checkArgs('fF', 'Airship.push.ios.getAuthorizedNotificationSettings', arguments) + perform("push#ios#getAuthorizedNotificationSettings", null, success, failure) +} + +airship.push.ios.getAuthorizedNotificationStatus = function (success, failure) { + argscheck.checkArgs('fF', 'Airship.push.ios.getAuthorizedNotificationStatus', arguments) + perform("push#ios#getAuthorizedNotificationStatus", null, success, failure) +} + +airship.push.ios.resetBadge = function (success, failure) { + argscheck.checkArgs('*FF', 'Airship.push.resetBadge', arguments) + perform("push#ios#resetBadge", null, success, failure) +} + +airship.push.ios.onAuthorizedSettingsChanged = function (callback) { + argscheck.checkArgs('F', 'Airship.push.ios.onAuthorizedSettingsChanged', arguments) + return registerListener("airship.event.ios_authorized_notification_settings_changed", callback) +} + + +// Privacy Manager + +airship.privacyManager.isFeaturesEnabled = function (features, success, failure) { + argscheck.checkArgs('afF', 'Airship.push.isFeaturesEnabled', arguments) + perform("privacyManager#isFeaturesEnabled", features, success, failure) +} + +airship.privacyManager.setEnabledFeatures = function (features, success, failure) { + argscheck.checkArgs('aFF', 'Airship.push.setEnabledFeatures', arguments) + perform("privacyManager#setEnabledFeatures", features, success, failure) +} + +airship.privacyManager.enableFeatures = function (features, success, failure) { + argscheck.checkArgs('aFF', 'Airship.push.enableFeatures', arguments) + perform("privacyManager#enableFeatures", features, success, failure) +} + +airship.privacyManager.disableFeatures = function (features, success, failure) { + argscheck.checkArgs('aFF', 'Airship.push.disableFeatures', arguments) + perform("privacyManager#disableFeatures", features, success, failure) +} + +airship.privacyManager.getEnabledFeatures = function (success, failure) { + argscheck.checkArgs('fF', 'Airship.push.getEnabledFeatures', arguments) + perform("privacyManager#getEnabledFeatures", null, success, failure) +} + +// Message Center + +airship.messageCenter.getUnreadCount = function (success, failure) { + argscheck.checkArgs('fF', 'Airship.messageCenter.getUnreadCount', arguments) + perform("messageCenter#getUnreadCount", null, success, failure) +} + +airship.messageCenter.getMessages = function (success, failure) { + argscheck.checkArgs('fF', 'Airship.messageCenter.getMessages', arguments) + perform("messageCenter#getMessages", null, success, failure) +} + +airship.messageCenter.markMessageRead = function (messageId, success, failure) { + argscheck.checkArgs('sFF', 'Airship.messageCenter.markMessageRead', arguments) + perform("messageCenter#markMessageRead", messageId, success, failure) +} + +airship.messageCenter.deleteMessage = function (messageId, success, failure) { + argscheck.checkArgs('sFF', 'Airship.messageCenter.deleteMessage', arguments) + perform("messageCenter#deleteMessage", messageId, success, failure) +} + +airship.messageCenter.dismiss = function (success, failure) { + argscheck.checkArgs('FF', 'Airship.messageCenter.dismiss', arguments) + perform("messageCenter#dismiss", null, success, failure) +} + +airship.messageCenter.display = function (messageId, success, failure) { + argscheck.checkArgs('SFF', 'Airship.messageCenter.display', arguments) + perform("messageCenter#display", messageId, success, failure) +} + +airship.messageCenter.showMessageView = function (messageId, success, failure) { + argscheck.checkArgs('sFF', 'Airship.messageCenter.showMessageView', arguments) + perform("messageCenter#showMessageView", messageId, success, failure) +} + +airship.messageCenter.refreshMessages = function (success, failure) { + argscheck.checkArgs('FF', 'Airship.messageCenter.refreshMessages', arguments) + perform("messageCenter#refreshMessages", null, success, failure) +} + +airship.messageCenter.setAutoLaunchDefaultMessageCenter = function (autoLaunch, success, failure) { + argscheck.checkArgs('*FF', 'Airship.messageCenter.setAutoLaunchDefaultMessageCenter', arguments) + perform("messageCenter#setAutoLaunchDefaultMessageCenter", !!autoLaunch, success, failure) +} + +airship.messageCenter.onUpdated = function (callback) { + argscheck.checkArgs('F', 'Airship.messageCenter.onUpdated', arguments) + return registerListener("airship.event.message_center_updated", callback) +} + +airship.messageCenter.onDisplay = function (callback) { + argscheck.checkArgs('F', 'Airship.messageCenter.onDisplay', arguments) + return registerListener("airship.event.display_message_center", callback) +} + + +// Preference Center + +airship.preferenceCenter.display = function (preferenceCenterId, success, failure) { + argscheck.checkArgs('sFF', 'Airship.preferenceCenter.display', arguments) + perform("preferenceCenter#display", preferenceCenterId, success, failure) +} + +airship.preferenceCenter.getConfig = function (preferenceCenterId, success, failure) { + argscheck.checkArgs('sfF', 'Airship.preferenceCenter.getConfig', arguments) + perform("preferenceCenter#getConfig", preferenceCenterId, success, failure) +} + +airship.preferenceCenter.setAutoLaunchDefaultPreferenceCenter = function (preferenceCenterId, autoLaunch, success, failure) { + argscheck.checkArgs('s*FF', 'Airship.preferenceCenter.getConfig', arguments) + perform("preferenceCenter#getConfig", [preferenceCenterId, !!autoLaunch], success, failure) +} + +airship.preferenceCenter.onDisplay = function (callback) { + argscheck.checkArgs('F', 'Airship.preferenceCenter.onDisplay', arguments) + return registerListener("airship.event.display_preference_center", callback) +} + +// Analytics + +airship.analytics.trackScreen = function (screen, success, failure) { + argscheck.checkArgs('SFF', 'Airship.analytics.trackScreen', arguments) + perform("analytics#trackScreen", screen, success, failure) +} + +airship.analytics.associateIdentifier = function (key, value, success, failure) { + argscheck.checkArgs('sSFF', 'Airship.analytics.associateIdentifier', arguments) + perform("analytics#associateIdentifier", [key, value], success, failure) +} + +airship.analytics.addCustomEvent = function (event, success, failure) { + argscheck.checkArgs('*FF', 'Airship.analytics.addCustomEvent', arguments) + perform("analytics#addCustomEvent", event, success, failure) +} + +// Actions + +airship.actions.run = function (name, value, success, failure) { + argscheck.checkArgs('s*FF', 'Airship.actions.run', arguments) + perform("actions#run", [name, value], success, failure) +} + +/// Feature Flags + +airship.featureFlagManager.flag = function (name, success, failure) { + argscheck.checkArgs('sfF', 'Airship.featureFlagManager.flag', arguments) + perform("featureFlagManager#flag", name, success, failure) +} + +airship.featureFlagManager.trackInteraction = function (flag, success, failure) { + argscheck.checkArgs('*FF', 'Airship.featureFlagManager.trackInteraction', arguments) + perform("featureFlagManager#trackInteraction", flag, success, failure) +} + +/// In App + +airship.inApp.setPaused = function (paused, success, failure) { + argscheck.checkArgs('sFF', 'Airship.inApp.setPaused', arguments) + perform("inApp#setPaused", !!paused, success, failure) +} + + +airship.inApp.isPaused = function (success, failure) { + argscheck.checkArgs('fF', 'Airship.inApp.isPaused', arguments) + perform("inApp#isPaused", null, success, failure) +} + +airship.inApp.setDisplayInterval = function (interval, success, failure) { + argscheck.checkArgs('nFF', 'Airship.inApp.setDisplayInterval', arguments) + perform("inApp#setDisplayInterval", interval, success, failure) +} + +airship.privacyManager.getDisplayInterval = function (success, failure) { + argscheck.checkArgs('fF', 'Airship.inApp.getDisplayInterval', arguments) + perform("inApp#getDisplayInterval", null, success, failure) +} + +/// Locale + +airship.locale.setLocaleOverride = function (locale, success, failure) { + argscheck.checkArgs('sFF', 'Airship.inApp.setLocaleOverride', arguments) + perform("locale#setLocaleOverride", locale, success, failure) +} + + +airship.locale.clearLocaleOverride = function (success, failure) { + argscheck.checkArgs('FF', 'Airship.inApp.clearLocaleOverride', arguments) + perform("locale#clearLocaleOverride", null, success, failure) +} + +airship.locale.getLocale = function (success, failure) { + argscheck.checkArgs('fF', 'Airship.locale.getLocale', arguments) + perform("locale#getLocale", null, success, failure) +} + +module.exports = airship; \ No newline at end of file diff --git a/jsdoc_readme.md b/jsdoc_readme.md deleted file mode 100644 index a1d0bf42..00000000 --- a/jsdoc_readme.md +++ /dev/null @@ -1,89 +0,0 @@ -# Urban Airship Cordova Plugin - -### Resources: - - [Getting started guide](http://docs.urbanairship.com/platform/cordova.html) - - [Github repo](https://github.com/urbanairship/urbanairship-cordova) - -### Installation - -1. Install this plugin using Cordova CLI: - - cordova plugin add urbanairship-cordova - - -2. Modify the config.xml file to contain (replacing with your configuration settings): - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -3. *(iOS Only)* Add your Apple Developer Account Team ID to the [build.json](https://cordova.apache.org/docs/en/latest/guide/platforms/ios/#using-buildjson): - - { - "ios": { - "debug": { - "developmentTeam": "XXXXXXXXXX" - }, - "release": { - "developmentTeam": "XXXXXXXXXX" - } - } - } - Your iOS builds will need to reference the build.json using Cordova's "--buildConfig" flag. - -4. Enable user notifications: - - // Enable user notifications (will prompt the user to accept push notifications) - UAirship.setUserNotificationsEnabled(true, function (enabled) { - console.log("User notifications are enabled! Fire away!") - }) diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000..32122854 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,229 @@ +{ + "name": "urbanairship-cordova", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "workspaces": { + "packages": [ + "urbanairship-cordova", + "urbanairship-hms-cordova" + ] + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/jsonc-parser": { + "version": "3.2.1", + "dev": true, + "license": "MIT" + }, + "node_modules/lunr": { + "version": "2.3.9", + "dev": true, + "license": "MIT" + }, + "node_modules/marked": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/minimatch": { + "version": "5.1.6", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shiki": { + "version": "0.12.1", + "dev": true, + "license": "MIT", + "dependencies": { + "jsonc-parser": "^3.2.0", + "vscode-oniguruma": "^1.7.0", + "vscode-textmate": "^8.0.0" + } + }, + "node_modules/typedoc": { + "version": "0.23.24", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "lunr": "^2.3.9", + "marked": "^4.2.5", + "minimatch": "^5.1.2", + "shiki": "^0.12.1" + }, + "bin": { + "typedoc": "bin/typedoc" + }, + "engines": { + "node": ">= 14.14" + }, + "peerDependencies": { + "typescript": "4.6.x || 4.7.x || 4.8.x || 4.9.x" + } + }, + "node_modules/typescript": { + "version": "4.9.5", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/urbanairship-cordova": { + "resolved": "urbanairship-cordova", + "link": true + }, + "node_modules/urbanairship-hms-cordova": { + "resolved": "urbanairship-hms-cordova", + "link": true + }, + "node_modules/vscode-oniguruma": { + "version": "1.7.0", + "dev": true, + "license": "MIT" + }, + "node_modules/vscode-textmate": { + "version": "8.0.0", + "dev": true, + "license": "MIT" + }, + "urbanairship-cordova": { + "version": "15.0.0", + "engines": [ + { + "name": "cordova-android", + "version": ">=10.0.0" + }, + { + "name": "cordova-ios", + "version": ">=6.2.0" + }, + { + "name": "cordova-plugman", + "version": ">=4.2.0" + } + ], + "license": "Apache 2.0", + "devDependencies": { + "typedoc": "0.23.24" + } + }, + "urbanairship-hms-cordova": { + "version": "15.0.0", + "engines": [ + { + "name": "cordova-android", + "version": ">=10.0.0" + }, + { + "name": "cordova-plugman", + "version": ">=4.2.0" + } + ], + "license": "Apache 2.0" + } + }, + "dependencies": { + "balanced-match": { + "version": "1.0.2", + "dev": true + }, + "brace-expansion": { + "version": "2.0.1", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "jsonc-parser": { + "version": "3.2.1", + "dev": true + }, + "lunr": { + "version": "2.3.9", + "dev": true + }, + "marked": { + "version": "4.3.0", + "dev": true + }, + "minimatch": { + "version": "5.1.6", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + }, + "shiki": { + "version": "0.12.1", + "dev": true, + "requires": { + "jsonc-parser": "^3.2.0", + "vscode-oniguruma": "^1.7.0", + "vscode-textmate": "^8.0.0" + } + }, + "typedoc": { + "version": "0.23.24", + "dev": true, + "requires": { + "lunr": "^2.3.9", + "marked": "^4.2.5", + "minimatch": "^5.1.2", + "shiki": "^0.12.1" + } + }, + "typescript": { + "version": "4.9.5", + "dev": true, + "peer": true + }, + "urbanairship-cordova": { + "version": "file:urbanairship-cordova", + "requires": { + "typedoc": "0.23.24" + } + }, + "urbanairship-hms-cordova": { + "version": "file:urbanairship-hms-cordova" + }, + "vscode-oniguruma": { + "version": "1.7.0", + "dev": true + }, + "vscode-textmate": { + "version": "8.0.0", + "dev": true + } + } +} diff --git a/package.json b/package.json index 0b4e41df..6feb9cef 100644 --- a/package.json +++ b/package.json @@ -3,20 +3,12 @@ "workspaces": { "packages": [ "urbanairship-cordova", - "urbanairship-accengage-cordova", "urbanairship-hms-cordova" ] }, "scripts": { - "generate-docs": "yarn workspace urbanairship-cordova run generate-docs", - "create-sample": "bash ./scripts/create_sample.sh ../cordova-sample", - "build-android": "cd ../cordova-sample/test; cordova build android", - "build-ios": "cd ../cordova-sample/test; cordova build ios", - "run-android": "cd ../cordova-sample/test; cordova run android", - "run-ios": "cd ../cordova-sample/test; cordova run ios", - "add-accengage-module": "cd ../cordova-sample/test; cordova plugin add ../../urbanairship-cordova/urbanairship-accengage-cordova", - "remove-accengage-module": "cd ../cordova-sample/test; cordova plugin rm urbanairship-accengage-cordova", - "add-hms-module": "cd ../cordova-sample/test; cordova plugin add ../../urbanairship-cordova/urbanairship-hms-cordova", - "remove-hms-module": "cd ../cordova-sample/test; cordova plugin rm urbanairship-hms-cordova" + "bootstrap": "npm ci && npm --prefix urbanairship-cordova ci && npm --prefix urbanairship-hms-cordova ci", + "generate-docs": "npm run --prefix urbanairship-cordova generate-docs", + "create-sample": "bash ./scripts/create_sample.sh ../cordova-sample" } -} \ No newline at end of file +} diff --git a/scripts/check_plugin_version.sh b/scripts/check_plugin_version.sh index 4a06be30..0b83bb3f 100755 --- a/scripts/check_plugin_version.sh +++ b/scripts/check_plugin_version.sh @@ -1,40 +1,32 @@ #!/bin/bash set -e -set -x ROOT_PATH=`dirname "${0}"`/.. -# Get version from package.json file -packageJSONFilePath="$ROOT_PATH/urbanairship-cordova/package.json" -packageJSONVersionRegex='"version": ?"[0-9]+\.[0-9]+\.[0-9]+"' -packageJSONVersion=$(grep -E "$packageJSONVersionRegex" $packageJSONFilePath | cut -f4 -d \") +CORE_PACKAGE_PATH="$ROOT_PATH/cordova-airship/package.json" +HMS_PACKAGE_PATH="$ROOT_PATH/cordova-airship-hms/package.json" +ANDROID_VERISON_PATH="$ROOT_PATH/cordova-airship/src/android/AirshipCordovaVersion.kt" +IOS_VERISON_PATH="$ROOT_PATH/cordova-airship/src/ios/AirshipCordovaVersion.swift" +HMS_PLUGIN_XML_PATH="$ROOT_PATH/cordova-airship-hms/plugin.xml" -# Get version from plugin.xml file -pluginXMLFilePath="$ROOT_PATH/urbanairship-cordova/plugin.xml" +coreVersion=$(node -p "require('$CORE_PACKAGE_PATH').version") +echo "core package version: $coreVersion" -# Get plugin version -pluginXMLFileVersionRegex='version= ?"[0-9]+\.[0-9]+\.[0-9]+"' -pluginXMLFileVersion=$(grep -E "$pluginXMLFileVersionRegex" $pluginXMLFilePath | cut -f2 -d \") +hmsVersion=$(node -p "require('$HMS_PACKAGE_PATH').version") +echo "hms package version: $hmsVersion" -if [ "$pluginXMLFileVersion" != "$packageJSONVersion" ]; then - echo "BUILD FAILED: The plugin version is not correct in the plugin.xml file. The version should be the same as the one in the package.json file." - exit 1 -fi - -# Get plugin version for android config -pluginXMLAndroidConfigVersionRegex='android:value= ?"[0-9]+\.[0-9]+\.[0-9]+"' -pluginXMLAndroidConfigVersion=$(grep -E "$pluginXMLAndroidConfigVersionRegex" $pluginXMLFilePath | cut -f2 -d \") +androidVersion=$(grep "var version" $ANDROID_VERISON_PATH | awk -F'"' '{print $2}') +echo "android: $androidVersion" -if [ "$pluginXMLAndroidConfigVersion" != "$packageJSONVersion" ]; then - echo "BUILD FAILED: The plugin version in the Android Config is not correct in the plugin.xml file. The version should be the same as the one in the package.json file." - exit 1 -fi +iosVersion=$(grep "static let version" $IOS_VERISON_PATH | awk -F'"' '{print $2}') +echo "ios: $iosVersion" -# Get plugin version for iOS config -pluginXMLiOSConfigVersionRegex='[0-9]+\.[0-9]+\.[0-9]+' -pluginXMLiOSConfigVersion=$(grep -E "$pluginXMLiOSConfigVersionRegex" $pluginXMLFilePath | cut -f2 -d \> | cut -f1 -d \<) +hmsDependencyVersion=$(grep '[0-9]+\.[0-9]+\.[0-9]+.*<\/string>/\$VERSION<\/string>/g" ${MODULE}/plugin.xml -done -for MODULE in ${SUBMODULES[@]} -do - # Updates the dependency version in plugin.xml - sed -E -i '' "s/\/s/version="[^"]*"/version="'$VERSION'"/' $HMS_PLUGIN_XML_PATH +npm --prefix $CORE_PACKAGE_PATH version $VERSION +npm --prefix $HMS_PACKAGE_PATH version $VERSION \ No newline at end of file diff --git a/tools/generate-header.sh b/tools/generate-header.sh deleted file mode 100755 index 33d4eba4..00000000 --- a/tools/generate-header.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash -e - -ROOT=`dirname "${0}"`/.. -AIRSHIP=$ROOT/src/ios/Airship - -HEADERS=`find $AIRSHIP -name '*.h'`; - -for file in $HEADERS -do - echo "" -done diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000..35a5dd83 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "baseUrl": "./", + "paths": { + "@ua/airship-cordova": ["./types/index.d.ts"] + }, + "allowUnreachableCode": false, + "allowUnusedLabels": false, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "lib": ["esnext"], + "module": "esnext", + "moduleResolution": "node", + "noFallthroughCasesInSwitch": true, + "noImplicitReturns": true, + "noImplicitUseStrict": false, + "noStrictGenericChecks": false, + "noUncheckedIndexedAccess": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "strict": true, + "target": "esnext" + } +} \ No newline at end of file diff --git a/urbanairship-accengage-cordova/README.md b/urbanairship-accengage-cordova/README.md deleted file mode 100644 index 6b31bbf8..00000000 --- a/urbanairship-accengage-cordova/README.md +++ /dev/null @@ -1,23 +0,0 @@ -# Urban Airship Accengage Cordova Plugin - -This plugin supports Cordova apps running on both iOS and Android. - -### Issues - -Please visit http://support.urbanairship.com/ for any issues integrating or using this plugin. - -### Requirements: - - cordova >= 9.0.1 - - cordova-ios >= 5.0.1 - - cococapods >= 1.7.3 - - urbanairship-cordova >= 10.1.0 - -#### iOS: -- Xcode 11+ - -### Quickstart - -Install this plugin using Cordova CLI: - - cordova plugin add urbanairship-accengage-cordova - diff --git a/urbanairship-accengage-cordova/package.json b/urbanairship-accengage-cordova/package.json deleted file mode 100644 index 79c796e0..00000000 --- a/urbanairship-accengage-cordova/package.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "name": "urbanairship-accengage-cordova", - "version": "14.11.0", - "description": "Urban Airship-Accengage Cordova plugin", - "cordova": { - "id": "urbanairship-accengage-cordova", - "platforms": [ - "ios", - "android" - ] - }, - "repository": { - "type": "git", - "url": "git+https://github.com/urbanairship/urbanairship-accengage-cordova.git" - }, - "keywords": [ - "ecosystem:cordova", - "urbanairship", - "accengage", - "cordova-ios", - "cordova-android" - ], - "engines": [ - { - "name": "cordova-android", - "version": ">=10.0.0" - }, - { - "name": "cordova-ios", - "version": ">=6.2.0" - }, - { - "name": "cordova-plugman", - "version": ">=4.2.0" - } - ], - "author": "Urban Airship", - "license": "Apache 2.0", - "homepage": "https://github.com/urbanairship/urbanairship-accengage-cordova.git", - "bugs": { - "url": "https://github.com/urbanairship/urbanairship-accengage-cordova/issues" - } -} diff --git a/urbanairship-accengage-cordova/plugin.xml b/urbanairship-accengage-cordova/plugin.xml deleted file mode 100644 index 1e16c505..00000000 --- a/urbanairship-accengage-cordova/plugin.xml +++ /dev/null @@ -1,48 +0,0 @@ - - - - urbanairship-accengage-cordova - Urban Airship-Accengage Cordova plugin - Apache 2.0 - cordova,urbanairship - https://github.com/urbanairship/urbanairship-accengage-cordova.git - - - - - - - - - - - - - - 14.11.0 - - - - - - - - - - - - - - - - - - - - diff --git a/urbanairship-cordova/plugin.xml b/urbanairship-cordova/plugin.xml deleted file mode 100644 index 3a0ff859..00000000 --- a/urbanairship-cordova/plugin.xml +++ /dev/null @@ -1,210 +0,0 @@ - - - - Urban Airship - Urban Airship Cordova plugin - Apache 2.0 - cordova,urbanairship - https://github.com/urbanairship/urbanairship-cordova.git - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - remote-notification - - - - - 14.11.0 - - - - - - - - - - - development - - - - production - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/urbanairship-cordova/src/android/ConfigUtils.java b/urbanairship-cordova/src/android/ConfigUtils.java deleted file mode 100644 index 9ee6eea3..00000000 --- a/urbanairship-cordova/src/android/ConfigUtils.java +++ /dev/null @@ -1,124 +0,0 @@ -/* Copyright Urban Airship and Contributors */ - -package com.urbanairship.cordova; - -import com.urbanairship.AirshipConfigOptions; -import android.content.Context; -import android.content.res.XmlResourceParser; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import android.util.Log; - -import java.util.HashMap; -import java.util.Locale; -import java.util.Map; - -/** - * Config Utils. - */ -class ConfigUtils { - private static final String UA_PREFIX = "com.urbanairship"; - private static final String SENDER_PREFIX = "sender:"; - - /** - * Convert the log level string to an int. - * - * @param logLevel The log level as a string. - * @param defaultLogLevel Default log level. - * @return The log level. - */ - public static int parseLogLevel(@Nullable String logLevel, int defaultLogLevel) { - if (logLevel == null || logLevel.length() == 0) { - return defaultLogLevel; - } - String logString = logLevel.trim().toLowerCase(); - if (logString.equals("verbose")) { - return Log.VERBOSE; - } else if (logString.equals("debug")) { - return Log.DEBUG; - } else if (logString.equals("info")) { - return Log.INFO; - } else if (logString.equals("warn")) { - return Log.WARN; - } else if (logString.equals("error")) { - return Log.ERROR; - } else if (logString.equals("none")) { - return Log.ASSERT; - } - return defaultLogLevel; - } - - /** - * Parses the sender ID. - * - * @param value The value from config. - * @return The sender ID. - */ - @Nullable - public static String parseSender(@Nullable String value) { - if (value == null) { - return null; - } - - if (value.startsWith("sender:")) { - return value.substring(SENDER_PREFIX.length()); - } - - return value; - } - - /** - * Parses a cloud site from a String. - * - * @param value The value to parse. - * @return The parsed site value. Defaults to US if site is null or does not match EU. - */ - @NonNull - @AirshipConfigOptions.Site - public static String parseCloudSite(@Nullable String value) { - if (AirshipConfigOptions.SITE_EU.equalsIgnoreCase(value)) { - return AirshipConfigOptions.SITE_EU; - } - return AirshipConfigOptions.SITE_US; - } - - /** - * Parses the config.xml file for any Urban Airship config. - * - * @param context The application context. - */ - @NonNull - public static Map parseConfigXml(@NonNull Context context) { - Map config = new HashMap(); - int id = context.getResources().getIdentifier("config", "xml", context.getPackageName()); - if (id == 0) { - return config; - } - - XmlResourceParser xml = context.getResources().getXml(id); - - int eventType = -1; - while (eventType != XmlResourceParser.END_DOCUMENT) { - - if (eventType == XmlResourceParser.START_TAG) { - if (xml.getName().equals("preference")) { - String name = xml.getAttributeValue(null, "name").toLowerCase(Locale.US); - String value = xml.getAttributeValue(null, "value"); - - if (name.startsWith(UA_PREFIX) && value != null) { - config.put(name, value); - PluginLogger.verbose("Found %s in config.xml with value: %s", name, value); - } - } - } - - try { - eventType = xml.next(); - } catch (Exception e) { - PluginLogger.error(e, "Error parsing config file"); - } - } - - return config; - } -} diff --git a/urbanairship-cordova/src/android/CordovaAutopilot.java b/urbanairship-cordova/src/android/CordovaAutopilot.java deleted file mode 100644 index a1dc3ab1..00000000 --- a/urbanairship-cordova/src/android/CordovaAutopilot.java +++ /dev/null @@ -1,248 +0,0 @@ -/* Copyright Urban Airship and Contributors */ - -package com.urbanairship.cordova; - -import android.content.Context; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageManager; -import android.preference.PreferenceManager; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.annotation.XmlRes; -import androidx.core.app.NotificationManagerCompat; - -import com.urbanairship.AirshipConfigOptions; -import com.urbanairship.Autopilot; -import com.urbanairship.UAirship; -import com.urbanairship.actions.DeepLinkListener; -import com.urbanairship.analytics.Analytics; -import com.urbanairship.channel.AirshipChannelListener; -import com.urbanairship.cordova.events.ShowInboxEvent; -import com.urbanairship.cordova.events.PreferenceCenterEvent; -import com.urbanairship.messagecenter.InboxListener; -import com.urbanairship.messagecenter.MessageCenter; -import com.urbanairship.preferencecenter.PreferenceCenter; -import com.urbanairship.push.NotificationActionButtonInfo; -import com.urbanairship.push.NotificationInfo; -import com.urbanairship.push.NotificationListener; -import com.urbanairship.push.PushListener; -import com.urbanairship.push.PushMessage; -import com.urbanairship.push.PushTokenListener; - -/** - * The Urban Airship autopilot to automatically handle takeOff. - */ -public class CordovaAutopilot extends Autopilot { - - private static final String CORDOVA_VERSION_KEY = "com.urbanairship.cordova.version"; - - @Override - public AirshipConfigOptions createAirshipConfigOptions(@NonNull Context context) { - AirshipConfigOptions configOptions = PluginManager.shared(context).getAirshipConfig(); - if (configOptions != null) { - PluginLogger.setLogLevel(configOptions.logLevel); - } - return configOptions; - } - - @Override - public boolean isReady(@NonNull Context context) { - return PluginManager.shared(context).getAirshipConfig() != null; - } - - @Override - public boolean allowEarlyTakeOff(@NonNull Context context) { - return false; - } - - @Override - public void onAirshipReady(@NonNull UAirship airship) { - final Context context = UAirship.getApplicationContext(); - final PluginManager pluginManager = PluginManager.shared(context); - - PluginManager.NotificationsOptedOutFlag optOutFlag = pluginManager.getDisableNotificationsOnOptOut(); - if (optOutFlag != null) { - if (!NotificationManagerCompat.from(context).areNotificationsEnabled()) { - switch(optOutFlag) { - case ONCE: - if (!pluginManager.getProcessedNotificationOptOutFlag()) { - airship.getPushManager().setUserNotificationsEnabled(false); - } - break; - case ALWAYS: - airship.getPushManager().setUserNotificationsEnabled(false); - break; - } - } - pluginManager.editConfig().setProcessedNotificationsOptedOutFlag(true).apply(); - } - - if (pluginManager.getEnablePushOnLaunch()) { - airship.getPushManager().setUserNotificationsEnabled(true); - } - - registerCordovaPluginVersion(context, airship); - - // Cordova notification provider - airship.getPushManager().setNotificationProvider(new CordovaNotificationProvider(context, PluginManager.shared(context))); - - // Deep link - airship.setDeepLinkListener(new DeepLinkListener() { - @Override - public boolean onDeepLink(@NonNull String deepLink) { - pluginManager.deepLinkReceived(deepLink); - return true; - } - }); - - airship.getChannel().addChannelListener(new AirshipChannelListener() { - @Override - public void onChannelCreated(@NonNull String channelId) { - PluginLogger.info("Channel created. Channel ID: %s.", channelId); - PluginManager.shared(context).channelUpdated(channelId, true); - PluginManager.shared(context).checkOptInStatus(); - } - - @Override - public void onChannelUpdated(@NonNull String channelId) { - PluginLogger.info("Channel updated. Channel ID: %s.", channelId); - PluginManager.shared(context).channelUpdated(channelId, true); - PluginManager.shared(context).checkOptInStatus(); - } - }); - - - airship.getPushManager().addPushTokenListener(new PushTokenListener() { - @Override - public void onPushTokenUpdated(@NonNull String pushToken) { - PluginLogger.info("Push token updated. Token: %s.", pushToken); - } - }); - - airship.getPushManager().addPushListener(new PushListener() { - @Override - public void onPushReceived(@NonNull PushMessage message, boolean notificationPosted) { - if (!notificationPosted) { - PluginLogger.info("Silent push received."); - PluginManager.shared(context).pushReceived(null, message); - } - } - }); - - airship.getPushManager().setNotificationListener(new NotificationListener() { - @Override - public void onNotificationPosted(@NonNull NotificationInfo notificationInfo) { - PluginLogger.info("Notification posted. Alert: %s. NotificationId: %s", notificationInfo.getMessage().getAlert(), notificationInfo.getNotificationId()); - PluginManager.shared(context).pushReceived(notificationInfo.getNotificationId(), notificationInfo.getMessage()); - } - - @Override - public boolean onNotificationOpened(@NonNull NotificationInfo notificationInfo) { - PluginLogger.info("Notification opened. Alert: %s. NotificationId: %s", notificationInfo.getMessage().getAlert(), notificationInfo.getNotificationId()); - PluginManager.shared(context).notificationOpened(notificationInfo); - - // Return false here to allow Urban Airship to auto launch the launcher activity - return false; - } - - @Override - public boolean onNotificationForegroundAction(@NonNull NotificationInfo notificationInfo, @NonNull NotificationActionButtonInfo notificationActionButtonInfo) { - PluginLogger.info("Notification action button opened. Button ID: %s. Alert: %s. NotificationId: %s", notificationActionButtonInfo.getButtonId(), notificationInfo.getMessage().getAlert(), notificationInfo.getNotificationId()); - PluginManager.shared(context).notificationOpened(notificationInfo, notificationActionButtonInfo); - - // Return false here to allow Urban Airship to auto launch the launcher - // activity for foreground notification action buttons - return false; - } - - @Override - public void onNotificationBackgroundAction(@NonNull NotificationInfo notificationInfo, @NonNull NotificationActionButtonInfo notificationActionButtonInfo) { - PluginLogger.info("Notification action button opened. Button ID: %s. Alert: %s. NotificationId: %s", notificationActionButtonInfo.getButtonId(), notificationInfo.getMessage().getAlert(), notificationInfo.getNotificationId()); - PluginManager.shared(context).notificationOpened(notificationInfo, notificationActionButtonInfo); - } - - @Override - public void onNotificationDismissed(@NonNull NotificationInfo notificationInfo) { - PluginLogger.info("Notification dismissed. Notification ID: %s.", notificationInfo.getNotificationId()); - } - }); - - // Inbox updates - MessageCenter.shared().getInbox().addListener(new InboxListener() { - @Override - public void onInboxUpdated() { - pluginManager.inboxUpdated(); - } - }); - - - MessageCenter.shared().setOnShowMessageCenterListener(new MessageCenter.OnShowMessageCenterListener() { - @Override - public boolean onShowMessageCenter(@Nullable String messageId) { - if (PluginManager.shared(UAirship.getApplicationContext()).getAutoLaunchMessageCenter()) { - return false; - } else { - sendShowInboxEvent(messageId); - return true; - } - } - }); - - PreferenceCenter.shared().setOpenListener(new PreferenceCenter.OnOpenListener() { - @Override - public boolean onOpenPreferenceCenter(String preferenceCenterId) { - boolean isCustomPreferenceCenterUiEnabled = pluginManager.getUseCustomPreferenceCenterUi(preferenceCenterId); - if (isCustomPreferenceCenterUiEnabled) { - sendPreferenceCenterEvent(preferenceCenterId); - return true; - } else { - return false; - } - } - }); - - loadCustomNotificationButtonGroups(context, airship); - loadCustomNotificationChannels(context, airship); - } - - private void registerCordovaPluginVersion(@NonNull Context context, @NonNull UAirship airship) { - try { - ApplicationInfo info = context.getPackageManager().getApplicationInfo(context.getPackageName(), PackageManager.GET_META_DATA); - if (info.metaData != null) { - String version = info.metaData.getString(CORDOVA_VERSION_KEY, "0.0.0"); - airship.getAnalytics().registerSDKExtension(Analytics.EXTENSION_CORDOVA, version); - } - } catch (PackageManager.NameNotFoundException e) { - PluginLogger.error(e, "Failed to get package info."); - } - } - - private void loadCustomNotificationButtonGroups(Context context, UAirship airship) { - @XmlRes int resId = context.getResources().getIdentifier("ua_custom_notification_buttons", "xml", context.getPackageName()); - - if (resId != 0) { - PluginLogger.debug("Loading custom notification button groups"); - airship.getPushManager().addNotificationActionButtonGroups(context, resId); - } - } - - private void loadCustomNotificationChannels(Context context, UAirship airship) { - @XmlRes int resId = context.getResources().getIdentifier("ua_custom_notification_channels", "xml", context.getPackageName()); - - if (resId != 0) { - PluginLogger.debug("Loading custom notification channels"); - airship.getPushManager().getNotificationChannelRegistry().createNotificationChannels(resId); - } - } - - private static void sendShowInboxEvent(@NonNull String messageId) { - Context context = UAirship.getApplicationContext(); - PluginManager.shared(context).sendShowInboxEvent(new ShowInboxEvent(messageId)); - } - - private static void sendPreferenceCenterEvent(@NonNull String preferenceCenterId) { - Context context = UAirship.getApplicationContext(); - PluginManager.shared(context).sendPreferenceCenterEvent(new PreferenceCenterEvent(preferenceCenterId)); - } -} diff --git a/urbanairship-cordova/src/android/CordovaNotificationProvider.java b/urbanairship-cordova/src/android/CordovaNotificationProvider.java deleted file mode 100644 index 4bc1677f..00000000 --- a/urbanairship-cordova/src/android/CordovaNotificationProvider.java +++ /dev/null @@ -1,88 +0,0 @@ -package com.urbanairship.cordova; - -import android.content.Context; - -import androidx.annotation.ColorInt; -import androidx.annotation.DrawableRes; -import androidx.annotation.NonNull; -import androidx.core.app.NotificationCompat; - -import com.urbanairship.app.GlobalActivityMonitor; -import com.urbanairship.push.PushMessage; -import com.urbanairship.push.notifications.AirshipNotificationProvider; -import com.urbanairship.push.notifications.NotificationArguments; -import com.urbanairship.push.notifications.NotificationResult; - -/** - * Notification provider that pulls its config from the {@link PluginManager}. - */ -public class CordovaNotificationProvider extends AirshipNotificationProvider { - - @NonNull - public static final String PUSH_MESSAGE_BUNDLE_EXTRA = "com.urbanairship.push_bundle"; - - private final PluginManager pluginManager; - - public CordovaNotificationProvider(@NonNull Context context, @NonNull PluginManager pluginManager) { - super(context, pluginManager.getAirshipConfig()); - this.pluginManager = pluginManager; - } - - @Override - public String getDefaultNotificationChannelId() { - String defaultChannelId = pluginManager.getDefaultNotificationChannelId(); - if (defaultChannelId != null) { - return defaultChannelId; - } - - return super.getDefaultNotificationChannelId(); - } - - @NonNull - @Override - public NotificationResult onCreateNotification(@NonNull Context context, @NonNull NotificationArguments arguments) { - if (!shouldDisplay(context, arguments)) { - return NotificationResult.cancel(); - } - return super.onCreateNotification(context, arguments); - } - - @NonNull - @Override - protected NotificationCompat.Builder onExtendBuilder(@NonNull Context context, @NonNull NotificationCompat.Builder builder, @NonNull NotificationArguments arguments) { - builder.getExtras().putBundle(PUSH_MESSAGE_BUNDLE_EXTRA, arguments.getMessage().getPushBundle()); - return super.onExtendBuilder(context, builder, arguments); - } - - @Override - @DrawableRes - public int getSmallIcon() { - int id = pluginManager.getNotificationIcon(); - - return id != 0 ? id : super.getSmallIcon(); - } - - @Override - @DrawableRes - public int getLargeIcon() { - int id = pluginManager.getNotificationLargeIcon(); - - return id != 0 ? id : super.getLargeIcon(); - } - - @Override - @ColorInt - public int getDefaultAccentColor() { - int id = pluginManager.getNotificationAccentColor(); - - return id != 0 ? id : super.getDefaultAccentColor(); - } - - private boolean shouldDisplay(@NonNull Context context, @NonNull NotificationArguments arguments) { - // If push does not define foreground display behavior fallback to plugin - if (arguments.getMessage().getExtra(PushMessage.EXTRA_FOREGROUND_DISPLAY) == null) { - return pluginManager.isForegroundNotificationsEnabled() || !GlobalActivityMonitor.shared(context).isAppForegrounded(); - } - return true; - } -} diff --git a/urbanairship-cordova/src/android/CustomMessageActivity.java b/urbanairship-cordova/src/android/CustomMessageActivity.java deleted file mode 100644 index d8a995ae..00000000 --- a/urbanairship-cordova/src/android/CustomMessageActivity.java +++ /dev/null @@ -1,30 +0,0 @@ -/* Copyright Urban Airship and Contributors */ - -package com.urbanairship.cordova; - -import android.content.Intent; -import android.os.Bundle; -import androidx.annotation.Nullable; - -import com.urbanairship.messagecenter.MessageActivity; - -public class CustomMessageActivity extends MessageActivity { - public static final String CLOSE_INTENT_ACTION = "CANCEL"; - - @Override - protected void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - if (getIntent() != null && CLOSE_INTENT_ACTION.equals(getIntent().getAction())) { - finish(); - } - } - - @Override - protected void onNewIntent(@Nullable Intent intent) { - super.onNewIntent(intent); - if (intent != null && CLOSE_INTENT_ACTION.equals(intent.getAction())) { - finish(); - } - } -} diff --git a/urbanairship-cordova/src/android/CustomMessageCenterActivity.java b/urbanairship-cordova/src/android/CustomMessageCenterActivity.java deleted file mode 100644 index 385bc93a..00000000 --- a/urbanairship-cordova/src/android/CustomMessageCenterActivity.java +++ /dev/null @@ -1,33 +0,0 @@ -/* Copyright Urban Airship and Contributors */ - -package com.urbanairship.cordova; - -import android.content.Intent; -import android.os.Bundle; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.urbanairship.messagecenter.MessageCenterActivity; - -public class CustomMessageCenterActivity extends MessageCenterActivity { - - @NonNull - public static final String CLOSE_INTENT_ACTION = "CANCEL"; - - @Override - protected void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - if (getIntent() != null && CLOSE_INTENT_ACTION.equals(getIntent().getAction())) { - finish(); - } - } - - @Override - protected void onNewIntent(@Nullable Intent intent) { - super.onNewIntent(intent); - if (intent != null && CLOSE_INTENT_ACTION.equals(intent.getAction())) { - finish(); - } - } -} diff --git a/urbanairship-cordova/src/android/PluginLogger.java b/urbanairship-cordova/src/android/PluginLogger.java deleted file mode 100644 index ea849501..00000000 --- a/urbanairship-cordova/src/android/PluginLogger.java +++ /dev/null @@ -1,232 +0,0 @@ -/* Copyright Urban Airship and Contributors */ - -package com.urbanairship.cordova; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.annotation.RestrictTo; -import android.util.Log; - -import com.urbanairship.util.UAStringUtil; - -import java.util.Locale; - -/** - * Cordova logger for Urban Airship. - */ -public final class PluginLogger { - - @NonNull - private static final String TAG = "UALib-Cordova"; - - /** - * The current log level, as defined by android.util.Log. - * Defaults to android.util.Log.ERROR. - */ - private static int logLevel = Log.INFO; - - /** - * Private, unused constructor - */ - private PluginLogger() { - } - - /** - * Sets the log level. - * - * @param logLevel The log level. - */ - @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) - public static void setLogLevel(int logLevel) { - PluginLogger.logLevel = logLevel; - } - - /** - * Send a warning log message. - * - * @param message The message you would like logged. - * @param args The message args. - */ - @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) - public static void warn(@NonNull String message, @Nullable Object... args) { - log(Log.WARN, null, message, args); - } - - /** - * Send a warning log message. - * - * @param t An exception to log - * @param message The message you would like logged. - * @param args The message args. - */ - @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) - public static void warn(@NonNull Throwable t, @NonNull String message, @Nullable Object... args) { - log(Log.WARN, t, message, args); - } - - /** - * Send a warning log message. - * - * @param t An exception to log - */ - @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) - public static void warn(@NonNull Throwable t) { - log(Log.WARN, t, null); - } - - /** - * Send a verbose log message. - * - * @param message The message you would like logged. - * @param args The message args. - */ - @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) - public static void verbose(@NonNull String message, @Nullable Object... args) { - log(Log.VERBOSE, null, message, args); - } - - /** - * Send a debug log message. - * - * @param message The message you would like logged. - * @param args The message args. - */ - @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) - public static void debug(@NonNull String message, @Nullable Object... args) { - log(Log.DEBUG, null, message, args); - } - - /** - * Send a debug log message. - * - * @param t An exception to log - * @param message The message you would like logged. - * @param args The message args. - */ - @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) - public static void debug(@NonNull Throwable t, @NonNull String message, @Nullable Object... args) { - log(Log.DEBUG, t, message, args); - } - - /** - * Send an info log message. - * - * @param message The message you would like logged. - * @param args The message args. - */ - @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) - public static void info(@NonNull String message, @NonNull Object... args) { - log(Log.INFO, null, message, args); - } - - /** - * Send an info log message. - * - * @param t An exception to log - * @param message The message you would like logged. - * @param args The message args. - */ - @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) - public static void info(@NonNull Throwable t, @NonNull String message, @Nullable Object... args) { - log(Log.INFO, t, message, args); - } - - /** - * Send an error log message. - * - * @param message The message you would like logged. - * @param args The message args. - */ - @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) - public static void error(@NonNull String message, @Nullable Object... args) { - log(Log.ERROR, null, message, args); - } - - /** - * Send an error log message. - * - * @param t An exception to log - */ - @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) - public static void error(@NonNull Throwable t) { - log(Log.ERROR, t, null); - } - - /** - * Send an error log message. - * - * @param t An exception to log - * @param message The message you would like logged. - * @param args The message args. - */ - @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) - public static void error(@NonNull Throwable t, @NonNull String message, @Nullable Object... args) { - log(Log.ERROR, t, message, args); - } - - /** - * Helper method that performs the logging. - * - * @param priority The log priority level. - * @param throwable The optional exception. - * @param message The optional message. - * @param args The optional message args. - */ - private static void log(int priority, @Nullable Throwable throwable, @Nullable String message, @Nullable Object... args) { - if (logLevel > priority) { - return; - } - - if (message == null && throwable == null) { - return; - } - - String formattedMessage; - - if (UAStringUtil.isEmpty(message)) { - // Default to empty string - formattedMessage = ""; - } else { - // Format the message if we have arguments - try { - formattedMessage = (args == null || args.length == 0) ? message : String.format(Locale.ROOT, message, args); - } catch (Exception e) { - Log.wtf(TAG, "Failed to format log.", e); - return; - } - } - - // Log directly if we do not have a throwable - if (throwable == null) { - if (priority == Log.ASSERT) { - Log.wtf(TAG, formattedMessage); - } else { - Log.println(priority, TAG, formattedMessage); - } - return; - } - - // Log using one of the provided log methods - switch (priority) { - case Log.INFO: - Log.i(TAG, formattedMessage, throwable); - break; - case Log.DEBUG: - Log.d(TAG, formattedMessage, throwable); - break; - case Log.VERBOSE: - Log.v(TAG, formattedMessage, throwable); - break; - case Log.WARN: - Log.w(TAG, formattedMessage, throwable); - break; - case Log.ERROR: - Log.e(TAG, formattedMessage, throwable); - break; - case Log.ASSERT: - Log.wtf(TAG, formattedMessage, throwable); - break; - } - } - -} \ No newline at end of file diff --git a/urbanairship-cordova/src/android/PluginManager.java b/urbanairship-cordova/src/android/PluginManager.java deleted file mode 100644 index b2235bdf..00000000 --- a/urbanairship-cordova/src/android/PluginManager.java +++ /dev/null @@ -1,749 +0,0 @@ -/* Copyright Urban Airship and Contributors */ - -package com.urbanairship.cordova; - -import android.annotation.SuppressLint; -import android.content.Context; -import android.content.SharedPreferences; -import android.graphics.Color; -import android.net.Uri; -import android.util.Log; - -import androidx.annotation.ColorInt; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.urbanairship.AirshipConfigOptions; -import com.urbanairship.PrivacyManager; -import com.urbanairship.UAirship; -import com.urbanairship.cordova.events.DeepLinkEvent; -import com.urbanairship.cordova.events.Event; -import com.urbanairship.cordova.events.InboxEvent; -import com.urbanairship.cordova.events.NotificationOpenedEvent; -import com.urbanairship.cordova.events.NotificationOptInEvent; -import com.urbanairship.cordova.events.PreferenceCenterEvent; -import com.urbanairship.cordova.events.PushEvent; -import com.urbanairship.cordova.events.RegistrationEvent; -import com.urbanairship.cordova.events.ShowInboxEvent; -import com.urbanairship.push.NotificationActionButtonInfo; -import com.urbanairship.push.NotificationInfo; -import com.urbanairship.push.PushMessage; -import com.urbanairship.util.UAStringUtil; - -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; -import java.util.Map; - -/** - * Plugin manager. - */ -public class PluginManager { - - enum NotificationsOptedOutFlag { - ALWAYS, - ONCE - } - - /** - * Interface when a new event is received. - */ - public interface Listener { - void onEvent(@NonNull Event event); - } - - private static final String PREFERENCE_FILE = "com.urbanairship.ua_plugin_shared_preferences"; - - private static final String PRODUCTION_KEY = "com.urbanairship.production_app_key"; - private static final String PRODUCTION_SECRET = "com.urbanairship.production_app_secret"; - private static final String DEVELOPMENT_KEY = "com.urbanairship.development_app_key"; - private static final String DEVELOPMENT_SECRET = "com.urbanairship.development_app_secret"; - private static final String PRODUCTION_LOG_LEVEL = "com.urbanairship.production_log_level"; - private static final String DEVELOPMENT_LOG_LEVEL = "com.urbanairship.development_log_level"; - private static final String IN_PRODUCTION = "com.urbanairship.in_production"; - private static final String ENABLE_PUSH_ONLAUNCH = "com.urbanairship.enable_push_onlaunch"; - - private static final String DISABLE_ANDROID_NOTIFICATIONS_ON_OPT_OUT = "com.urbanairship.android.disable_user_notifications_on_system_opt_out"; - private static final String PROCESSED_NOTIFICATIONS_OPTED_OUT_FLAG = "com.urbanairship.PROCESSED_NOTIFICATIONS_OPTED_OUT_FLAG"; - - private static final String NOTIFICATION_ICON = "com.urbanairship.notification_icon"; - private static final String NOTIFICATION_LARGE_ICON = "com.urbanairship.notification_large_icon"; - private static final String NOTIFICATION_ACCENT_COLOR = "com.urbanairship.notification_accent_color"; - private static final String NOTIFICATION_SOUND = "com.urbanairship.notification_sound"; - static final String AUTO_LAUNCH_MESSAGE_CENTER = "com.urbanairship.auto_launch_message_center"; - private static final String ENABLE_ANALYTICS = "com.urbanairship.enable_analytics"; - private static final String CLOUD_SITE = "com.urbanairship.site"; - private static final String FCM_FIREBASE_APP_NAME = "com.urbanairship.fcm_firebase_app_name"; - private static final String INITIAL_CONFIG_URL = "com.urbanairship.initial_config_url"; - - private static final String NOTIFICATION_OPT_IN_STATUS_EVENT_PREFERENCES_KEY = "com.urbanairship.notification_opt_in_status_preferences"; - - private static final String DEFAULT_NOTIFICATION_CHANNEL_ID = "com.urbanairship.default_notification_channel_id"; - private static final String FOREGROUND_NOTIFICATIONS = "com.urbanairship.foreground_notifications"; - - private static PluginManager instance; - private final Object lock = new Object(); - - private NotificationOpenedEvent notificationOpenedEvent; - private DeepLinkEvent deepLinkEvent = null; - private Listener listener = null; - private final List pendingEvents = new ArrayList(); - - private final SharedPreferences sharedPreferences; - private final Map defaultConfigValues; - private final Context context; - private AirshipConfigOptions configOptions; - private boolean isAirshipAvailable = false; - - private PluginManager(@NonNull Context context) { - this.context = context.getApplicationContext(); - this.sharedPreferences = context.getSharedPreferences(PREFERENCE_FILE, Context.MODE_PRIVATE); - this.defaultConfigValues = ConfigUtils.parseConfigXml(context); - } - - /** - * Gets the shared instance. - * - * @param context The context. - * @return The shared instance. - */ - public synchronized static PluginManager shared(@NonNull Context context) { - if (instance == null) { - instance = new PluginManager(context); - } - - return instance; - } - - /** - * Called when the inbox is updated. - */ - public void inboxUpdated() { - notifyListener(new InboxEvent()); - } - - /** - * Called when a push is received. - * - * @param notificationId The notification ID. - * @param pushMessage The push message. - */ - public void pushReceived(@Nullable Integer notificationId, @NonNull PushMessage pushMessage) { - notifyListener(new PushEvent(notificationId, pushMessage)); - } - - /** - * Called when a new deep link is received. - * - * @param deepLink The deep link. - */ - public void deepLinkReceived(@NonNull String deepLink) { - synchronized (lock) { - DeepLinkEvent event = new DeepLinkEvent(deepLink); - this.deepLinkEvent = event; - - if (!notifyListener(event)) { - pendingEvents.add(event); - } - } - } - - /** - * Called to open the inbox when auto launch is disabled. - * - * @param showInboxEvent The show inbox event. - */ - public void sendShowInboxEvent(@NonNull ShowInboxEvent showInboxEvent) { - synchronized (lock) { - if (!notifyListener(showInboxEvent)) { - pendingEvents.add(showInboxEvent); - } - } - } - - /** - * Called to open the preference center when use custom UI is disabled. - * - * @param preferenceCenterEvent . - */ - public void sendPreferenceCenterEvent(@NonNull PreferenceCenterEvent preferenceCenterEvent) { - synchronized (lock) { - if (!notifyListener(preferenceCenterEvent)) { - pendingEvents.add(preferenceCenterEvent); - } - } - } - - /** - * Called on app resume and when registration changes. - */ - public void checkOptInStatus() { - boolean optIn = UAirship.shared().getPushManager().isOptIn(); - - // Check preferences for opt-in - if (sharedPreferences.getBoolean(NOTIFICATION_OPT_IN_STATUS_EVENT_PREFERENCES_KEY, false) != optIn) { - sharedPreferences.edit() - .putBoolean(NOTIFICATION_OPT_IN_STATUS_EVENT_PREFERENCES_KEY, optIn) - .apply(); - notifyListener(new NotificationOptInEvent(optIn)); - } - } - - /** - * Gets the default notification channel ID. - * - * @return The default notification channel ID. - */ - @Nullable - public String getDefaultNotificationChannelId() { - return sharedPreferences.getString(DEFAULT_NOTIFICATION_CHANNEL_ID, null); - } - - public boolean getUseCustomPreferenceCenterUi(@NonNull String preferenceCenterId) { - return sharedPreferences.getBoolean(useCustomPreferenceCenterUiKey(preferenceCenterId), false); - } - - public boolean isForegroundNotificationsEnabled() { - return sharedPreferences.getBoolean(FOREGROUND_NOTIFICATIONS, true); - } - - private static String useCustomPreferenceCenterUiKey(@NonNull String preferenceCenterId) { - return "preference_" + preferenceCenterId + "_use_custom_ui"; - } - - /** - * Called when the notification is opened. - * - * @param notificationInfo The notification info. - */ - public void notificationOpened(@NonNull NotificationInfo notificationInfo) { - notificationOpened(new NotificationOpenedEvent(notificationInfo)); - } - - /** - * Called when the notification is opened. - * - * @param notificationInfo The notification info. - */ - public void notificationOpened(@NonNull NotificationInfo notificationInfo, @Nullable NotificationActionButtonInfo actionButtonInfo) { - notificationOpened(new NotificationOpenedEvent(notificationInfo, actionButtonInfo)); - } - - private void notificationOpened(@NonNull NotificationOpenedEvent event) { - synchronized (lock) { - this.notificationOpenedEvent = event; - - if (!notifyListener(event)) { - pendingEvents.add(event); - } - } - } - - /** - * Called when the channel is updated. - * - * @param channel The channel ID. - * @param success {@code true} if the channel updated successfully, otherwise {@code false}. - */ - public void channelUpdated(@Nullable String channel, boolean success) { - notifyListener(new RegistrationEvent(channel, UAirship.shared().getPushManager().getPushToken(), success)); - } - - /** - * Returns {@code true} if Airship is available, i.e., you can call UAirship.shared() and - * it should return an instance. - * - * @return {@code true} if airship is available, otherwise {@code false}. - */ - public boolean isAirshipAvailable() { - if (isAirshipAvailable) { - return true; - } - - if (getAirshipConfig() == null) { - return false; - } - - if (UAirship.isFlying() || UAirship.isTakingOff()) { - isAirshipAvailable = true; - return true; - } - - try { - UAirship.shared(); - isAirshipAvailable = true; - } catch (IllegalArgumentException e) { - // ignore - } - - return isAirshipAvailable; - } - - /** - * Returns the last deep link event. - * - * @param clear {@code true} to clear the event, otherwise {@code false}. - * @return The deep link event, or null if the event is not available. - */ - @Nullable - public DeepLinkEvent getLastDeepLinkEvent(boolean clear) { - synchronized (lock) { - DeepLinkEvent event = this.deepLinkEvent; - if (clear) { - this.deepLinkEvent = null; - } - - return event; - } - } - - /** - * Returns the last notification opened event. - * - * @param clear {@code true} to clear the event, otherwise {@code false}. - * @return The notification opened event, or null if the event is not available. - */ - @Nullable - public NotificationOpenedEvent getLastLaunchNotificationEvent(boolean clear) { - synchronized (lock) { - NotificationOpenedEvent event = this.notificationOpenedEvent; - if (clear) { - this.notificationOpenedEvent = null; - } - - return event; - } - } - - /** - * Sets the event listener. - * - * @param listener The event listener. - */ - public void setListener(@Nullable Listener listener) { - synchronized (lock) { - this.listener = listener; - - if (listener != null && !pendingEvents.isEmpty()) { - for (Event event : pendingEvents) { - notifyListener(event); - } - pendingEvents.clear(); - } - } - } - - /** - * Gets the airship config for this instance. - * - * @return The airship config if available, or null if the plugin is not configured. - */ - @SuppressLint("RestrictedApi") - @Nullable - public AirshipConfigOptions getAirshipConfig() { - if (configOptions != null) { - return configOptions; - } - - if (!hasConfig(DEVELOPMENT_KEY) && !hasConfig(DEVELOPMENT_SECRET) && !hasConfig(PRODUCTION_KEY) && !hasConfig(PRODUCTION_SECRET)) { - return null; - } - - AirshipConfigOptions.Builder builder = new AirshipConfigOptions.Builder() - .setDevelopmentAppKey(getConfigString(DEVELOPMENT_KEY, "")) - .setDevelopmentAppSecret(getConfigString(DEVELOPMENT_SECRET, "")) - .setProductionAppKey(getConfigString(PRODUCTION_KEY, "")) - .setProductionAppSecret(getConfigString(PRODUCTION_SECRET, "")) - .setAnalyticsEnabled(getConfigBoolean(ENABLE_ANALYTICS, true)) - .setDevelopmentLogLevel(ConfigUtils.parseLogLevel(getConfigString(DEVELOPMENT_LOG_LEVEL, ""), Log.DEBUG)) - .setProductionLogLevel(ConfigUtils.parseLogLevel(getConfigString(PRODUCTION_LOG_LEVEL, ""), Log.ERROR)) - .setSite(ConfigUtils.parseCloudSite(getConfigValue(CLOUD_SITE))) - .setEnabledFeatures(PrivacyManager.FEATURE_ALL) - .setUrlAllowListScopeOpenUrl(new String[]{"*"}); - - if (hasConfig(FCM_FIREBASE_APP_NAME)) { - builder.setFcmFirebaseAppName(getConfigString(FCM_FIREBASE_APP_NAME, "")); - } - - if (hasConfig(INITIAL_CONFIG_URL)) { - builder.setInitialConfigUrl(getConfigString(INITIAL_CONFIG_URL, null)); - } - - if (hasConfig(IN_PRODUCTION)) { - builder.setInProduction(getConfigBoolean(IN_PRODUCTION, false)); - } else { - builder.detectProvisioningMode(context); - } - - try { - AirshipConfigOptions config = builder.build(); - config.validate(); - configOptions = config; - return configOptions; - } catch (IllegalArgumentException e) { - PluginLogger.error(e, "Invalid AirshipConfig"); - return null; - } - } - - /** - * Gets the enable push on launch option. - * - * @return {@code true} to enable push on launch, otherwise {@code false}. - */ - public boolean getEnablePushOnLaunch() { - return getConfigBoolean(ENABLE_PUSH_ONLAUNCH, false); - } - - @Nullable - public NotificationsOptedOutFlag getDisableNotificationsOnOptOut() { - String disableNotifications = getConfigString(DISABLE_ANDROID_NOTIFICATIONS_ON_OPT_OUT, null); - if (UAStringUtil.isEmpty(disableNotifications)) { - return null; - } - - switch (disableNotifications.toLowerCase(Locale.ROOT).trim()) { - case "once": - return NotificationsOptedOutFlag.ONCE; - case "always": - return NotificationsOptedOutFlag.ALWAYS; - default: - PluginLogger.error("Invalid value for %s: %s", DISABLE_ANDROID_NOTIFICATIONS_ON_OPT_OUT, disableNotifications); - } - - return null; - } - - boolean getProcessedNotificationOptOutFlag() { - return sharedPreferences.getBoolean(PROCESSED_NOTIFICATIONS_OPTED_OUT_FLAG, false); - } - - /** - * Gets the auto launch message center option. - * - * @return {@code true} to enable auto launching the message center, otherwise {@code false}. - */ - public boolean getAutoLaunchMessageCenter() { - return getConfigBoolean(AUTO_LAUNCH_MESSAGE_CENTER, true); - } - - /** - * Gets the notification sound. - * - * @return The notification sound. - */ - @Nullable - public Uri getNotificationSound() { - int resource = getConfigResource(NOTIFICATION_SOUND, "raw"); - if (resource != 0) { - return Uri.parse("android.resource://" + context.getPackageName() + "/" + resource); - } - - return null; - } - - /** - * Gets the notification large icon. - * - * @return The notification large icon. - */ - public int getNotificationLargeIcon() { - return getConfigResource(NOTIFICATION_LARGE_ICON, "drawable"); - } - - /** - * Gets the notification accent color. - * - * @return The notification accent color. - */ - public int getNotificationAccentColor() { - return getConfigColor(NOTIFICATION_ACCENT_COLOR, Color.GRAY); - } - - /** - * Gets the notification icon. - * - * @return The notification icon. - */ - public int getNotificationIcon() { - return getConfigResource(NOTIFICATION_ICON, "drawable"); - } - - /** - * Creates a config editor. - * - * @return A config editor. - */ - @NonNull - public ConfigEditor editConfig() { - return new ConfigEditor(sharedPreferences.edit()); - } - - - /** - * Gets a String value from the config. - * - * @param key The config key. - * @param defaultValue Default value if the key does not exist. - * @return The value of the config, or default value. - */ - private String getConfigString(@NonNull String key, String defaultValue) { - String value = getConfigValue(key); - if (value == null) { - return defaultValue; - } - - return value; - } - - /** - * Gets a Boolean value from the config. - * - * @param key The config key. - * @param defaultValue Default value if the key does not exist. - * @return The value of the config, or default value. - */ - private boolean getConfigBoolean(String key, boolean defaultValue) { - String value = getConfigValue(key); - if (value == null) { - return defaultValue; - } - - return Boolean.parseBoolean(value); - } - - /** - * Gets a color value from the config. - * - * @param key The config key. - * @param defaultColor Default value if the key does not exist. - * @return The value of the config, or default value. - */ - @ColorInt - private int getConfigColor(@NonNull String key, @ColorInt int defaultColor) { - String color = getConfigValue(key); - if (!UAStringUtil.isEmpty(color)) { - try { - return Color.parseColor(color); - } catch (IllegalArgumentException e) { - PluginLogger.error(e, "Unable to parse color: %s", color); - } - } - return defaultColor; - } - - - - /** - * Gets a resource value from the config. - * - * @param key The config key. - * @param key The resource folder. - * @return The resource ID or 0 if not found. - */ - private int getConfigResource(@NonNull String key, @NonNull String resourceFolder) { - String resourceName = getConfigString(key, null); - if (!UAStringUtil.isEmpty(resourceName)) { - int id = context.getResources().getIdentifier(resourceName, resourceFolder, context.getPackageName()); - if (id != 0) { - return id; - } else { - PluginLogger.error("Unable to find resource with name: %s", resourceName); - } - } - return 0; - } - - /** - * Checks if a config value is defined. - * - * @param key The key. - * @return {@code true} if the value is not null, otherwise {@code false}. - */ - private boolean hasConfig(@NonNull String key) { - return getConfigValue(key) != null; - } - - /** - * Gets a config value. - * - * @param key The key. - * @return The config value if it exists, otherwise the default config value. - */ - @Nullable - private String getConfigValue(@NonNull String key) { - return sharedPreferences.getString(key, defaultConfigValues.get(key)); - } - - - - /** - * Helper method to notify the listener of the event. - * - * @param event The event. - * @return {@code true} if the listener was notified, otherwise {@code false}. - */ - private boolean notifyListener(@NonNull Event event) { - synchronized (lock) { - if (listener != null) { - listener.onEvent(event); - return true; - } - return false; - } - } - - - /** - * Config editor. - */ - public class ConfigEditor { - private final SharedPreferences.Editor editor; - - private ConfigEditor(@NonNull SharedPreferences.Editor editor) { - this.editor = editor; - } - - /** - * Sets the production app key and secret. - * - * @param appKey The app key. - * @param appSecret The app secret. - * @return The config editor. - */ - @NonNull - public ConfigEditor setProductionConfig(@NonNull String appKey, @NonNull String appSecret) { - editor.putString(PRODUCTION_KEY, appKey) - .putString(PRODUCTION_SECRET, appSecret); - return this; - } - - /** - * Sets the development app key and secret. - * - * @param appKey The app key. - * @param appSecret The app secret. - * @return The config editor. - */ - @NonNull - public ConfigEditor setDevelopmentConfig(@NonNull String appKey, @NonNull String appSecret) { - editor.putString(DEVELOPMENT_KEY, appKey) - .putString(DEVELOPMENT_SECRET, appSecret); - return this; - } - - /** - * Sets the notification icon. - * - * @param icon The icon name. - * @return The config editor. - */ - @NonNull - public ConfigEditor setNotificationIcon(@Nullable String icon) { - if (icon == null) { - editor.remove(NOTIFICATION_ICON); - } else { - editor.putString(NOTIFICATION_ICON, icon); - } - return this; - } - - /** - * Sets the notification large icon. - * - * @param largeIcon The icon name. - * @return The config editor. - */ - @NonNull - public ConfigEditor setNotificationLargeIcon(String largeIcon) { - if (largeIcon == null) { - editor.remove(NOTIFICATION_LARGE_ICON); - } else { - editor.putString(NOTIFICATION_LARGE_ICON, largeIcon); - } - return this; - } - - /** - * Sets the notification accent color. - * - * @param accentColor The accent color. - * @return The config editor. - */ - @NonNull - public ConfigEditor setNotificationAccentColor(String accentColor) { - if (accentColor == null) { - editor.remove(NOTIFICATION_ACCENT_COLOR); - } else { - editor.putString(NOTIFICATION_ACCENT_COLOR, accentColor); - } - return this; - } - - /** - * Sets the default notification channel ID. - * - * @param value The string value. - * @return The config editor. - */ - @NonNull - public ConfigEditor setDefaultNotificationChannelId(@Nullable String value) { - if (value == null) { - editor.remove(DEFAULT_NOTIFICATION_CHANNEL_ID); - } else { - editor.putString(DEFAULT_NOTIFICATION_CHANNEL_ID, value); - } - return this; - } - - /** - * Sets auto launch message center option. - * - * @param autoLaunchMessageCenter {@code true} to enable auto launching the message center, otherwise {@code false}. - * @return The config editor. - */ - @NonNull - public ConfigEditor setAutoLaunchMessageCenter(boolean autoLaunchMessageCenter) { - editor.putString(AUTO_LAUNCH_MESSAGE_CENTER, Boolean.toString(autoLaunchMessageCenter)); - return this; - } - - @NonNull - public ConfigEditor setForegroundNotificationsEnabled(boolean allow) { - editor.putBoolean(FOREGROUND_NOTIFICATIONS, allow); - return this; - } - - @NonNull - public ConfigEditor setProcessedNotificationsOptedOutFlag(boolean optedNotificationsOut) { - editor.putBoolean(PROCESSED_NOTIFICATIONS_OPTED_OUT_FLAG, optedNotificationsOut); - return this; - } - - /** - * Sets the cloud site. - * - * @param site The string value for the site, either "US" or "EU". - * @return The config editor. - */ - @NonNull - public ConfigEditor setCloudSite(String site) { - editor.putString(CLOUD_SITE, site); - return this; - } - - @NonNull - public ConfigEditor setUseCustomPreferenceCenterUi(@NonNull String preferenceCenterId, boolean useCustomUi) { - editor.putBoolean(useCustomPreferenceCenterUiKey(preferenceCenterId), useCustomUi); - return this; - } - - /** - * Applies the changes. - */ - void apply() { - editor.apply(); - } - } - -} \ No newline at end of file diff --git a/urbanairship-cordova/src/android/UAirshipPlugin.java b/urbanairship-cordova/src/android/UAirshipPlugin.java deleted file mode 100644 index cf22496c..00000000 --- a/urbanairship-cordova/src/android/UAirshipPlugin.java +++ /dev/null @@ -1,1651 +0,0 @@ -/* Copyright Urban Airship and Contributors */ - -package com.urbanairship.cordova; - -import android.annotation.SuppressLint; -import android.app.NotificationManager; -import android.content.Context; -import android.content.Intent; -import android.net.Uri; -import android.os.Build; -import android.os.Bundle; -import android.os.Handler; -import android.os.Looper; -import android.preference.PreferenceManager; -import android.service.notification.StatusBarNotification; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.core.app.NotificationManagerCompat; -import androidx.core.util.Consumer; - -import com.urbanairship.Autopilot; -import com.urbanairship.PendingResult; -import com.urbanairship.PrivacyManager; -import com.urbanairship.ResultCallback; -import com.urbanairship.UAirship; -import com.urbanairship.actions.ActionArguments; -import com.urbanairship.actions.ActionCompletionCallback; -import com.urbanairship.actions.ActionResult; -import com.urbanairship.actions.ActionRunRequest; -import com.urbanairship.channel.AttributeEditor; -import com.urbanairship.channel.SubscriptionListEditor; -import com.urbanairship.channel.TagGroupsEditor; -import com.urbanairship.contacts.Scope; -import com.urbanairship.contacts.ScopedSubscriptionListEditor; -import com.urbanairship.cordova.events.DeepLinkEvent; -import com.urbanairship.cordova.events.Event; -import com.urbanairship.cordova.events.NotificationOpenedEvent; -import com.urbanairship.google.PlayServicesUtils; -import com.urbanairship.json.JsonList; -import com.urbanairship.json.JsonMap; -import com.urbanairship.json.JsonValue; -import com.urbanairship.messagecenter.Inbox; -import com.urbanairship.messagecenter.Message; -import com.urbanairship.messagecenter.MessageCenter; -import com.urbanairship.permission.Permission; -import com.urbanairship.permission.PermissionRequestResult; -import com.urbanairship.permission.PermissionStatus; -import com.urbanairship.preferencecenter.PreferenceCenter; -import com.urbanairship.push.PushMessage; -import com.urbanairship.reactive.Observable; -import com.urbanairship.reactive.Subscriber; -import com.urbanairship.util.UAStringUtil; - -import org.apache.cordova.CallbackContext; -import org.apache.cordova.CordovaInterface; -import org.apache.cordova.CordovaPlugin; -import org.apache.cordova.CordovaWebView; -import org.apache.cordova.PluginResult; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Calendar; -import java.util.Date; -import java.util.GregorianCalendar; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - -/** - * The Urban Airship Cordova plugin. - */ -public class UAirshipPlugin extends CordovaPlugin { - - /** - * These actions are only available after takeOff. - */ - private final static List AIRSHIP_ACTIONS = Arrays.asList("setUserNotificationsEnabled", - "isUserNotificationsEnabled", "enableUserNotifications", "isSoundEnabled", "isVibrateEnabled", "isQuietTimeEnabled", "isInQuietTime", - "getLaunchNotification", "getChannelID", "getQuietTime", "getTags", "setTags", "setSoundEnabled", "setVibrateEnabled", - "setQuietTimeEnabled", "setQuietTime", "clearNotifications", "setAnalyticsEnabled", "isAnalyticsEnabled", - "setNamedUser", "getNamedUser", "runAction", "editNamedUserTagGroups", "editChannelTagGroups", "editChannelSubscriptionLists", "editContactSubscriptionLists", "getChannelSubscriptionLists", "getContactSubscriptionLists", "displayMessageCenter", "markInboxMessageRead", - "deleteInboxMessage", "getInboxMessages", "displayInboxMessage", "refreshInbox", "getDeepLink", "setAssociatedIdentifier", - "isAppNotificationsEnabled", "dismissMessageCenter", "dismissInboxMessage", "setAutoLaunchDefaultMessageCenter", - "getActiveNotifications", "clearNotification", "editChannelAttributes", "editNamedUserAttributes", "trackScreen", - "enableFeature", "disableFeature", "setEnabledFeatures", "getEnabledFeatures", "isFeatureEnabled", "openPreferenceCenter", - "getPreferenceCenterConfig", "setUseCustomPreferenceCenterUi", "setAndroidForegroundNotificationsEnabled", "setCurrentLocale", "getCurrentLocale", "clearLocale"); - - /* - * These actions are available even if airship is not ready. - */ - private final static List GLOBAL_ACTIONS = Arrays.asList("takeOff", "registerListener", "setAndroidNotificationConfig"); - private final static List CHANNEL_SCOPE = Arrays.asList("sms", "email", "app", "web"); - private final ExecutorService executorService = Executors.newFixedThreadPool(1); - - private static final String NOTIFICATION_ICON_KEY = "icon"; - private static final String NOTIFICATION_LARGE_ICON_KEY = "largeIcon"; - private static final String ACCENT_COLOR_KEY = "accentColor"; - private static final String DEFAULT_CHANNEL_ID_KEY = "defaultChannelId"; - - private static final String ATTRIBUTE_OPERATION_KEY = "key"; - private static final String ATTRIBUTE_OPERATION_VALUE = "value"; - private static final String ATTRIBUTE_OPERATION_TYPE = "action"; - private static final String ATTRIBUTE_OPERATION_VALUETYPE = "type"; - private static final String ATTRIBUTE_OPERATION_SET = "set"; - private static final String ATTRIBUTE_OPERATION_REMOVE = "remove"; - - private static final Map AUTHORIZED_FEATURES = new HashMap(); - - static { - AUTHORIZED_FEATURES.put("FEATURE_NONE", PrivacyManager.FEATURE_NONE); - AUTHORIZED_FEATURES.put("FEATURE_IN_APP_AUTOMATION", PrivacyManager.FEATURE_IN_APP_AUTOMATION); - AUTHORIZED_FEATURES.put("FEATURE_MESSAGE_CENTER", PrivacyManager.FEATURE_MESSAGE_CENTER); - AUTHORIZED_FEATURES.put("FEATURE_PUSH", PrivacyManager.FEATURE_PUSH); - AUTHORIZED_FEATURES.put("FEATURE_CHAT", PrivacyManager.FEATURE_CHAT); - AUTHORIZED_FEATURES.put("FEATURE_ANALYTICS", PrivacyManager.FEATURE_ANALYTICS); - AUTHORIZED_FEATURES.put("FEATURE_TAGS_AND_ATTRIBUTES", PrivacyManager.FEATURE_TAGS_AND_ATTRIBUTES); - AUTHORIZED_FEATURES.put("FEATURE_CONTACTS", PrivacyManager.FEATURE_CONTACTS); - AUTHORIZED_FEATURES.put("FEATURE_LOCATION", PrivacyManager.FEATURE_LOCATION); - AUTHORIZED_FEATURES.put("FEATURE_ALL", PrivacyManager.FEATURE_ALL); - } - - private Context context; - private PluginManager pluginManager; - - @Override - public void initialize(@NonNull CordovaInterface cordova, @NonNull CordovaWebView webView) { - super.initialize(cordova, webView); - PluginLogger.info("Initializing Urban Airship cordova plugin."); - context = cordova.getActivity().getApplicationContext(); - - Autopilot.automaticTakeOff(context); - pluginManager = PluginManager.shared(context); - } - - @Override - public void onResume(boolean multitasking) { - super.onResume(multitasking); - - if (pluginManager.isAirshipAvailable()) { - pluginManager.checkOptInStatus(); - } - } - - /** - * To extend the plugin, add the actions to either {@link #AIRSHIP_ACTIONS} or {#link #GLOBAL_ACTIONS} and - * All methods will be executed in the ExecutorService. Any exceptions thrown by the actions are automatically caught - * and the callbackContext will return an error result. - */ - @Override - public boolean execute(final String action, final JSONArray data, final CallbackContext callbackContext) { - final boolean isGlobalAction = GLOBAL_ACTIONS.contains(action); - final boolean isAirshipAction = AIRSHIP_ACTIONS.contains(action); - - if (!isAirshipAction && !isGlobalAction) { - PluginLogger.debug("Invalid action: %s", action); - return false; - } - - executorService.execute(new Runnable() { - @Override - public void run() { - if (isAirshipAction && !pluginManager.isAirshipAvailable()) { - callbackContext.error("TakeOff not called. Unable to process action: " + action); - return; - } - - try { - PluginLogger.debug("Plugin Execute: %s", action); - if ("clearNotification".equals(action)) { - clearNotification(data, callbackContext); - } else if ("clearNotifications".equals(action)) { - clearNotifications(data, callbackContext); - } else if ("deleteInboxMessage".equals(action)) { - deleteInboxMessage(data, callbackContext); - } else if ("dismissInboxMessage".equals(action)) { - dismissInboxMessage(data, callbackContext); - } else if ("dismissMessageCenter".equals(action)) { - dismissMessageCenter(data, callbackContext); - } else if ("displayInboxMessage".equals(action)) { - displayInboxMessage(data, callbackContext); - } else if ("displayMessageCenter".equals(action)) { - displayMessageCenter(data, callbackContext); - } else if ("editChannelAttributes".equals(action)) { - editChannelAttributes(data, callbackContext); - } else if ("editNamedUserAttributes".equals(action)) { - editNamedUserAttributes(data, callbackContext); - } else if ("editChannelTagGroups".equals(action)) { - editChannelTagGroups(data, callbackContext); - } else if ("editNamedUserTagGroups".equals(action)) { - editNamedUserTagGroups(data, callbackContext); - } else if ("editChannelSubscriptionLists".equals(action)) { - editChannelSubscriptionLists(data, callbackContext); - } else if ("editContactSubscriptionLists".equals(action)) { - editContactSubscriptionLists(data, callbackContext); - } else if ("getChannelSubscriptionLists".equals(action)) { - getChannelSubscriptionLists(data, callbackContext); - } else if ("getContactSubscriptionLists".equals(action)) { - getContactSubscriptionLists(data, callbackContext); - } else if ("getActiveNotifications".equals(action)) { - getActiveNotifications(data, callbackContext); - } else if ("getChannelID".equals(action)) { - getChannelID(data, callbackContext); - } else if ("getDeepLink".equals(action)) { - getDeepLink(data, callbackContext); - } else if ("getInboxMessages".equals(action)) { - getInboxMessages(data, callbackContext); - } else if ("getLaunchNotification".equals(action)) { - getLaunchNotification(data, callbackContext); - } else if ("getNamedUser".equals(action)) { - getNamedUser(data, callbackContext); - } else if ("getQuietTime".equals(action)) { - getQuietTime(data, callbackContext); - } else if ("getTags".equals(action)) { - getTags(data, callbackContext); - } else if ("isAnalyticsEnabled".equals(action)) { - isAnalyticsEnabled(data, callbackContext); - } else if ("isAppNotificationsEnabled".equals(action)) { - isAppNotificationsEnabled(data, callbackContext); - } else if ("isInQuietTime".equals(action)) { - isInQuietTime(data, callbackContext); - } else if ("isQuietTimeEnabled".equals(action)) { - isQuietTimeEnabled(data, callbackContext); - } else if ("isSoundEnabled".equals(action)) { - isSoundEnabled(data, callbackContext); - } else if ("isUserNotificationsEnabled".equals(action)) { - isUserNotificationsEnabled(data, callbackContext); - } else if ("isVibrateEnabled".equals(action)) { - isVibrateEnabled(data, callbackContext); - } else if ("markInboxMessageRead".equals(action)) { - markInboxMessageRead(data, callbackContext); - } else if ("refreshInbox".equals(action)) { - refreshInbox(data, callbackContext); - } else if ("registerListener".equals(action)) { - registerListener(data, callbackContext); - } else if ("runAction".equals(action)) { - runAction(data, callbackContext); - } else if ("setAnalyticsEnabled".equals(action)) { - setAnalyticsEnabled(data, callbackContext); - } else if ("setAndroidNotificationConfig".equals(action)) { - setAndroidNotificationConfig(data, callbackContext); - } else if ("setAssociatedIdentifier".equals(action)) { - setAssociatedIdentifier(data, callbackContext); - } else if ("setAutoLaunchDefaultMessageCenter".equals(action)) { - setAutoLaunchDefaultMessageCenter(data, callbackContext); - } else if ("setNamedUser".equals(action)) { - setNamedUser(data, callbackContext); - } else if ("setQuietTime".equals(action)) { - setQuietTime(data, callbackContext); - } else if ("setQuietTimeEnabled".equals(action)) { - setQuietTimeEnabled(data, callbackContext); - } else if ("setSoundEnabled".equals(action)) { - setSoundEnabled(data, callbackContext); - } else if ("setTags".equals(action)) { - setTags(data, callbackContext); - } else if ("setUserNotificationsEnabled".equals(action)) { - setUserNotificationsEnabled(data, callbackContext); - } else if ("enableUserNotifications".equals(action)) { - enableUserNotifications(data, callbackContext); - } else if ("setVibrateEnabled".equals(action)) { - setVibrateEnabled(data, callbackContext); - } else if ("takeOff".equals(action)) { - takeOff(data, callbackContext); - } else if ("trackScreen".equals(action)) { - trackScreen(data, callbackContext); - } else if ("enableFeature".equals(action)) { - enableFeature(data, callbackContext); - } else if ("disableFeature".equals(action)) { - disableFeature(data, callbackContext); - } else if ("setEnabledFeatures".equals(action)) { - setEnabledFeatures(data, callbackContext); - } else if ("getEnabledFeatures".equals(action)) { - getEnabledFeatures(data, callbackContext); - } else if ("isFeatureEnabled".equals(action)) { - isFeatureEnabled(data, callbackContext); - } else if ("openPreferenceCenter".equals(action)) { - openPreferenceCenter(data, callbackContext); - } else if ("getPreferenceCenterConfig".equals(action)) { - getPreferenceCenterConfig(data, callbackContext); - } else if ("setUseCustomPreferenceCenterUi".equals(action)) { - setUseCustomPreferenceCenterUi(data, callbackContext); - } else if ("setAndroidForegroundNotificationsEnabled".equals(action)) { - setForegroundNotificationsEnabled(data, callbackContext); - } else if ("setCurrentLocale".equals(action)) { - setCurrentLocale(data, callbackContext); - } else if ("getCurrentLocale".equals(action)) { - getCurrentLocale(data, callbackContext); - } else if ("clearLocale".equals(action)) { - clearLocale(data, callbackContext); - } else { - PluginLogger.debug("No implementation for action: %s", action); - callbackContext.error("No implementation for action " + action); - } - } catch (Exception e) { - PluginLogger.error(e, "Action failed to execute: %s", action); - callbackContext.error("Action " + action + " failed with exception: " + e.getMessage()); - } - } - }); - - return true; - } - - @Override - public void onReset() { - super.onReset(); - pluginManager.setListener(null); - } - - @Override - public void onDestroy() { - super.onDestroy(); - pluginManager.setListener(null); - } - - /** - * Registers for events. - * - * @param data The call data. - * @param callbackContext The callback context. - */ - private void registerListener(@NonNull JSONArray data, @NonNull final CallbackContext callbackContext) { - pluginManager.setListener(new PluginManager.Listener() { - @Override - public void onEvent(@NonNull Event event) { - JSONObject eventData = new JSONObject(); - - try { - eventData.putOpt("eventType", event.getEventName()); - eventData.putOpt("eventData", event.getEventData()); - } catch (JSONException e) { - PluginLogger.error("Failed to create event: %s", event); - return; - } - - PluginResult result = new PluginResult(PluginResult.Status.OK, eventData); - result.setKeepCallback(true); - callbackContext.sendPluginResult(result); - } - }); - } - - /** - * Initializes the Urban Airship plugin. - * - * @param data The data. - * @param callbackContext THe callback context. - * @throws JSONException - */ - private void takeOff(@NonNull JSONArray data, @NonNull final CallbackContext callbackContext) throws JSONException { - JsonMap config = JsonValue.wrapOpt(data.getJSONObject(0)).optMap(); - JsonMap prod = config.opt("production").optMap(); - JsonMap dev = config.opt("development").optMap(); - - pluginManager.editConfig() - .setProductionConfig(prod.opt("appKey").optString(), prod.opt("appSecret").optString()) - .setDevelopmentConfig(dev.opt("appKey").optString(), dev.opt("appSecret").optString()) - .setCloudSite(config.opt("site").optString()) - .apply(); - - final CountDownLatch latch = new CountDownLatch(1); - - // TakeOff must be called on the main thread - new Handler(Looper.getMainLooper()).post(new Runnable() { - @Override - public void run() { - Autopilot.automaticTakeOff(context); - - if (!pluginManager.isAirshipAvailable()) { - callbackContext.error("Airship config is invalid. Unable to takeOff."); - } else { - callbackContext.success(); - } - - latch.countDown(); - } - }); - - try { - latch.await(); - } catch (InterruptedException e) { - PluginLogger.error(e, "Failed to takeOff"); - Thread.currentThread().interrupt(); - } - } - - /** - * Configures the notification factory for Android. - * - * @param data The data. - * @param callbackContext THe callback context. - * @throws JSONException - */ - private void setAndroidNotificationConfig(@NonNull JSONArray data, @NonNull CallbackContext callbackContext) throws JSONException { - JSONObject config = data.getJSONObject(0); - - // Factory will pull the latest values from the config. - pluginManager.editConfig() - .setNotificationIcon(config.optString(NOTIFICATION_ICON_KEY)) - .setNotificationLargeIcon(config.optString(NOTIFICATION_LARGE_ICON_KEY)) - .setNotificationAccentColor(config.optString(ACCENT_COLOR_KEY)) - .setDefaultNotificationChannelId(config.optString(DEFAULT_CHANNEL_ID_KEY)) - .apply(); - - callbackContext.success(); - } - - /** - * Enables/disables auto launching the message center. - * - * @param data The data. - * @param callbackContext THe callback context. - * @throws JSONException - */ - private void setAutoLaunchDefaultMessageCenter(@NonNull JSONArray data, @NonNull CallbackContext callbackContext) throws JSONException { - boolean enabled = data.getBoolean(0); - - // Actions that check this value pull latest values from the config. - pluginManager.editConfig() - .setAutoLaunchMessageCenter(enabled) - .apply(); - - callbackContext.success(); - } - - /** - * Clears all notifications posted by the application. - * - * @param data The call data. - * @param callbackContext The callback context. - */ - private void clearNotifications(@NonNull JSONArray data, @NonNull CallbackContext callbackContext) { - NotificationManagerCompat.from(context).cancelAll(); - callbackContext.success(); - } - - /** - * Enables or disables user notifications. - *

- * Expected arguments: Boolean - * - * @param data The call data. - * @param callbackContext The callback context. - */ - private void setUserNotificationsEnabled(@NonNull JSONArray data, @NonNull CallbackContext callbackContext) throws JSONException { - boolean enabled = data.getBoolean(0); - UAirship.shared().getPushManager().setUserNotificationsEnabled(enabled); - callbackContext.success(); - } - - /** - * Checks if user notifications are enabled or not. - * - * @param data The call data. - * @param callbackContext The callback context. - */ - private void isUserNotificationsEnabled(@NonNull JSONArray data, @NonNull CallbackContext callbackContext) { - int value = UAirship.shared().getPushManager().getUserNotificationsEnabled() ? 1 : 0; - callbackContext.success(value); - } - - /** - * Enables user notifications. - * - * @param data The call data. - * @param callbackContext The callback context. - */ - private void enableUserNotifications(@NonNull JSONArray data, @NonNull CallbackContext callbackContext) { - UAirship.shared().getPermissionsManager().requestPermission( - Permission.DISPLAY_NOTIFICATIONS, - true, - permissionRequestResult -> { - if (permissionRequestResult.getPermissionStatus() == PermissionStatus.GRANTED) { - callbackContext.success(1); - } else { - callbackContext.success(0); - } - }); - } - - /** - * Checks if notification sound is enabled or not. - * - * @param data The call data. - * @param callbackContext The callback context. - */ - private void isSoundEnabled(@NonNull JSONArray data, @NonNull CallbackContext callbackContext) { - int value = UAirship.shared().getPushManager().isSoundEnabled() ? 1 : 0; - callbackContext.success(value); - } - - /** - * Checks if notification vibration is enabled or not. - * - * @param data The call data. - * @param callbackContext The callback context. - */ - private void isVibrateEnabled(@NonNull JSONArray data, @NonNull CallbackContext callbackContext) { - int value = UAirship.shared().getPushManager().isVibrateEnabled() ? 1 : 0; - callbackContext.success(value); - } - - /** - * Checks if quiet time is enabled or not. - * - * @param data The call data. - * @param callbackContext The callback context. - */ - private void isQuietTimeEnabled(@NonNull JSONArray data, @NonNull CallbackContext callbackContext) { - int value = UAirship.shared().getPushManager().isQuietTimeEnabled() ? 1 : 0; - callbackContext.success(value); - } - - /** - * Checks if the device is currently in quiet time. - * - * @param data The call data. - * @param callbackContext The callback context. - */ - private void isInQuietTime(@NonNull JSONArray data, @NonNull CallbackContext callbackContext) { - int value = UAirship.shared().getPushManager().isInQuietTime() ? 1 : 0; - callbackContext.success(value); - } - - /** - * Returns the last notification that launched the application. - *

- * Expected arguments: Boolean - `YES` to clear the notification - * - * @param data The call data. - * @param callbackContext The callback context. - */ - private void getLaunchNotification(@NonNull JSONArray data, @NonNull CallbackContext callbackContext) { - boolean clear = data.optBoolean(0, false); - NotificationOpenedEvent event = pluginManager.getLastLaunchNotificationEvent(clear); - - if (event != null) { - callbackContext.success(event.getEventData()); - } else { - callbackContext.success(new JSONObject()); - } - } - - /** - * Returns the last deep link. - *

- * Expected arguments: Boolean - `YES` to clear the deep link - * - * @param data The call data. - * @param callbackContext The callback context. - */ - private void getDeepLink(@NonNull JSONArray data, @NonNull CallbackContext callbackContext) { - boolean clear = data.optBoolean(0, false); - DeepLinkEvent event = pluginManager.getLastDeepLinkEvent(clear); - String deepLink = event == null ? null : event.getDeepLink(); - callbackContext.success(deepLink); - } - - /** - * Returns the channel ID. - * - * @param data The call data. - * @param callbackContext The callback context. - */ - private void getChannelID(@NonNull JSONArray data, @NonNull CallbackContext callbackContext) { - String channelId = UAirship.shared().getChannel().getId(); - channelId = channelId != null ? channelId : ""; - callbackContext.success(channelId); - } - - /** - * Returns the quiet time as an object with the following: - * "startHour": Number, - * "startMinute": Number, - * "endHour": Number, - * "endMinute": Number - * - * @param data The call data. - * @param callbackContext The callback context. - */ - private void getQuietTime(@NonNull JSONArray data, @NonNull CallbackContext callbackContext) throws JSONException { - Date[] quietTime = UAirship.shared().getPushManager().getQuietTimeInterval(); - - int startHour = 0; - int startMinute = 0; - int endHour = 0; - int endMinute = 0; - - if (quietTime != null) { - Calendar start = new GregorianCalendar(); - Calendar end = new GregorianCalendar(); - start.setTime(quietTime[0]); - end.setTime(quietTime[1]); - - startHour = start.get(Calendar.HOUR_OF_DAY); - startMinute = start.get(Calendar.MINUTE); - endHour = end.get(Calendar.HOUR_OF_DAY); - endMinute = end.get(Calendar.MINUTE); - } - - JSONObject returnObject = new JSONObject(); - returnObject.put("startHour", startHour); - returnObject.put("startMinute", startMinute); - returnObject.put("endHour", endHour); - returnObject.put("endMinute", endMinute); - - PluginLogger.debug("Returning quiet time"); - callbackContext.success(returnObject); - } - - /** - * Returns the tags as an array. - * - * @param data The call data. - * @param callbackContext The callback context. - */ - private void getTags(@NonNull JSONArray data, @NonNull CallbackContext callbackContext) { - Set tags = UAirship.shared().getChannel().getTags(); - PluginLogger.debug("Returning tags"); - callbackContext.success(new JSONArray(tags)); - } - - /** - * Sets the tags. - *

- * Expected arguments: An array of Strings - * - * @param data The call data. - * @param callbackContext The callback context. - */ - private void setTags(@NonNull JSONArray data, @NonNull CallbackContext callbackContext) throws JSONException { - HashSet tagSet = new HashSet(); - JSONArray tagsArray = data.getJSONArray(0); - for (int i = 0; i < tagsArray.length(); ++i) { - tagSet.add(tagsArray.getString(i)); - } - - PluginLogger.debug("Settings tags: %s", tagSet); - UAirship.shared().getChannel().setTags(tagSet); - - callbackContext.success(); - } - - /** - * Enables or disables notification sound. - *

- * Expected arguments: Boolean - * - * @param data The call data. - * @param callbackContext The callback context. - */ - @SuppressWarnings("deprecation") - private void setSoundEnabled(@NonNull JSONArray data, @NonNull CallbackContext callbackContext) throws JSONException { - boolean soundPreference = data.getBoolean(0); - UAirship.shared().getPushManager().setSoundEnabled(soundPreference); - PluginLogger.debug("Settings Sound: %s", soundPreference); - callbackContext.success(); - } - - /** - * Enables or disables notification vibration. - *

- * Expected arguments: Boolean - * - * @param data The call data. - * @param callbackContext The callback context. - */ - @SuppressWarnings("deprecation") - private void setVibrateEnabled(@NonNull JSONArray data, @NonNull CallbackContext callbackContext) throws JSONException { - boolean vibrationPreference = data.getBoolean(0); - UAirship.shared().getPushManager().setVibrateEnabled(vibrationPreference); - PluginLogger.debug("Settings Vibrate: %s.", vibrationPreference); - callbackContext.success(); - } - - /** - * Enables or disables quiet time. - *

- * Expected arguments: Boolean - * - * @param data The call data. - * @param callbackContext The callback context. - */ - @SuppressWarnings("deprecation") - private void setQuietTimeEnabled(@NonNull JSONArray data, @NonNull CallbackContext callbackContext) throws JSONException { - boolean quietPreference = data.getBoolean(0); - UAirship.shared().getPushManager().setQuietTimeEnabled(quietPreference); - PluginLogger.debug("Settings QuietTime: %s", quietPreference); - callbackContext.success(); - } - - /** - * Sets the quiet time. - *

- * Expected arguments: Number - start hour, Number - start minute, - * Number - end hour, Number - end minute - * - * @param data The call data. - * @param callbackContext The callback context. - */ - @SuppressWarnings("deprecation") - private void setQuietTime(@NonNull JSONArray data, @NonNull CallbackContext callbackContext) throws JSONException { - Calendar start = new GregorianCalendar(); - Calendar end = new GregorianCalendar(); - int startHour = data.getInt(0); - int startMinute = data.getInt(1); - int endHour = data.getInt(2); - int endMinute = data.getInt(3); - - start.set(Calendar.HOUR_OF_DAY, startHour); - start.set(Calendar.MINUTE, startMinute); - end.set(Calendar.HOUR_OF_DAY, endHour); - end.set(Calendar.MINUTE, endMinute); - - PluginLogger.debug("Settings QuietTime. Start: %s. End: %s.", start.getTime(), end.getTime()); - UAirship.shared().getPushManager().setQuietTimeInterval(start.getTime(), end.getTime()); - - callbackContext.success(); - } - - /** - * Enables or disables analytics. - *

- * Disabling analytics will delete any locally stored events - * and prevent any events from uploading. Features that depend on analytics being - * enabled may not work properly if it's disabled (reports, region triggers, - * location segmentation, push to local time). - *

- * Expected arguments: Boolean - * - * @param data The call data. - * @param callbackContext The callback context. - */ - private void setAnalyticsEnabled(@NonNull JSONArray data, @NonNull CallbackContext callbackContext) throws JSONException { - boolean enabled = data.getBoolean(0); - PluginLogger.debug("Settings analyticsEnabled: %s", enabled); - UAirship.shared().getAnalytics().setEnabled(enabled); - callbackContext.success(); - } - - /** - * Checks if analytics is enabled or not. - * - * @param data The call data. - * @param callbackContext The callback context. - */ - private void isAnalyticsEnabled(@NonNull JSONArray data, @NonNull CallbackContext callbackContext) { - int value = UAirship.shared().getAnalytics().isEnabled() ? 1 : 0; - callbackContext.success(value); - } - - /** - * Sets associated custom identifiers for use with the Connect data stream. - *

- * Previous identifiers will be replaced by the new identifiers each time setAssociateIdentifier is called. It is a set operation. - *

- * Expected arguments: String - * - * @param data The call data. - * @param callbackContext The callback context. - */ - private void setAssociatedIdentifier(@NonNull JSONArray data, @NonNull CallbackContext callbackContext) throws JSONException { - String key = data.getString(0); - String identifier = data.getString(1); - - UAirship.shared().getAnalytics() - .editAssociatedIdentifiers() - .addIdentifier(key, identifier) - .apply(); - - callbackContext.success(); - } - - /** - * Returns the named user ID. - *

- * Expected arguments: String - * - * @param data The call data. - * @param callbackContext The callback context. - */ - private void getNamedUser(@NonNull JSONArray data, @NonNull CallbackContext callbackContext) { - String namedUserId = UAirship.shared().getContact().getNamedUserId(); - namedUserId = namedUserId != null ? namedUserId : ""; - callbackContext.success(namedUserId); - } - - /** - * Sets the named user ID. - * - * @param data The call data. - * @param callbackContext The callback context. - */ - private void setNamedUser(@NonNull JSONArray data, @NonNull CallbackContext callbackContext) throws JSONException { - String namedUserId = data.isNull(0) ? null : data.getString(0); - PluginLogger.debug("Setting named user: %s", namedUserId); - - if (UAStringUtil.isEmpty(namedUserId)) { - UAirship.shared().getContact().reset(); - } else { - UAirship.shared().getContact().identify(namedUserId); - } - callbackContext.success(); - } - - /** - * Edits the named user tag groups. - * - * @param data The call data. - * @param callbackContext The callback context. - */ - private void editNamedUserTagGroups(@NonNull JSONArray data, @NonNull CallbackContext callbackContext) throws JSONException { - JSONArray operations = data.getJSONArray(0); - - PluginLogger.debug("Editing named user tag groups: %s", operations); - - TagGroupsEditor editor = UAirship.shared().getContact().editTagGroups(); - applyTagGroupOperations(editor, operations); - editor.apply(); - - callbackContext.success(); - } - - /** - * Edits the channel tag groups. - * - * @param data The call data. - * @param callbackContext The callback context. - */ - private void editChannelTagGroups(@NonNull JSONArray data, @NonNull CallbackContext callbackContext) throws JSONException { - JSONArray operations = data.getJSONArray(0); - - PluginLogger.debug("Editing channel tag groups: %s", operations); - - TagGroupsEditor editor = UAirship.shared().getChannel().editTagGroups(); - applyTagGroupOperations(editor, operations); - editor.apply(); - - callbackContext.success(); - } - - /** - * Edits the channel subscription lists. - * - * @param data The call data. - * @param callbackContext The callback context. - */ - private void editChannelSubscriptionLists(@NonNull JSONArray data, @NonNull CallbackContext callbackContext) throws JSONException { - - JSONArray operations = data.getJSONArray(0); - - PluginLogger.debug("Editing channel subscription lists: %s", operations); - - SubscriptionListEditor editor = UAirship.shared().getChannel().editSubscriptionLists(); - for (int i = 0; i < operations.length(); i++) { - JSONObject operation = operations.getJSONObject(i); - - String operationType = operation.getString("operation"); - String listId = operation.getString("listId"); - - if ("subscribe".equals(operationType)) { - editor.subscribe(listId); - } else if ("unsubscribe".equals(operationType)) { - editor.unsubscribe(listId); - } - } - - editor.apply(); - - callbackContext.success(); - } - - /** - * Edits the contact subscription lists. - * - * @param data The call data. - * @param callbackContext The callback context. - */ - private void editContactSubscriptionLists(@NonNull JSONArray data, @NonNull CallbackContext callbackContext) throws JSONException { - - JSONArray operations = data.getJSONArray(0); - - PluginLogger.debug("Editing contact subscription lists: %s", operations); - - ScopedSubscriptionListEditor editor = UAirship.shared().getContact().editSubscriptionLists(); - for (int i = 0; i < operations.length(); i++) { - JSONObject operation = operations.getJSONObject(i); - - String operationType = operation.getString("operation"); - String listId = operation.getString("listId"); - String scope = operation.getString("scope"); - - if (!CHANNEL_SCOPE.contains(scope)) { - continue; - } - - if ("subscribe".equals(operationType)) { - editor.subscribe(listId, getScope(scope)); - } else if ("unsubscribe".equals(operationType)) { - editor.unsubscribe(listId, getScope(scope)); - } - } - - editor.apply(); - - callbackContext.success(); - } - - private Scope getScope(@NonNull String scope) { - return Scope.valueOf(scope.toUpperCase(Locale.ROOT)); - } - - /** - * Returns the current set of the subscription lists for this channel. - * An empty set indicates that this channel is not subscribed to any lists. - * - * @param data The call data. - * @param callbackContext The callback context. - */ - private void getChannelSubscriptionLists(@NonNull JSONArray data, @NonNull CallbackContext callbackContext) throws JSONException { - PluginLogger.debug("Fetch channel subscription lists: %s"); - UAirship.shared().getChannel().getSubscriptionLists(true).addResultCallback(new ResultCallback>() { - - @Override - public void onResult(@Nullable Set channelSubscriptionList) { - JSONArray jsonArray = new JSONArray(channelSubscriptionList); - callbackContext.success(jsonArray); - - } - }); - } - - /** - * Returns the current set of the subscription lists for this contact. - * An empty set indicates that this channel is not subscribed to any lists. - * - * @param data The call data. - * @param callbackContext The callback context. - */ - private void getContactSubscriptionLists(@NonNull JSONArray data, @NonNull CallbackContext callbackContext) throws JSONException { - PluginLogger.debug("Fetch contact subscription lists: %s"); - UAirship.shared().getContact().getSubscriptionLists(true).addResultCallback(new ResultCallback>>() { - - @Override - public void onResult(@Nullable Map> contactSubscriptionList) { - try { - callbackContext.success(new JSONObject(JsonValue.wrap(contactSubscriptionList, JsonMap.EMPTY_MAP.toJsonValue()).toString())); - } catch (JSONException e) { - callbackContext.error(e.getMessage()); - } - } - }); - } - - /** - * Runs an Urban Airship action. - *

- * Expected arguments: String - action name, * - the action value - * - * @param data The call data. - * @param callbackContext The callback context. - */ - private void runAction(@NonNull JSONArray data, @NonNull final CallbackContext callbackContext) throws JSONException { - final String actionName = data.getString(0); - final Object actionValue = data.opt(1); - - ActionRunRequest.createRequest(actionName) - .setValue(actionValue) - .run(new ActionCompletionCallback() { - @Override - public void onFinish(@NonNull ActionArguments arguments, @NonNull ActionResult result) { - - if (result.getStatus() == ActionResult.STATUS_COMPLETED) { - - /* - * We are wrapping the value in an object to preserve the type of data - * the action returns. CallbackContext.success does not allow all types. - * The value will be pulled out in the UAirship.js file before passing - * it back to the user. - */ - - Map resultMap = new HashMap(); - resultMap.put("value", result.getValue().toJsonValue()); - - try { - callbackContext.success(new JSONObject(resultMap.toString())); - } catch (JSONException e) { - callbackContext.error("Failed to convert action results: " + e.getMessage()); - } - } else { - callbackContext.error(createActionErrorMessage(actionName, result)); - } - } - }); - } - - /** - * Helper method to create the action run error message. - * - * @param name The name of the action. - * @param result The action result. - * @return The action error message. - */ - private static String createActionErrorMessage(String name, ActionResult result) { - switch (result.getStatus()) { - case ActionResult.STATUS_ACTION_NOT_FOUND: - return String.format("Action %s not found", name); - case ActionResult.STATUS_REJECTED_ARGUMENTS: - return String.format("Action %s rejected its arguments", name); - case ActionResult.STATUS_EXECUTION_ERROR: - if (result.getException() != null) { - return result.getException().getMessage(); - } - case ActionResult.STATUS_COMPLETED: - return ""; - } - - return String.format("Action %s failed with unspecified error", name); - } - - /** - * Helper method to apply tag operations to a TagGroupsEditor. - * - * @param editor The editor. - * @param operations The tag operations. - */ - private static void applyTagGroupOperations(TagGroupsEditor editor, JSONArray operations) throws JSONException { - for (int i = 0; i < operations.length(); i++) { - JSONObject operation = operations.getJSONObject(i); - - JSONArray tags = operation.getJSONArray("tags"); - String group = operation.getString("group"); - String operationType = operation.getString("operation"); - - HashSet tagSet = new HashSet(); - for (int j = 0; j < tags.length(); j++) { - tagSet.add(tags.getString(j)); - } - - if (tagSet.isEmpty()) { - continue; - } - - if ("add".equals(operationType)) { - editor.addTags(group, tagSet); - } else if ("remove".equals(operationType)) { - editor.removeTags(group, tagSet); - } - } - } - - /** - * Displays the message center. - * - * @param data The call data. The message ID is expected to be the first entry. - * @param callbackContext The callback context. - */ - private void displayMessageCenter(@NonNull JSONArray data, @NonNull CallbackContext callbackContext) { - String messageId = data.optString(0); - - PluginLogger.debug("Displaying Message Center"); - if (!UAStringUtil.isEmpty(messageId)) { - Intent intent = new Intent(cordova.getActivity(), com.urbanairship.cordova.CustomMessageCenterActivity.class) - .setAction(MessageCenter.VIEW_MESSAGE_INTENT_ACTION) - .setPackage(cordova.getActivity().getPackageName()) - .setData(Uri.fromParts(MessageCenter.MESSAGE_DATA_SCHEME, messageId, null)) - .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP); - - cordova.getActivity().startActivity(intent); - } else { - Intent intent = new Intent(cordova.getActivity(), com.urbanairship.cordova.CustomMessageCenterActivity.class) - .setPackage(cordova.getActivity().getPackageName()) - .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP); - - cordova.getActivity().startActivity(intent); - } - callbackContext.success(); - } - - /** - * Dismiss the message center. - * - * @param data The call data. The message ID is expected to be the first entry. - * @param callbackContext The callback context. - */ - private void dismissMessageCenter(@NonNull JSONArray data, @NonNull CallbackContext callbackContext) { - PluginLogger.debug("Dismissing Message Center"); - Intent intent = new Intent(cordova.getActivity(), com.urbanairship.cordova.CustomMessageCenterActivity.class) - .setAction(com.urbanairship.cordova.CustomMessageCenterActivity.CLOSE_INTENT_ACTION); - - cordova.getActivity().startActivity(intent); - - callbackContext.success(); - } - - /** - * Deletes an inbox message. - * - * @param data The call data. The message ID is expected to be the first entry. - * @param callbackContext The callback context. - * @throws JSONException - */ - private void deleteInboxMessage(@NonNull JSONArray data, @NonNull CallbackContext callbackContext) throws JSONException { - String messageId = data.getString(0); - Message message = MessageCenter.shared().getInbox().getMessage(messageId); - - if (message == null) { - callbackContext.error("Message not found: " + messageId); - return; - } - - message.delete(); - callbackContext.success(); - } - - /** - * Marks an inbox message read. - * - * @param data The call data. The message ID is expected to be the first entry. - * @param callbackContext The callback context. - * @throws JSONException - */ - private void markInboxMessageRead(@NonNull JSONArray data, @NonNull CallbackContext callbackContext) throws JSONException { - String messageId = data.getString(0); - Message message = MessageCenter.shared().getInbox().getMessage(messageId); - - if (message == null) { - callbackContext.error("Message not found: " + messageId); - return; - } - - message.markRead(); - callbackContext.success(); - } - - /** - * Gets the inbox listing. - * - * @param data The call data. - * @param callbackContext The callback context. - * @throws JSONException - */ - private void getInboxMessages(@NonNull JSONArray data, @NonNull CallbackContext callbackContext) throws JSONException { - JSONArray messagesJson = new JSONArray(); - - for (Message message : MessageCenter.shared().getInbox().getMessages()) { - JSONObject messageJson = new JSONObject(); - messageJson.putOpt("id", message.getMessageId()); - messageJson.putOpt("title", message.getTitle()); - messageJson.putOpt("sentDate", message.getSentDateMS()); - messageJson.putOpt("listIconUrl", message.getListIconUrl()); - messageJson.putOpt("isRead", message.isRead()); - - JSONObject extrasJson = new JSONObject(); - Bundle extras = message.getExtras(); - for (String key : extras.keySet()) { - Object value = extras.get(key); - extrasJson.putOpt(key, value); - } - - messageJson.put("extras", extrasJson); - - messagesJson.put(messageJson); - } - - callbackContext.success(messagesJson); - } - - /** - * Displays an inbox message. - * - * @param data The call data. The message ID is expected to be the first entry. - * @param callbackContext The callback context. - * @throws JSONException - */ - private void displayInboxMessage(@NonNull JSONArray data, @NonNull CallbackContext callbackContext) throws JSONException { - final String messageId = data.getString(0); - Message message = MessageCenter.shared().getInbox().getMessage(messageId); - - if (message == null) { - callbackContext.error("Message not found: " + messageId); - return; - } - - cordova.getActivity().runOnUiThread(new Runnable() { - @Override - public void run() { - Intent intent = new Intent(cordova.getActivity(), com.urbanairship.cordova.CustomMessageActivity.class) - .setAction(MessageCenter.VIEW_MESSAGE_INTENT_ACTION) - .setPackage(cordova.getActivity().getPackageName()) - .setData(Uri.fromParts(MessageCenter.MESSAGE_DATA_SCHEME, messageId, null)) - .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP); - - cordova.getActivity().startActivity(intent); - } - }); - - callbackContext.success(); - } - - /** - * Dismiss the inbox message. - * - * @param data The call data. The message ID is expected to be the first entry. - * @param callbackContext The callback context. - * @throws JSONException - */ - private void dismissInboxMessage(@NonNull JSONArray data, @NonNull CallbackContext callbackContext) { - PluginLogger.debug("Dismissing Inbox Message"); - Intent intent = new Intent(cordova.getActivity(), com.urbanairship.cordova.CustomMessageActivity.class) - .setAction(com.urbanairship.cordova.CustomMessageActivity.CLOSE_INTENT_ACTION) - .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP); - - cordova.getActivity().startActivity(intent); - - callbackContext.success(); - } - - /** - * Refreshes the inbox. - * - * @param data The call data. The message ID is expected to be the first entry. - * @param callbackContext The callback context. - */ - private void refreshInbox(@NonNull JSONArray data, @NonNull final CallbackContext callbackContext) { - cordova.getActivity().runOnUiThread(new Runnable() { - @Override - public void run() { - MessageCenter.shared().getInbox().fetchMessages(new Inbox.FetchMessagesCallback() { - @Override - public void onFinished(boolean success) { - if (success) { - callbackContext.success(); - } else { - callbackContext.error("Inbox failed to refresh"); - } - } - }); - } - }); - } - - /** - * Checks if app notifications are enabled or not. - * - * @param data The call data. - * @param callbackContext The callback context. - */ - private void isAppNotificationsEnabled(@NonNull JSONArray data, @NonNull final CallbackContext callbackContext) { - int value = UAirship.shared().getPushManager().isOptIn() ? 1 : 0; - callbackContext.success(value); - } - - /** - * Gets currently active notifications. - * - * @param data The call data. - * @param callbackContext The callback context. - */ - private void getActiveNotifications(@NonNull JSONArray data, @NonNull final CallbackContext callbackContext) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - JSONArray notificationsJSON = new JSONArray(); - - NotificationManager notificationManager = (NotificationManager) UAirship.getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE); - StatusBarNotification[] statusBarNotifications = notificationManager.getActiveNotifications(); - - for (StatusBarNotification statusBarNotification : statusBarNotifications) { - int id = statusBarNotification.getId(); - String tag = statusBarNotification.getTag(); - PushMessage pushMessage = com.urbanairship.cordova.Utils.messageFromNotification(statusBarNotification); - - try { - notificationsJSON.put(com.urbanairship.cordova.Utils.notificationObject(pushMessage, tag, id)); - } catch (Exception e) { - PluginLogger.error(e, "Unable to serialize push message: %s", pushMessage); - } - } - - callbackContext.success(notificationsJSON); - } else { - callbackContext.error("Getting active notifications is only supported on Marshmallow and newer devices."); - } - } - - /** - * Clears all notifications. - * - * @param data The call data. - * @param callbackContext The callback context - * @throws JSONException - */ - private void clearNotification(@NonNull JSONArray data, @NonNull final CallbackContext callbackContext) throws JSONException { - final String identifier = data.getString(0); - - if (UAStringUtil.isEmpty(identifier)) { - return; - } - - String[] parts = identifier.split(":", 2); - - if (parts.length == 0) { - callbackContext.error("Invalid identifier: " + identifier); - return; - } - - int id; - String tag = null; - - try { - id = Integer.parseInt(parts[0]); - } catch (NumberFormatException e) { - callbackContext.error("Invalid identifier: " + identifier); - return; - } - - if (parts.length == 2) { - tag = parts[1]; - } - - - NotificationManagerCompat.from(UAirship.getApplicationContext()).cancel(tag, id); - - callbackContext.success(); - } - - /** - * Edits the channel attributes. - * - * @param data The call data. - * @param callbackContext The callback context. - */ - private void editChannelAttributes(@NonNull JSONArray data, @NonNull CallbackContext callbackContext) throws JSONException { - JSONArray operations = data.getJSONArray(0); - - PluginLogger.debug("Editing channel attributes: %s", operations); - - AttributeEditor editor = UAirship.shared().getChannel().editAttributes(); - applyAttributesOperations(editor, operations); - editor.apply(); - - callbackContext.success(); - } - - /** - * Edits the named user attributes. - * - * @param data The call data. - * @param callbackContext The callback context. - */ - private void editNamedUserAttributes(@NonNull JSONArray data, @NonNull CallbackContext callbackContext) throws JSONException { - JSONArray operations = data.getJSONArray(0); - - PluginLogger.debug("Editing named user attributes: %s", operations); - - AttributeEditor editor = UAirship.shared().getContact().editAttributes(); - applyAttributesOperations(editor, operations); - editor.apply(); - - callbackContext.success(); - } - - /** - * Helper method to apply attribute operations to an AttributeEditor. - * - * @param editor The attribute editor. - * @param operations The attribute operations. - */ - private static void applyAttributesOperations(AttributeEditor editor, JSONArray operations) throws JSONException { - for (int i = 0; i < operations.length(); i++) { - JSONObject operation = operations.optJSONObject(i); - if (operation == null) { - continue; - } - - String action = operation.optString(ATTRIBUTE_OPERATION_TYPE); - String key = operation.optString(ATTRIBUTE_OPERATION_KEY); - - if (ATTRIBUTE_OPERATION_SET.equals(action)) { - Object value = operation.opt(ATTRIBUTE_OPERATION_VALUE); - String valueType = (String) operation.opt(ATTRIBUTE_OPERATION_VALUETYPE); - if ("string".equals(valueType)) { - editor.setAttribute(key, (String) value); - } else if ("number".equals(valueType)) { - editor.setAttribute(key, ((Number) value).doubleValue()); - } else if ("date".equals(valueType)) { - // JavaScript's date type doesn't pass through the JS to native bridge. Dates are instead serialized as milliseconds since epoch. - editor.setAttribute(key, new Date(((Number) value).longValue())); - } else { - PluginLogger.warn("Unknown channel attribute type: %s", valueType); - } - } else if (ATTRIBUTE_OPERATION_REMOVE.equals(action)) { - editor.removeAttribute(key); - } - } - } - - /** - * Initiates screen tracking for a specific app screen. - *

- * Expected arguments: String - * - * @param data The call data. - * @param callbackContext The callback context. - */ - private void trackScreen(@NonNull JSONArray data, @NonNull CallbackContext callbackContext) throws JSONException { - String screen = data.getString(0); - UAirship.shared().getAnalytics().trackScreen(screen); - callbackContext.success(); - } - - /** - * Enables features, adding them to the set of currently enabled features. - * - * @param data The call data. - * @param callbackContext The callback context. - * @throws JSONException - */ - private void enableFeature(@NonNull JSONArray data, @NonNull CallbackContext callbackContext) throws JSONException { - JSONArray features = data.getJSONArray(0); - if (isValidFeature(features)) { - UAirship.shared().getPrivacyManager().enable(stringToFeature(features)); - callbackContext.success(); - } else { - callbackContext.error("Invalid features " + features); - } - } - - /** - * Disables features, removing them from the set of currently enabled features. - * - * @param data The call data. - * @param callbackContext The callback context. - * @throws JSONException - */ - private void disableFeature(@NonNull JSONArray data, @NonNull CallbackContext callbackContext) throws JSONException { - JSONArray features = data.getJSONArray(0); - if (isValidFeature(features)) { - UAirship.shared().getPrivacyManager().disable(stringToFeature(features)); - callbackContext.success(); - } else { - callbackContext.error("Invalid features " + features); - } - } - - /** - * Sets the current enabled features, replacing any currently enabled features with the given set. - * - * @param data The call data. - * @param callbackContext The callback context. - * @throws JSONException - */ - private void setEnabledFeatures(@NonNull JSONArray data, @NonNull CallbackContext callbackContext) throws JSONException { - JSONArray features = data.getJSONArray(0); - if (isValidFeature(features)) { - UAirship.shared().getPrivacyManager().setEnabledFeatures(stringToFeature(features)); - callbackContext.success(); - } else { - callbackContext.error("Invalid features " + features); - } - } - - /** - * Gets the current enabled features. - * - * @param data The call data. - * @param callbackContext The callback context. - */ - private void getEnabledFeatures(@NonNull JSONArray data, @NonNull CallbackContext callbackContext) { - callbackContext.success(featureToString(UAirship.shared().getPrivacyManager().getEnabledFeatures())); - } - - /** - * Checks if all of the given features are enabled. - * - * @param data The call data. - * @param callbackContext The callback context. - */ - private void isFeatureEnabled(@NonNull JSONArray data, @NonNull CallbackContext callbackContext) throws JSONException { - JSONArray features = data.getJSONArray(0); - if (isValidFeature(features)) { - int value = UAirship.shared().getPrivacyManager().isEnabled(stringToFeature(features)) ? 1 : 0; - callbackContext.success(value); - } else { - callbackContext.error("Invalid features " + features); - } - } - - /** - * Opens the Preference Center with the given preferenceCenterId. - * - * @param data The call data. - * @param callbackContext The callback context. - * @throws JSONException - */ - private void openPreferenceCenter(@NonNull JSONArray data, @NonNull CallbackContext callbackContext) throws JSONException { - String preferenceCenterId = data.getString(0); - PreferenceCenter.shared().open(preferenceCenterId); - callbackContext.success(); - } - - /** - * Gets the configuration of the Preference Center with the given Id trough a callback method. - * - * @param data The call data. - * @param callbackContext The callback context. - */ - private void getPreferenceCenterConfig(@NonNull JSONArray data, @NonNull CallbackContext callbackContext) throws JSONException { - String preferenceCenterId = data.getString(0); - PreferenceCenter.shared().getJsonConfig(preferenceCenterId).addResultCallback(result -> { - if (result == null) { - callbackContext.success(); - return; - } - - try { - callbackContext.success(new JSONObject(result.toString())); - } catch (JSONException e) { - callbackContext.error(e.getMessage()); - } - }); - } - - /** - * Set to true the override the preference center. - * - * @param callbackContext The callback context. - * @throws JSONException - */ - private void setUseCustomPreferenceCenterUi(@NonNull JSONArray data, @NonNull CallbackContext callbackContext) throws JSONException { - String preferenceCenterId = data.getString(0); - boolean useCustomUi = data.getBoolean(1); - pluginManager.editConfig() - .setUseCustomPreferenceCenterUi(preferenceCenterId, useCustomUi) - .apply(); - callbackContext.success(); - } - - private void setForegroundNotificationsEnabled(@NonNull JSONArray data, @NonNull CallbackContext callbackContext) throws JSONException { - boolean enabled = data.getBoolean(0); - pluginManager.editConfig() - .setForegroundNotificationsEnabled(enabled) - .apply(); - callbackContext.success(); - } - - /** - * Overriding the locale. - * - * @param data The call data. - * @throws JSONException - */ - private void setCurrentLocale(@NonNull JSONArray data, @NonNull CallbackContext callbackContext) throws JSONException { - String localeIdentifier = data.getString(0); - UAirship.shared().setLocaleOverride(new Locale(localeIdentifier)); - callbackContext.success(); - } - - /** - * Getting the locale currently used by Airship. - * @param callbackContext The callback context. - * @throws JSONException - */ - - private void getCurrentLocale(@NonNull JSONArray data, @NonNull CallbackContext callbackContext) throws JSONException { - Locale airshipLocale = UAirship.shared().getLocale(); - callbackContext.success(airshipLocale.getLanguage()); - } - - /** - * Resets the current locale. - * @param callbackContext The callback context. - * @throws JSONException - */ - private void clearLocale(@NonNull JSONArray data, @NonNull CallbackContext callbackContext) throws JSONException { - UAirship.shared().setLocaleOverride(null); - callbackContext.success(); - } - - /** - * Helper method to verify if a Feature is authorized. - * - * @param features The String features to verify. - * @return {@code true} if the provided features are authorized, otherwise {@code false}. - */ - private boolean isValidFeature(JSONArray features) throws JSONException { - if (features == null || features.length() == 0) { - return false; - } - - for (int i = 0; i < features.length(); i++) { - if (!AUTHORIZED_FEATURES.containsKey(features.getString(i))) { - return false; - } - } - return true; - } - - /** - * Helper method to parse a String features JSONArray into {@link PrivacyManager.Feature} int array. - * - * @param features The String features JSONArray to parse. - * @return The {@link PrivacyManager.Feature} int array. - */ - @PrivacyManager.Feature - private @NonNull - int[] stringToFeature(@NonNull JSONArray features) throws JSONException { - @PrivacyManager.Feature - int[] intFeatures = new int[features.length()]; - - for (int i = 0; i < features.length(); i++) { - intFeatures[i] = (int) AUTHORIZED_FEATURES.get(features.getString(i)); - } - return intFeatures; - } - - /** - * Helper method to parse a {@link PrivacyManager.Feature} int array into a String features JSONArray. - * - * @param features The {@link PrivacyManager.Feature} int array to parse. - * @return The String feature JSONArray. - */ - private @NonNull - JSONArray featureToString(@PrivacyManager.Feature int features) { - List stringFeatures = new ArrayList(); - - if (features == PrivacyManager.FEATURE_ALL) { - stringFeatures.add("FEATURE_ALL"); - } else if (features == PrivacyManager.FEATURE_NONE) { - stringFeatures.add("FEATURE_NONE"); - } else { - for (String feature : AUTHORIZED_FEATURES.keySet()) { - @PrivacyManager.Feature - int intFeature = (int) AUTHORIZED_FEATURES.get(feature); - if (((intFeature & features) != 0) && (intFeature != PrivacyManager.FEATURE_ALL)) { - stringFeatures.add(feature); - } - } - } - return new JSONArray(stringFeatures); - } - -} diff --git a/urbanairship-cordova/src/android/Utils.java b/urbanairship-cordova/src/android/Utils.java deleted file mode 100644 index 0903ed5b..00000000 --- a/urbanairship-cordova/src/android/Utils.java +++ /dev/null @@ -1,102 +0,0 @@ -/* Copyright Urban Airship and Contributors */ - -package com.urbanairship.cordova; - -import android.os.Bundle; -import android.os.Message; -import android.service.notification.StatusBarNotification; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.urbanairship.push.PushMessage; -import com.urbanairship.util.UAStringUtil; - -import org.json.JSONException; -import org.json.JSONObject; - -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; - -/** - * Utility methods. - */ -public class Utils { - - /** - * Parses a {@link PushMessage} from a status bar notification. - * - * @param statusBarNotification The status bar notification. - * @return The push message from the status bar notification. - */ - @NonNull - public static PushMessage messageFromNotification(@NonNull StatusBarNotification statusBarNotification) { - Bundle extras = statusBarNotification.getNotification().extras; - if (extras == null) { - return new PushMessage(new Bundle()); - } - - Bundle pushBundle = extras.getBundle(CordovaNotificationProvider.PUSH_MESSAGE_BUNDLE_EXTRA); - if (pushBundle == null) { - return new PushMessage(new Bundle()); - } else { - return new PushMessage(pushBundle); - } - } - - /** - * Helper method to create a notification JSONObject. - * - * @param message The push message. - * @param notificationTag The optional notification tag. - * @param notificationId The optional notification ID. - * @return A JSONObject containing the notification data. - */ - @NonNull - public static JSONObject notificationObject(@NonNull PushMessage message, @Nullable String notificationTag, @Nullable Integer notificationId) throws JSONException { - JSONObject data = new JSONObject(); - Map extras = new HashMap(); - for (String key : message.getPushBundle().keySet()) { - if ("android.support.content.wakelockid".equals(key)) { - continue; - } - if ("google.sent_time".equals(key)) { - extras.put(key, Long.toString(message.getPushBundle().getLong(key))); - continue; - } - if ("google.ttl".equals(key)) { - extras.put(key, Integer.toString(message.getPushBundle().getInt(key))); - continue; - } - String value = message.getPushBundle().getString(key); - if (value != null) { - extras.put(key, value); - } - } - - data.putOpt("message", message.getAlert()); - data.putOpt("title", message.getTitle()); - data.putOpt("subtitle", message.getSummary()); - data.putOpt("extras", new JSONObject(extras)); - - String actions = message.getExtra(PushMessage.EXTRA_ACTIONS); - if (actions != null) { - data.putOpt("actions", new JSONObject(actions)); - } - - if (notificationId != null) { - data.putOpt("notification_id", notificationId); - data.putOpt("notificationId", getNotificationId(notificationId, notificationTag)); - } - return data; - } - - @NonNull - private static String getNotificationId(int notificationId, @Nullable String notificationTag) { - String id = String.valueOf(notificationId); - if (!UAStringUtil.isEmpty(notificationTag)) { - id += ":" + notificationTag; - } - return id; - } -} diff --git a/urbanairship-cordova/src/android/build-extras.gradle b/urbanairship-cordova/src/android/build-extras.gradle deleted file mode 100644 index fa447b75..00000000 --- a/urbanairship-cordova/src/android/build-extras.gradle +++ /dev/null @@ -1,18 +0,0 @@ -dependencies { - def airshipVersion = "16.11.1" - implementation "com.urbanairship.android:urbanairship-fcm:$airshipVersion" - implementation "com.urbanairship.android:urbanairship-message-center:$airshipVersion" - implementation "com.urbanairship.android:urbanairship-automation:$airshipVersion" - implementation "com.urbanairship.android:urbanairship-preference-center:$airshipVersion" -} - -cdvPluginPostBuildExtras.push({ - android { - compileSdkVersion 33 - - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } - } -}) diff --git a/urbanairship-cordova/src/android/events/DeepLinkEvent.java b/urbanairship-cordova/src/android/events/DeepLinkEvent.java deleted file mode 100644 index c4e649a1..00000000 --- a/urbanairship-cordova/src/android/events/DeepLinkEvent.java +++ /dev/null @@ -1,41 +0,0 @@ -/* Copyright Urban Airship and Contributors */ - -package com.urbanairship.cordova.events; - -import com.urbanairship.cordova.PluginLogger; - -import org.json.JSONException; -import org.json.JSONObject; - -/** - * Deep link event when a new deep link is received. - */ -public class DeepLinkEvent implements Event { - private static final String EVENT_DEEPLINK_ACTION = "urbanairship.deep_link"; - - private final String deepLink; - - public DeepLinkEvent(String deepLink) { - this.deepLink = deepLink; - } - - public String getDeepLink() { - return deepLink; - } - - @Override - public String getEventName() { - return EVENT_DEEPLINK_ACTION; - } - - @Override - public JSONObject getEventData() { - JSONObject jsonObject = new JSONObject(); - try { - jsonObject.putOpt("deepLink", deepLink); - } catch (JSONException e) { - PluginLogger.error(e, "Error constructing deep link event"); - } - return jsonObject; - } -} diff --git a/urbanairship-cordova/src/android/events/Event.java b/urbanairship-cordova/src/android/events/Event.java deleted file mode 100644 index 7b657df5..00000000 --- a/urbanairship-cordova/src/android/events/Event.java +++ /dev/null @@ -1,30 +0,0 @@ -/* Copyright Urban Airship and Contributors */ - -package com.urbanairship.cordova.events; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import org.json.JSONObject; - -/** - * Interface for Urban Airship Cordova events. - */ -public interface Event { - - /** - * The event name. - * - * @return The event name. - */ - @NonNull - String getEventName(); - - /** - * The event data. - * - * @return The event data. - */ - @Nullable - JSONObject getEventData(); -} diff --git a/urbanairship-cordova/src/android/events/InboxEvent.java b/urbanairship-cordova/src/android/events/InboxEvent.java deleted file mode 100644 index 3114ef08..00000000 --- a/urbanairship-cordova/src/android/events/InboxEvent.java +++ /dev/null @@ -1,27 +0,0 @@ -/* Copyright Urban Airship and Contributors */ - -package com.urbanairship.cordova.events; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import org.json.JSONObject; - -/** - * Inbox update event. - */ -public class InboxEvent implements Event { - private static final String EVENT_INBOX_UPDATED = "urbanairship.inbox_updated"; - - @Override - @NonNull - public String getEventName() { - return EVENT_INBOX_UPDATED; - } - - @Override - @Nullable - public JSONObject getEventData() { - return null; - } -} diff --git a/urbanairship-cordova/src/android/events/NotificationOpenedEvent.java b/urbanairship-cordova/src/android/events/NotificationOpenedEvent.java deleted file mode 100644 index 22ae221c..00000000 --- a/urbanairship-cordova/src/android/events/NotificationOpenedEvent.java +++ /dev/null @@ -1,77 +0,0 @@ -/* Copyright Urban Airship and Contributors */ - -package com.urbanairship.cordova.events; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.urbanairship.cordova.PluginLogger; -import com.urbanairship.push.NotificationActionButtonInfo; -import com.urbanairship.push.NotificationInfo; - -import org.json.JSONException; -import org.json.JSONObject; - -/** - * Notification opened event. - */ -public class NotificationOpenedEvent extends PushEvent { - - private static final String EVENT_NOTIFICATION_OPENED = "urbanairship.notification_opened"; - - private static final String ACTION_ID = "actionID"; - private static final String IS_FOREGROUND = "isForeground"; - - private final NotificationActionButtonInfo actionButtonInfo; - - - /** - * Creates an event for a notification response. - * - * @param notificationInfo The notification info. - */ - public NotificationOpenedEvent(@NonNull NotificationInfo notificationInfo) { - this(notificationInfo, null); - } - - /** - * Creates an event for a notification action button response. - * - * @param notificationInfo The notification info. - * @param actionButtonInfo The notification action button info. - */ - public NotificationOpenedEvent(@NonNull NotificationInfo notificationInfo, @Nullable NotificationActionButtonInfo actionButtonInfo) { - super(notificationInfo.getNotificationId(), notificationInfo.getMessage()); - this.actionButtonInfo = actionButtonInfo; - } - - @Override - @NonNull - public String getEventName() { - return EVENT_NOTIFICATION_OPENED; - } - - - @Override - @Nullable - public JSONObject getEventData() { - JSONObject jsonObject = super.getEventData(); - - if (jsonObject == null) { - return null; - } - - try { - if (actionButtonInfo != null) { - jsonObject.put(ACTION_ID, actionButtonInfo.getButtonId()); - jsonObject.put(IS_FOREGROUND, actionButtonInfo.isForeground()); - } else { - jsonObject.put(IS_FOREGROUND, true); - } - } catch (JSONException e) { - PluginLogger.error(e,"Error constructing notification object"); - } - - return jsonObject; - } -} diff --git a/urbanairship-cordova/src/android/events/NotificationOptInEvent.java b/urbanairship-cordova/src/android/events/NotificationOptInEvent.java deleted file mode 100644 index b4c4799e..00000000 --- a/urbanairship-cordova/src/android/events/NotificationOptInEvent.java +++ /dev/null @@ -1,52 +0,0 @@ -/* Copyright Urban Airship and Contributors */ - -package com.urbanairship.cordova.events; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.urbanairship.cordova.PluginLogger; - -import org.json.JSONException; -import org.json.JSONObject; - - -/** - * Notification opt-in status event. - */ -public class NotificationOptInEvent implements Event { - - private static final String NOTIFICATION_OPT_IN_STATUS_EVENT = "urbanairship.notification_opt_in_status"; - private static final String OPT_IN = "optIn"; - - private final boolean optIn; - - /** - * Default constructor. - * - * @param optIn The app opt-in status. - */ - public NotificationOptInEvent(boolean optIn) { - this.optIn = optIn; - } - - @NonNull - @Override - public String getEventName() { - return NOTIFICATION_OPT_IN_STATUS_EVENT; - } - - @Override - @Nullable - public JSONObject getEventData() { - JSONObject data = new JSONObject(); - - try { - data.put(OPT_IN, optIn); - } catch (JSONException e) { - PluginLogger.error(e, "Error adding opt-in event data"); - } - - return data; - } -} diff --git a/urbanairship-cordova/src/android/events/PreferenceCenterEvent.java b/urbanairship-cordova/src/android/events/PreferenceCenterEvent.java deleted file mode 100644 index 79f3f695..00000000 --- a/urbanairship-cordova/src/android/events/PreferenceCenterEvent.java +++ /dev/null @@ -1,41 +0,0 @@ -/* Copyright Urban Airship and Contributors */ - -package com.urbanairship.cordova.events; - -import com.urbanairship.cordova.PluginLogger; - -import org.json.JSONException; -import org.json.JSONObject; - -/** - * Preference Center event when the open preference center listener is called. - */ -public class PreferenceCenterEvent implements com.urbanairship.cordova.events.Event { - private static final String EVENT_PREFERENCE_CENTER_ACTION = "urbanairship.open_preference_center"; - - private final String preferenceCenterId; - - public PreferenceCenterEvent(String preferenceCenterId) { - this.preferenceCenterId = preferenceCenterId; - } - - public String getPreferenceCenterId() { - return preferenceCenterId; - } - - @Override - public String getEventName() { - return EVENT_PREFERENCE_CENTER_ACTION; - } - - @Override - public JSONObject getEventData() { - JSONObject jsonObject = new JSONObject(); - try { - jsonObject.putOpt("preferenceCenterId", preferenceCenterId); - } catch (JSONException e) { - PluginLogger.error(e, "Error constructing preference center event"); - } - return jsonObject; - } -} diff --git a/urbanairship-cordova/src/android/events/PushEvent.java b/urbanairship-cordova/src/android/events/PushEvent.java deleted file mode 100644 index ce03b11a..00000000 --- a/urbanairship-cordova/src/android/events/PushEvent.java +++ /dev/null @@ -1,46 +0,0 @@ -/* Copyright Urban Airship and Contributors */ - -package com.urbanairship.cordova.events; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.urbanairship.cordova.PluginLogger; -import com.urbanairship.cordova.Utils; -import com.urbanairship.push.PushMessage; - -import org.json.JSONException; -import org.json.JSONObject; - -/** - * Push event. - */ -public class PushEvent implements Event { - - private static final String EVENT_PUSH_RECEIVED = "urbanairship.push"; - - private final PushMessage message; - private final Integer notificationId; - - public PushEvent(@Nullable Integer notificationId, @NonNull PushMessage message) { - this.notificationId = notificationId; - this.message = message; - } - - @NonNull - @Override - public String getEventName() { - return EVENT_PUSH_RECEIVED; - } - - @Nullable - @Override - public JSONObject getEventData() { - try { - return Utils.notificationObject(message, message.getNotificationTag(), notificationId); - } catch (JSONException e) { - PluginLogger.error(e, "Error constructing notification object"); - return null; - } - } -} diff --git a/urbanairship-cordova/src/android/events/RegistrationEvent.java b/urbanairship-cordova/src/android/events/RegistrationEvent.java deleted file mode 100644 index 61900dc6..00000000 --- a/urbanairship-cordova/src/android/events/RegistrationEvent.java +++ /dev/null @@ -1,60 +0,0 @@ -/* Copyright Urban Airship and Contributors */ - -package com.urbanairship.cordova.events; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.urbanairship.cordova.PluginLogger; - -import org.json.JSONException; -import org.json.JSONObject; - -/** - * Registration event. - */ -public class RegistrationEvent implements Event { - - private static final String EVENT_CHANNEL_UPDATED = "urbanairship.registration"; - - private static final String CHANNEL_ID = "channelID"; - private static final String REGISTRATION_TOKEN = "registrationToken"; - - private final String channel; - private final String registrationToken; - private final boolean success; - - - public RegistrationEvent(@Nullable String channel, @Nullable String registrationToken, boolean success) { - this.channel = channel; - this.registrationToken = registrationToken; - this.success = success; - } - - @NonNull - @Override - public String getEventName() { - return EVENT_CHANNEL_UPDATED; - } - - @Nullable - @Override - public JSONObject getEventData() { - JSONObject data = new JSONObject(); - try { - if (success) { - data.put(CHANNEL_ID, channel); - if (registrationToken != null) { - data.put(REGISTRATION_TOKEN, registrationToken); - } - - } else { - data.put("error", "Invalid registration."); - } - } catch (JSONException e) { - PluginLogger.error(e, "Error in channel registration"); - } - - return data; - } -} diff --git a/urbanairship-cordova/src/android/events/ShowInboxEvent.java b/urbanairship-cordova/src/android/events/ShowInboxEvent.java deleted file mode 100644 index 07672d90..00000000 --- a/urbanairship-cordova/src/android/events/ShowInboxEvent.java +++ /dev/null @@ -1,54 +0,0 @@ -/* Copyright Urban Airship and Contributors */ - -package com.urbanairship.cordova.events; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.urbanairship.cordova.PluginLogger; - -import org.json.JSONException; -import org.json.JSONObject; - - -/** - * Show inbox event. - */ -public class ShowInboxEvent implements Event { - - private static final String SHOW_INBOX_EVENT = "urbanairship.show_inbox"; - private static final String MESSAGE_ID = "messageId"; - - private final String messageId; - - /** - * Default constructor. - * - * @param messageId The optional message ID. - */ - public ShowInboxEvent(@Nullable String messageId) { - this.messageId = messageId; - } - - @Override - @NonNull - public String getEventName() { - return SHOW_INBOX_EVENT; - } - - @Override - @Nullable - public JSONObject getEventData() { - JSONObject data = new JSONObject(); - - try { - if (messageId != null) { - data.put(MESSAGE_ID, messageId); - } - } catch (JSONException e) { - PluginLogger.error(e, "Error in show inbox event"); - } - - return data; - } -} diff --git a/urbanairship-cordova/src/ios/UACordovaPluginManager.h b/urbanairship-cordova/src/ios/UACordovaPluginManager.h deleted file mode 100644 index b5b8952e..00000000 --- a/urbanairship-cordova/src/ios/UACordovaPluginManager.h +++ /dev/null @@ -1,111 +0,0 @@ -/* Copyright Urban Airship and Contributors */ - -#import - -#if __has_include("AirshipLib.h") -#import "AirshipLib.h" -#else -@import AirshipKit; -#endif - -NS_ASSUME_NONNULL_BEGIN - -/** - * Manager delegate. - */ -@protocol UACordovaPluginManagerDelegate - -/** - * Called to notify listeners of a new or pending event. - * - * @param eventType The event type string. - * @param data The json payload dictionary. - * - * @return `YES` if a listener was notified, `NO` otherwise. - */ --(BOOL)notifyListener:(NSString *)eventType data:(NSDictionary *)data; -@end - -/** - * Manages config and event forwarding from the Urban Airship SDK. - */ -@interface UACordovaPluginManager : NSObject - -/** - * Delegate. - */ -@property (nonatomic, weak, nullable) id delegate; - -/** - * Last received deep link. - */ -@property (nonatomic, copy, nullable) NSString *lastReceivedDeepLink; - -/** - * Flag that enables/disables auto launching the default message center. - */ -@property (nonatomic, assign) BOOL autoLaunchMessageCenter; - -/** - * Last received notification response. - */ -@property (nonatomic, copy, nullable) NSDictionary *lastReceivedNotificationResponse; - -/** - * Checks if Airship is ready. - */ -@property (nonatomic, readonly, assign) BOOL isAirshipReady; - -/** - * Factory method. - * @param defaultConfig The default cordova config. - * @return Plugin Manager instance. - */ -+ (instancetype)pluginManagerWithDefaultConfig:(NSDictionary *)defaultConfig; - -/** - * Attempts takeOff if Airship is not already flying. - */ -- (void)attemptTakeOff; - -/** - * Attempts takeOff if Airship is not already flying with launch options. - */ -- (void)attemptTakeOffWithLaunchOptions:(nullable NSDictionary *)launchOptions; - -/** - * Sets the development credentials. - * @param appKey UA app key. - * @param appSecret UA app secret. - */ -- (void)setDevelopmentAppKey:(NSString *)appKey appSecret:(NSString *)appSecret; - -/** - * Sets the production credentials. - * @param appKey The appKey. - * @param appSecret The appSecret. - */ -- (void)setProductionAppKey:(NSString *)appKey appSecret:(NSString *)appSecret; - -/** - * Sets the cloud site. - * @param site The site, either "US" or "EU". - */ -- (void)setCloudSite:(NSString *)site; - -/** - * Sets the message center style config file. - * @param fileName The plist file name that will be used to set the message center style. - */ -- (void)setMessageCenterStyleFile:(NSString *)fileName; - -/** - * Sets the presentation options. - * @param options The presentation options. - */ -- (void)setPresentationOptions:(NSUInteger)options; - -- (void)setPreferenceCenter:(NSString *)preferenceCenterID useCustomUI:(BOOL)useCustomUI; -@end - -NS_ASSUME_NONNULL_END diff --git a/urbanairship-cordova/src/ios/UACordovaPluginManager.m b/urbanairship-cordova/src/ios/UACordovaPluginManager.m deleted file mode 100644 index 615842c5..00000000 --- a/urbanairship-cordova/src/ios/UACordovaPluginManager.m +++ /dev/null @@ -1,436 +0,0 @@ -/* Copyright Urban Airship and Contributors */ - -#import "UACordovaPluginManager.h" - -#if __has_include("AirshipLib.h") -#import "AirshipLib.h" -#import "AirshipMessageCenterLib.h" -#else -@import AirshipKit; -#endif - -#import "UACordovaEvent.h" -#import "UACordovaDeepLinkEvent.h" -#import "UACordovaInboxUpdatedEvent.h" -#import "UACordovaNotificationOpenedEvent.h" -#import "UACordovaNotificationOptInEvent.h" -#import "UACordovaPushEvent.h" -#import "UACordovaRegistrationEvent.h" -#import "UACordovaShowInboxEvent.h" -#import "UACordovaPreferenceCenterEvent.h" - -// Config keys -NSString *const ProductionAppKeyConfigKey = @"com.urbanairship.production_app_key"; -NSString *const ProductionAppSecretConfigKey = @"com.urbanairship.production_app_secret"; -NSString *const DevelopmentAppKeyConfigKey = @"com.urbanairship.development_app_key"; -NSString *const DevelopmentAppSecretConfigKey = @"com.urbanairship.development_app_secret"; -NSString *const ProductionLogLevelKey = @"com.urbanairship.production_log_level"; -NSString *const DevelopmentLogLevelKey = @"com.urbanairship.development_log_level"; -NSString *const ProductionConfigKey = @"com.urbanairship.in_production"; -NSString *const EnablePushOnLaunchConfigKey = @"com.urbanairship.enable_push_onlaunch"; -NSString *const ClearBadgeOnLaunchConfigKey = @"com.urbanairship.clear_badge_onlaunch"; -NSString *const EnableAnalyticsConfigKey = @"com.urbanairship.enable_analytics"; -NSString *const AutoLaunchMessageCenterKey = @"com.urbanairship.auto_launch_message_center"; -NSString *const NotificationPresentationAlertKey = @"com.urbanairship.ios_foreground_notification_presentation_alert"; -NSString *const NotificationPresentationBadgeKey = @"com.urbanairship.ios_foreground_notification_presentation_badge"; -NSString *const NotificationPresentationSoundKey = @"com.urbanairship.ios_foreground_notification_presentation_sound"; -NSString *const CloudSiteConfigKey = @"com.urbanairship.site"; -NSString *const MessageCenterStyleConfigKey = @"com.urbanairship.message.center.style.file"; -NSString *const CloudSiteEUString = @"EU"; -NSString *const InitialConfigURLKey = @"com.urbanairship.initial_config_url"; - -NSString *const UACordovaPluginVersionKey = @"UACordovaPluginVersion"; - -// Events -NSString *const CategoriesPlistPath = @"UACustomNotificationCategories"; - - -@interface UACordovaPluginManager() -@property (nonatomic, strong) NSDictionary *defaultConfig; -@property (nonatomic, strong) NSMutableArray *> *pendingEvents; -@property (nonatomic, assign) BOOL isAirshipReady; - -@end -@implementation UACordovaPluginManager - -- (void)load { - [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidFinishLaunchingNotification - object:nil - queue:nil usingBlock:^(NSNotification * _Nonnull note) { - - [self attemptTakeOffWithLaunchOptions:note.userInfo]; - }]; -} - -- (void)dealloc { - [UAirship push].pushNotificationDelegate = nil; - [UAirship push].registrationDelegate = nil; - [UAMessageCenter shared].displayDelegate = nil; - [UAPreferenceCenter shared].openDelegate = nil; - [[NSNotificationCenter defaultCenter] removeObserver:self]; -} - -- (instancetype)initWithDefaultConfig:(NSDictionary *)defaultConfig { - self = [super init]; - - if (self) { - self.defaultConfig = defaultConfig; - self.pendingEvents = [NSMutableArray array]; - } - - return self; -} - -+ (instancetype)pluginManagerWithDefaultConfig:(NSDictionary *)defaultConfig { - return [[UACordovaPluginManager alloc] initWithDefaultConfig:defaultConfig]; -} - -- (void)attemptTakeOff { - [self attemptTakeOffWithLaunchOptions:nil]; -} - -- (void)attemptTakeOffWithLaunchOptions:(NSDictionary *)launchOptions { - if (self.isAirshipReady) { - return; - } - - UAConfig *config = [self createAirshipConfig]; - if (![config validate]) { - return; - } - - [UAirship takeOff:config launchOptions:launchOptions]; - [self registerCordovaPluginVersion]; - - if ([[self configValueForKey:EnablePushOnLaunchConfigKey] boolValue]) { - [UAirship push].userPushNotificationsEnabled = true; - } - - if ([[self configValueForKey:ClearBadgeOnLaunchConfigKey] boolValue]) { - [[UAirship push] resetBadge]; - } - - [self loadCustomNotificationCategories]; - - [UAirship push].pushNotificationDelegate = self; - [UAirship push].registrationDelegate = self; - [UAMessageCenter shared].displayDelegate = self; - [UAirship shared].deepLinkDelegate = self; - [UAPreferenceCenter shared].openDelegate = self; - - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(inboxUpdated) - name:UAInboxMessageListUpdatedNotification - object:nil]; - - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(channelRegistrationSucceeded:) - name:UAChannel.channelUpdatedEvent - object:nil]; - - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(channelRegistrationFailed) - name:UAChannel.channelRegistrationFailedEvent - object:nil]; - - - - self.isAirshipReady = YES; -} - -- (void)loadCustomNotificationCategories { - NSString *categoriesPath = [[NSBundle mainBundle] pathForResource:CategoriesPlistPath ofType:@"plist"]; - NSSet *customNotificationCategories = [UANotificationCategories createCategoriesFromFile:categoriesPath]; - - if (customNotificationCategories.count) { - UA_LDEBUG(@"Registering custom notification categories: %@", customNotificationCategories); - [UAirship push].customCategories = customNotificationCategories; - [[UAirship push] updateRegistration]; - } -} - -- (UAConfig *)createAirshipConfig { - UAConfig *airshipConfig = [UAConfig config]; - airshipConfig.productionAppKey = [self configValueForKey:ProductionAppKeyConfigKey]; - airshipConfig.productionAppSecret = [self configValueForKey:ProductionAppSecretConfigKey]; - airshipConfig.developmentAppKey = [self configValueForKey:DevelopmentAppKeyConfigKey]; - airshipConfig.developmentAppSecret = [self configValueForKey:DevelopmentAppSecretConfigKey]; - airshipConfig.URLAllowListScopeOpenURL = @[@"*"]; - - NSString *cloudSite = [self configValueForKey:CloudSiteConfigKey]; - airshipConfig.site = [UACordovaPluginManager parseCloudSiteString:cloudSite]; - - NSString* fileName = [self configValueForKey:MessageCenterStyleConfigKey]; - if (fileName == nil) { - fileName = @"messageCenterConfigStyle"; - } - airshipConfig.messageCenterStyleConfig = fileName; - - if ([self configValueForKey:ProductionConfigKey] != nil) { - airshipConfig.inProduction = [[self configValueForKey:ProductionConfigKey] boolValue]; - } - - airshipConfig.developmentLogLevel = [self parseLogLevel:[self configValueForKey:DevelopmentLogLevelKey] - defaultLogLevel:UALogLevelDebug]; - - airshipConfig.productionLogLevel = [self parseLogLevel:[self configValueForKey:ProductionLogLevelKey] - defaultLogLevel:UALogLevelError]; - - if ([self configValueForKey:EnableAnalyticsConfigKey] != nil) { - airshipConfig.isAnalyticsEnabled = [[self configValueForKey:EnableAnalyticsConfigKey] boolValue]; - } - - if ([self configValueForKey:InitialConfigURLKey] != nil) { - airshipConfig.initialConfigURL = [self configValueForKey:InitialConfigURLKey]; - } - - airshipConfig.enabledFeatures = UAFeaturesAll; - - return airshipConfig; -} - -- (void)registerCordovaPluginVersion { - NSString *version = [NSBundle mainBundle].infoDictionary[UACordovaPluginVersionKey] ?: @"0.0.0"; - [[UAirship analytics] registerSDKExtension:UASDKExtensionCordova version:version]; -} - -- (id)configValueForKey:(NSString *)key { - id value = [[NSUserDefaults standardUserDefaults] objectForKey:key]; - if (value != nil) { - return value; - } - - return self.defaultConfig[key]; -} - -- (BOOL)autoLaunchMessageCenter { - if ([self configValueForKey:AutoLaunchMessageCenterKey] == nil) { - return YES; - } - - return [[self configValueForKey:AutoLaunchMessageCenterKey] boolValue]; -} - -- (void)setAutoLaunchMessageCenter:(BOOL)autoLaunchMessageCenter { - [[NSUserDefaults standardUserDefaults] setValue:@(autoLaunchMessageCenter) forKey:AutoLaunchMessageCenterKey]; -} - -- (void)setProductionAppKey:(NSString *)appKey appSecret:(NSString *)appSecret { - [[NSUserDefaults standardUserDefaults] setValue:appKey forKey:ProductionAppKeyConfigKey]; - [[NSUserDefaults standardUserDefaults] setValue:appSecret forKey:ProductionAppSecretConfigKey]; -} - -- (void)setDevelopmentAppKey:(NSString *)appKey appSecret:(NSString *)appSecret { - [[NSUserDefaults standardUserDefaults] setValue:appKey forKey:DevelopmentAppKeyConfigKey]; - [[NSUserDefaults standardUserDefaults] setValue:appSecret forKey:DevelopmentAppSecretConfigKey]; -} - -- (void)setCloudSite:(NSString *)site { - [[NSUserDefaults standardUserDefaults] setValue:site forKey:CloudSiteConfigKey]; -} - -- (void)setMessageCenterStyleFile:(NSString *)fileName { - [[NSUserDefaults standardUserDefaults] setValue:fileName forKey:MessageCenterStyleConfigKey]; -} - -- (void)setPresentationOptions:(NSUInteger)options { - [[NSUserDefaults standardUserDefaults] setValue:@(options & UNNotificationPresentationOptionAlert) forKey:NotificationPresentationAlertKey]; - [[NSUserDefaults standardUserDefaults] setValue:@(options & UNNotificationPresentationOptionBadge) forKey:NotificationPresentationBadgeKey]; - [[NSUserDefaults standardUserDefaults] setValue:@(options & UNNotificationPresentationOptionSound) forKey:NotificationPresentationSoundKey]; -} - --(NSInteger)parseLogLevel:(id)logLevel defaultLogLevel:(UALogLevel)defaultValue { - if (![logLevel isKindOfClass:[NSString class]] || ![logLevel length]) { - return defaultValue; - } - - NSString *normalizedLogLevel = [[logLevel stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] lowercaseString]; - - if ([normalizedLogLevel isEqualToString:@"verbose"]) { - return UALogLevelTrace; - } else if ([normalizedLogLevel isEqualToString:@"debug"]) { - return UALogLevelDebug; - } else if ([normalizedLogLevel isEqualToString:@"info"]) { - return UALogLevelInfo; - } else if ([normalizedLogLevel isEqualToString:@"warning"]) { - return UALogLevelWarn; - } else if ([normalizedLogLevel isEqualToString:@"error"]) { - return UALogLevelError; - } else if ([normalizedLogLevel isEqualToString:@"none"]) { - return UALogLevelNone; - } - - return defaultValue; -} - -+ (UACloudSite)parseCloudSiteString:(NSString *)site { - if ([CloudSiteEUString caseInsensitiveCompare:site] == NSOrderedSame) { - return UACloudSiteEU; - } else { - return UACloudSiteUS; - } -} - -#pragma mark - -#pragma mark UAInboxDelegate - -- (void)displayMessageCenterForMessageID:(NSString *)messageID animated:(BOOL)animated { - if (self.autoLaunchMessageCenter) { - [[UAMessageCenter shared].defaultUI displayMessageCenterForMessageID:messageID animated:true]; - } else { - [self fireEvent:[UACordovaShowInboxEvent eventWithMessageID:messageID]]; - } -} - -- (void)displayMessageCenterAnimated:(BOOL)animated { - if (self.autoLaunchMessageCenter) { - [[UAMessageCenter shared].defaultUI displayMessageCenterAnimated:animated]; - } else { - [self fireEvent:[UACordovaShowInboxEvent event]]; - } -} - -- (void)dismissMessageCenterAnimated:(BOOL)animated { - if (self.autoLaunchMessageCenter) { - [[UAMessageCenter shared].defaultUI dismissMessageCenterAnimated:animated]; - } -} - -- (void)inboxUpdated { - UA_LDEBUG(@"Inbox updated"); - [self fireEvent:[UACordovaInboxUpdatedEvent event]]; -} - -#pragma mark - -#pragma mark UAPushNotificationDelegate - --(void)receivedForegroundNotification:(NSDictionary *)userInfo completionHandler:(void (^)(void))completionHandler { - UA_LDEBUG(@"Received a notification while the app was already in the foreground %@", userInfo); - - [self fireEvent:[UACordovaPushEvent eventWithNotificationContent:userInfo]]; - - completionHandler(); -} - -- (void)receivedBackgroundNotification:(NSDictionary *)userInfo - completionHandler:(void (^)(UIBackgroundFetchResult))completionHandler { - - UA_LDEBUG(@"Received a background notification %@", userInfo); - - [self fireEvent:[UACordovaPushEvent eventWithNotificationContent:userInfo]]; - - completionHandler(UIBackgroundFetchResultNoData); -} - --(void)receivedNotificationResponse:(UNNotificationResponse *)notificationResponse completionHandler:(void (^)(void))completionHandler { - UA_LDEBUG(@"The application was launched or resumed from a notification %@", notificationResponse); - - UACordovaNotificationOpenedEvent *event = [UACordovaNotificationOpenedEvent eventWithNotificationResponse:notificationResponse]; - self.lastReceivedNotificationResponse = event.data; - [self fireEvent:event]; - - completionHandler(); -} - -- (UNNotificationPresentationOptions)extendPresentationOptions:(UNNotificationPresentationOptions)options notification:(UNNotification *)notification { - if ([[self configValueForKey:NotificationPresentationAlertKey] boolValue]) { - options = options | UNNotificationPresentationOptionAlert; - } - - if ([[self configValueForKey:NotificationPresentationBadgeKey] boolValue]) { - options = options | UNNotificationPresentationOptionBadge; - } - - if ([[self configValueForKey:NotificationPresentationSoundKey] boolValue]) { - options = options | UNNotificationPresentationOptionSound; - } - - return options; -} - -#pragma mark - -#pragma mark UADeepLinkDelegate - --(void)receivedDeepLink:(NSURL *_Nonnull)url completionHandler:(void (^_Nonnull)(void))completionHandler { - self.lastReceivedDeepLink = [url absoluteString]; - [self fireEvent:[UACordovaDeepLinkEvent eventWithDeepLink:url]]; - completionHandler(); -} - -#pragma mark - -#pragma mark Channel Registration Events - -- (void)channelRegistrationSucceeded:(NSNotification *)notification { - NSString *channelID = notification.userInfo[UAChannel.channelIdentifierKey]; - NSString *deviceToken = [UAirship push].deviceToken; - - UA_LINFO(@"Channel registration successful %@.", channelID); - - [self fireEvent:[UACordovaRegistrationEvent registrationSucceededEventWithChannelID:channelID deviceToken:deviceToken]]; -} - -- (void)channelRegistrationFailed { - UA_LINFO(@"Channel registration failed."); - [self fireEvent:[UACordovaRegistrationEvent registrationFailedEvent]]; -} - -#pragma mark - -#pragma mark UARegistrationDelegate - -- (void)notificationAuthorizedSettingsDidChange:(UAAuthorizedNotificationSettings)authorizedSettings { - UACordovaNotificationOptInEvent *event = [UACordovaNotificationOptInEvent eventWithAuthorizedSettings:authorizedSettings]; - [self fireEvent:event]; -} - -- (void)fireEvent:(NSObject *)event { - id strongDelegate = self.delegate; - - if (strongDelegate && [strongDelegate notifyListener:event.type data:event.data]) { - UA_LTRACE(@"Cordova plugin manager delegate notified with event of type:%@ with data:%@", event.type, event.data); - - return; - } - - UA_LTRACE(@"No cordova plugin manager delegate available, storing pending event of type:%@ with data:%@", event.type, event.data); - - // Add pending event - [self.pendingEvents addObject:event]; -} - -- (void)setDelegate:(id)delegate { - _delegate = delegate; - - if (delegate) { - @synchronized(self.pendingEvents) { - UA_LTRACE(@"Cordova plugin manager delegate set:%@", delegate); - - NSDictionary *events = [self.pendingEvents copy]; - [self.pendingEvents removeAllObjects]; - - for (NSObject *event in events) { - [self fireEvent:event]; - } - } - } -} - -#pragma mark - -#pragma mark UAPreferenceCenterOpenDelegate - -- (BOOL)openPreferenceCenter:(NSString * _Nonnull)preferenceCenterID { - BOOL useCustomUi = [[NSUserDefaults standardUserDefaults] boolForKey:[self preferenceCenterUIKey:preferenceCenterID]]; - if (useCustomUi) { - [self fireEvent:[UACordovaPreferenceCenterEvent eventWithPreferenceCenterId:preferenceCenterID]]; - } - return useCustomUi; -} - -- (void)setPreferenceCenter:(NSString *)preferenceCenterID useCustomUI:(BOOL)useCustomUI { - [[NSUserDefaults standardUserDefaults] setBool:useCustomUI forKey:[self preferenceCenterUIKey:preferenceCenterID]]; -} - -- (NSString *)preferenceCenterUIKey:(NSString *)preferenceCenterID { - return [NSString stringWithFormat:@"com.urbanairship.preference_%@_custom_ui", preferenceCenterID]; -} - -@end diff --git a/urbanairship-cordova/src/ios/UAMessageViewController.h b/urbanairship-cordova/src/ios/UAMessageViewController.h deleted file mode 100644 index 0d009ec7..00000000 --- a/urbanairship-cordova/src/ios/UAMessageViewController.h +++ /dev/null @@ -1,15 +0,0 @@ -/* Copyright Urban Airship and Contributors */ - -#if __has_include("AirshipLib.h") -#import "AirshipLib.h" -#import "AirshipMessageCenterLib.h" -#else -@import AirshipKit; -#endif - -@interface UAMessageViewController : UINavigationController - -- (void)loadMessageForID:(nullable NSString *)messageID; - -@end - diff --git a/urbanairship-cordova/src/ios/UAMessageViewController.m b/urbanairship-cordova/src/ios/UAMessageViewController.m deleted file mode 100644 index eda2999d..00000000 --- a/urbanairship-cordova/src/ios/UAMessageViewController.m +++ /dev/null @@ -1,179 +0,0 @@ -/* Copyright Urban Airship and Contributors */ - -#import "UAMessageViewController.h" - -@interface UAMessageViewController() -@property (nonatomic, copy) NSString *pendingMessageID; -@property (nonatomic, strong) UADefaultMessageCenterMessageViewController *airshipMessageViewController; -@end - -@implementation UAMessageViewController - -- (void)viewDidLoad { - [super viewDidLoad]; - - self.airshipMessageViewController = [[UADefaultMessageCenterMessageViewController alloc] - initWithNibName:@"UADefaultMessageCenterMessageViewController" - bundle:[UAMessageCenterResources bundle]]; - self.airshipMessageViewController.delegate = self; - - - UIBarButtonItem *done = [[UIBarButtonItem alloc] - initWithBarButtonSystemItem:UIBarButtonSystemItemDone - target:self - action:@selector(inboxMessageDone:)]; - - self.airshipMessageViewController.navigationItem.leftBarButtonItem = done; - - self.viewControllers = @[self.airshipMessageViewController]; - - if (self.pendingMessageID) { - [self.airshipMessageViewController loadMessageForID:self.pendingMessageID]; - self.pendingMessageID = nil; - } -} - -- (void)viewDidLayoutSubviews { - self.airshipMessageViewController.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:UAMessageCenterLocalizedString(@"ua_delete_message") - style:UIBarButtonItemStylePlain - target:self - action:@selector(delete:)]; - self.airshipMessageViewController.navigationItem.rightBarButtonItem.accessibilityHint = UAMessageCenterLocalizedString(@"ua_delete_message_description"); - -} - -- (void)inboxMessageDone:(id)sender { - [self dismissViewControllerAnimated:true completion:nil]; -} - -- (void)loadMessageForID:(NSString *)messageID { - if (self.airshipMessageViewController) { - [self.airshipMessageViewController loadMessageForID:messageID]; - self.pendingMessageID = nil; - } else { - self.pendingMessageID = messageID; - } -} - -#pragma mark UAMessageCenterMessageViewDelegate - -- (void)delete:(nullable id)sender { - [self.airshipMessageViewController delete:sender]; - [self dismissViewControllerAnimated:YES completion:nil]; -} - -- (void)messageClosed:(NSString *)messageID { - [self dismissViewControllerAnimated:YES completion:nil]; -} - -- (void)messageLoadStarted:(NSString *)messageID { - // no-op -} - -- (void)messageLoadSucceeded:(NSString *)messageID { - // no-op -} - -- (void)displayFailedToLoadAlertOnOK:(void (^)(void))okCompletion onRetry:(void (^)(void))retryCompletion { - UIAlertController* alert = [UIAlertController alertControllerWithTitle:UAMessageCenterLocalizedString(@"ua_connection_error") - message:UAMessageCenterLocalizedString(@"ua_mc_failed_to_load") - preferredStyle:UIAlertControllerStyleAlert]; - - UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:UAMessageCenterLocalizedString(@"ua_ok") - style:UIAlertActionStyleDefault - handler:^(UIAlertAction * action) { - if (okCompletion) { - okCompletion(); - } - }]; - - [alert addAction:defaultAction]; - - if (retryCompletion) { - UIAlertAction *retryAction = [UIAlertAction actionWithTitle:UAMessageCenterLocalizedString(@"ua_retry_button") - style:UIAlertActionStyleDefault - handler:^(UIAlertAction * _Nonnull action) { - if (retryCompletion) { - retryCompletion(); - } - }]; - - [alert addAction:retryAction]; - } - - [self presentViewController:alert animated:YES completion:nil]; -} - -- (void)displayNoLongerAvailableAlertOnOK:(void (^)(void))okCompletion { - UIAlertController* alert = [UIAlertController alertControllerWithTitle:UAMessageCenterLocalizedString(@"ua_content_error") - message:UAMessageCenterLocalizedString(@"ua_mc_no_longer_available") - preferredStyle:UIAlertControllerStyleAlert]; - - UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:UAMessageCenterLocalizedString(@"ua_ok") - style:UIAlertActionStyleDefault - handler:^(UIAlertAction * action) { - if (okCompletion) { - okCompletion(); - } - }]; - - [alert addAction:defaultAction]; - - [self presentViewController:alert animated:YES completion:nil]; -} - -- (void)messageLoadFailed:(NSString *)messageID error:(NSError *)error { - UA_LTRACE(@"message load failed: %@", messageID); - - void (^retry)(void) = ^{ - UA_WEAKIFY(self); - [self displayFailedToLoadAlertOnOK:^{ - UA_STRONGIFY(self) - [self dismissViewControllerAnimated:true completion:nil]; - } onRetry:^{ - UA_STRONGIFY(self) - [self loadMessageForID:messageID]; - }]; - }; - - void (^handleFailed)(void) = ^{ - UA_WEAKIFY(self); - [self displayFailedToLoadAlertOnOK:^{ - UA_STRONGIFY(self) - [self dismissViewControllerAnimated:true completion:nil]; - } onRetry:nil]; - }; - - void (^handleExpired)(void) = ^{ - UA_WEAKIFY(self); - [self displayNoLongerAvailableAlertOnOK:^{ - UA_STRONGIFY(self) - [self dismissViewControllerAnimated:true completion:nil]; - }]; - }; - - if ([error.domain isEqualToString:UAMessageCenterMessageLoadErrorDomain]) { - if (error.code == UAMessageCenterMessageLoadErrorCodeFailureStatus) { - // Encountered a failure status code - NSUInteger status = [error.userInfo[UAMessageCenterMessageLoadErrorHTTPStatusKey] unsignedIntValue]; - - if (status >= 500) { - retry(); - } else if (status == 410) { - // Gone: message has been permanently deleted from the backend. - handleExpired(); - } else { - handleFailed(); - } - } else if (error.code == UAMessageCenterMessageLoadErrorCodeMessageExpired) { - handleExpired(); - } else { - retry(); - } - } else { - // Other errors - retry(); - } -} -@end - diff --git a/urbanairship-cordova/src/ios/UAirshipPlugin.h b/urbanairship-cordova/src/ios/UAirshipPlugin.h deleted file mode 100644 index 8fbfe64a..00000000 --- a/urbanairship-cordova/src/ios/UAirshipPlugin.h +++ /dev/null @@ -1,533 +0,0 @@ -/* Copyright Urban Airship and Contributors */ - -#import -#import - -#if __has_include("AirshipLib.h") -#import "AirshipLib.h" -#import "AirshipMessageCenterLib.h" -#import "AirshipAutomationLib.h" -#else -@import AirshipKit; -#endif - -/** - * The Urban Airship Cordova plugin. - */ -@interface UAirshipPlugin : CDVPlugin - -/** - * Sets the Urban Airship config and attempts takeOff. - * - * Expected arguments: NSDictionary - * - * @param command The cordova command. - */ -- (void)takeOff:(CDVInvokedUrlCommand *)command; - -/** - * Sets the default behavior when the message center is launched from a push - * notification. If set to false the message center must be manually launched. - * - * Expected arguments: Boolean - * - * @param command The cordova command. - */ -- (void)setAutoLaunchDefaultMessageCenter:(CDVInvokedUrlCommand *)command; - -/** - * Enables or disables user push notifications. - * - * Expected arguments: Boolean - * - * @param command The cordova command. - */ -- (void)setUserNotificationsEnabled:(CDVInvokedUrlCommand *)command; - -/** - * Enables user push notifications. - * - * @param command The cordova command. - */ -- (void)enableUserNotifications:(CDVInvokedUrlCommand *)command; - -/** - * Checks if user push notifications are enabled or not. - * - * @param command The cordova command. - */ -- (void)isUserNotificationsEnabled:(CDVInvokedUrlCommand *)command; - -/** - * Returns the last notification that launched the application. - * - * Expected arguments: Boolean - `YES` to clear the notification. - * - * @param command The cordova command. - */ -- (void)getLaunchNotification:(CDVInvokedUrlCommand *)command; - -/** - * Returns the last received deep link. - * - * Expected arguments: Boolean - `YES` to clear the deep link. - * - * @param command The cordova command. - */ -- (void)getDeepLink:(CDVInvokedUrlCommand *)command; - -/** - * Returns the channel ID. - * - * @param command The cordova command. - */ -- (void)getChannelID:(CDVInvokedUrlCommand *)command; - -/** - * Returns the tags as an array. - * - * @param command The cordova command. - */ -- (void)getTags:(CDVInvokedUrlCommand *)command; - -/** - * Sets the tags. - * - * Expected arguments: An array of Strings - * - * @param command The cordova command. - */ -- (void)setTags:(CDVInvokedUrlCommand *)command; - -/** - * Returns the current badge number. - * - * @param command The cordova command. - */ -- (void)getBadgeNumber:(CDVInvokedUrlCommand *)command; - -/** - * Enables or disables auto badge. Defaults to `NO`. - * - * Expected arguments: Boolean - * - * @param command The cordova command. - */ -- (void)setAutobadgeEnabled:(CDVInvokedUrlCommand *)command; - -/** - * Sets the badge number. - * - * Expected arguments: Number - * - * @param command The cordova command. - */ -- (void)setBadgeNumber:(CDVInvokedUrlCommand *)command; - -/** - * Clears the badge. - * - * @param command The cordova command. - */ -- (void)resetBadge:(CDVInvokedUrlCommand *)command; - -/** - * Sets the named user ID. - * - * Expected arguments: String - * - * @param command The cordova command. - */ -- (void)setNamedUser:(CDVInvokedUrlCommand *)command; - -/** - * Returns the named user ID. - * - * Expected arguments: String - * - * @param command The cordova command. - */ -- (void)getNamedUser:(CDVInvokedUrlCommand *)command; - -/** - * Enables or disables quiet time. - * - * Expected arguments: Boolean - * - * @param command The cordova command. - */ -- (void)setQuietTimeEnabled:(CDVInvokedUrlCommand *)command; - -/** - * Checks if quiet time is currently enabled. - * - * @param command The cordova command. - */ -- (void)isQuietTimeEnabled:(CDVInvokedUrlCommand *)command; - -/** - * Sets the quiet time. - * - * Expected arguments: Number - start hour, Number - start minute, - * Number - end hour, Number - end minute - * - * @param command The cordova command. - */ -- (void)setQuietTime:(CDVInvokedUrlCommand *)command; - -/** - * Returns the quiet time as an object with the following: - * "startHour": Number, - * "startMinute": Number, - * "endHour": Number, - * "endMinute": Number - * - * @param command The cordova command. - */ -- (void)getQuietTime:(CDVInvokedUrlCommand *)command; - -/** - * Checks if the device is currently in quiet time. - * - * @param command The cordova command. - */ -- (void)isInQuietTime:(CDVInvokedUrlCommand *)command; - -/** - * Sets the user notification types. Defaults to all notification types. - * - * Expected arguments: Number - bitmask of the notification types - * - * @param command The cordova command. - */ -- (void)setNotificationTypes:(CDVInvokedUrlCommand *)command; - -/** - * Sets notification presentation options. - * - * Expected arguments: Number - bitmask of the notification options - * - * @param command The cordova command. - */ -- (void)setPresentationOptions:(CDVInvokedUrlCommand *)command; - -/** - * Enables or disables analytics. - * - * Disabling analytics will delete any locally stored events - * and prevent any events from uploading. Features that depend on analytics being - * enabled may not work properly if it's disabled (reports, region triggers, - * location segmentation, push to local time). - * - * Expected arguments: Boolean - * - * @param command The cordova command. - */ -- (void)setAnalyticsEnabled:(CDVInvokedUrlCommand *)command; - -/** - * Sets associated custom identifiers for use with the Connect data stream. - * - * Previous identifiers will be replaced by the new identifiers each time setAssociateIdentifier is called. It is a set operation. - * - * Expected arguments: An array of strings containing the identifier and key. - * - * @param command The cordova command. - */ -- (void)setAssociatedIdentifier:(CDVInvokedUrlCommand *)command; - -/** - * Checks if analytics is enabled or not. - * - * @param command The cordova command. - */ -- (void)isAnalyticsEnabled:(CDVInvokedUrlCommand *)command; - -/** - * Runs an Urban Airship action. - * - * Expected arguments: String - action name, * - the action value - * - * @param command The cordova command. - */ -- (void)runAction:(CDVInvokedUrlCommand *)command; - -/** - * Edits the named user tag groups. - * - * Expected arguments: An array of objects that contain: - * "operation": String, either "add" or "remove", - * "group": String, the tag group, - * "tags": Array of tags - * - * @param command The cordova command. - */ -- (void)editNamedUserTagGroups:(CDVInvokedUrlCommand *)command; - -/** - * Edits the channel tag groups. - * - * Expected arguments: An array of objects that contain: - * "operation": String, either "add" or "remove", - * "group": String, the tag group, - * "tags": Array of tags - * - * @param command The cordova command. - */ -- (void)editChannelTagGroups:(CDVInvokedUrlCommand *)command; - -/** - * Edits the channel attributes. - * - * Expected arguments: An array of objects that contain: - * "action": String, either `remove` or `set` - * "key": String, the attribute name. - * "value": String, the attribute value. - * - * @param command The cordova command. - */ -- (void)editChannelAttributes:(CDVInvokedUrlCommand *)command; - -/** - * Edits the named user attributes. - * - * Expected arguments: An array of objects that contain: - * "action": String, either `remove` or `set` - * "key": String, the attribute name. - * "value": String, the attribute value. - * - * @param command The cordova command. - */ -- (void)editNamedUserAttributes:(CDVInvokedUrlCommand *)command; - -/** - * Registers a listener for events. - * - * @param command The cordova command. - */ -- (void)registerListener:(CDVInvokedUrlCommand *)command; - -/** - * Display the given message without animation. - * - * @param command The cordova command. - */ -- (void)displayMessageCenter:(CDVInvokedUrlCommand *)command; - -/** - * Dismiss the message center. - * - * @param command The cordova command. - */ -- (void)dismissMessageCenter:(CDVInvokedUrlCommand *)command; - -/** - * Gets the inbox listing. - * - * @param command The cordova command. - */ -- (void)getInboxMessages:(CDVInvokedUrlCommand *)command; - -/** - * Marks an inbox message read. - * - * Expected arguments: String - message ID. - * - * @param command The cordova command. - */ -- (void)markInboxMessageRead:(CDVInvokedUrlCommand *)command; - -/** - * Deletes an inbox message. - * - * Expected arguments: String - message ID. - * - * @param command The cordova command. - */ -- (void)deleteInboxMessage:(CDVInvokedUrlCommand *)command; - -/** - * Displays an inbox message. - * - * Expected arguments: String - message ID. - * - * @param command The cordova command. - */ -- (void)displayInboxMessage:(CDVInvokedUrlCommand *)command; - -/** - * Dismiss an inbox message. - * - * @param command The cordova command. - */ -- (void)dismissInboxMessage:(CDVInvokedUrlCommand *)command; - -/** - * Refreshes the inbox. - * - * @param command The cordova command. - */ -- (void)refreshInbox:(CDVInvokedUrlCommand *)command; - -/** - * Checks if app notifications are enabled or not. - * - * @param command The cordova command. - */ -- (void)isAppNotificationsEnabled:(CDVInvokedUrlCommand *)command; - -/** - * Gets the currently active notifications. - * - * @param command The cordova command. - */ -- (void)getActiveNotifications:(CDVInvokedUrlCommand *)command; - -/** - * Clears notifications by identifier. - * - * Expected arguments: String - notification identifier. - * - * @param command The cordova command. - */ -- (void)clearNotification:(CDVInvokedUrlCommand *)command; - -/** - * Clears all notifications. - * - * @param command The cordova command. - */ -- (void)clearNotifications:(CDVInvokedUrlCommand *)command; - -/** - * Enables features, adding them to the set of currently enabled features. - * - * Expected arguments: NSArray - the features. - * - * @param command The cordova command. - */ -- (void)enableFeature:(CDVInvokedUrlCommand *)command; - -/** - * Disables features, removing them from the set of currently enabled features. - * - * Expected arguments: NSArray - the features. - * - * @param command The cordova command. - */ -- (void)disableFeature:(CDVInvokedUrlCommand *)command; - -/** - * Sets the current enabled features, replacing any currently enabled features with the given set. - * - * Expected arguments: NSArray - the features. - * - * @param command The cordova command. - */ -- (void)setEnabledFeatures:(CDVInvokedUrlCommand *)command; - -/** - * Gets the current enabled features. - * - * @param command The cordova command. - */ -- (void)getEnabledFeatures:(CDVInvokedUrlCommand *)command; - -/** - * Checks if all of the given features are enabled. - * - * Expected arguments: NSArray - the features. - * - * @param command The cordova command. - */ -- (void)isFeatureEnabled:(CDVInvokedUrlCommand *)command; - -/** - * Opens the Preference Center with the given preferenceCenterId. - * - * Expected arguments: String - the preference center id. - * - * @param command The cordova command. - */ -- (void)openPreferenceCenter:(CDVInvokedUrlCommand *)command; - - -/** - * Gets the configuration of the Preference Center with the given Id trough a callback method. - * - * Expected arguments: String - the preference center Id. - * - * @param command The cordova command. - */ -- (void)getPreferenceCenterConfig:(CDVInvokedUrlCommand *)command; - -/** - * Set to true of override the preference center UI - * - * Expected arguments: An array of objects that contain: - * "preferenceCenterId": the preference center Id. - * "userCustomUi": Boolean: true to use your custom preference center otherwise set to false. - * - * @param command The cordova command. - */ -- (void)setUseCustomPreferenceCenterUi:(CDVInvokedUrlCommand *)command; - -/** - * Edits channel subscription lists. - * - * Expected arguments: An array of objects that contain: - * "operation": String, either `subscribe` or `unsubscribe` - * "listId": String, the listID. - * - * @param command The cordova command. - */ -- (void)editChannelSubscriptionLists:(CDVInvokedUrlCommand *)command; - -/** - * Edits contact subscription lists. - * - * Expected arguments: An array of objects that contain: - * "operation": String, either `subscribe` or `unsubscribe` - * "listId": String, the listID. - * "scope": Defines the channel types that the change applies to - * - * @param command The cordova command. - */ -- (void)editContactSubscriptionLists:(CDVInvokedUrlCommand *)command; - -/** - * Returns the current set of subscription lists for the current channel, - * optionally applying pending subscription list changes that will be applied during the next channel update. - * - * @param command The cordova command. - */ -- (void)getChannelSubscriptionLists:(CDVInvokedUrlCommand *)command; - -/** - * Returns the current set of subscription lists for the current contact, - * optionally applying pending subscription list changes that will be applied during the next contact update. - * - * @param command The cordova command. - */ -- (void)getContactSubscriptionLists:(CDVInvokedUrlCommand *)command; - -/** - * Returns the locale currently used by Airship. - * @param command The cordova command. - */ -- (void)getCurrentLocale:(CDVInvokedUrlCommand *)command; - -/** - * Overrides the locale. - * @param command The cordova command. - */ -- (void)setCurrentLocale:(CDVInvokedUrlCommand *)command; - -/** - * Resets the current locale. - * - * @param command The cordova command. - */ -- (void)clearLocale:(CDVInvokedUrlCommand *)command ; - -@end diff --git a/urbanairship-cordova/src/ios/UAirshipPlugin.m b/urbanairship-cordova/src/ios/UAirshipPlugin.m deleted file mode 100644 index f1cff661..00000000 --- a/urbanairship-cordova/src/ios/UAirshipPlugin.m +++ /dev/null @@ -1,1214 +0,0 @@ -/* Copyright Urban Airship and Contributors */ - -#import "UAirshipPlugin.h" -#import "UACordovaPluginManager.h" -#import "UACordovaPushEvent.h" -#import "UAMessageViewController.h" - -#if __has_include("AirshipLib.h") -#import "AirshipLib.h" -#import "AirshipMessageCenterLib.h" -#import "AirshipAutomationLib.h" -#else -@import AirshipKit; -#endif - -NSString *const PreferenceCenterIdKey = @"id"; -NSString *const PreferenceCenterSectionsKey = @"sections"; -NSString *const PreferenceCenterDisplayKey = @"display"; -NSString *const PreferenceCenterDisplayNameKey = @"name"; -NSString *const PreferenceCenterDisplayDescriptionKey = @"description"; -NSString *const PreferenceCenterItemsKey = @"items"; -NSString *const PreferenceCenterSubscriptionIdKey = @"subscriptionId"; -NSString *const PreferenceCenterComponentsKey = @"components"; -NSString *const PreferenceCenterScopesKey = @"scopes"; -NSString *const PreferenceCenterScopeWebKey = @"web"; -NSString *const PreferenceCenterScopeEmailKey = @"email"; -NSString *const PreferenceCenterScopeAppKey = @"app"; -NSString *const PreferenceCenterScopeSmsKey = @"sms"; - -typedef void (^UACordovaCompletionHandler)(CDVCommandStatus, id); -typedef void (^UACordovaExecutionBlock)(NSArray *args, UACordovaCompletionHandler completionHandler); - -@interface UAirshipPlugin() -@property (nonatomic, copy) NSString *listenerCallbackID; -@property (nonatomic, weak) UAMessageViewController *messageViewController; -@property (nonatomic, strong) UACordovaPluginManager *pluginManager; -@property (nonatomic, weak) UAInAppMessageHTMLAdapter *htmlAdapter; -@property (nonatomic, assign) BOOL factoryBlockAssigned; -@end - -@implementation UAirshipPlugin - -- (void)pluginInitialize { - UA_LINFO(@"Initializing UrbanAirship cordova plugin."); - - if (!self.pluginManager) { - self.pluginManager = [UACordovaPluginManager pluginManagerWithDefaultConfig:self.commandDelegate.settings]; - } - - UA_LDEBUG(@"pluginIntialize called:plugin initializing and attempting takeOff with pluginManager:%@", self.pluginManager); - [self.pluginManager attemptTakeOff]; -} - -- (void)dealloc { - self.pluginManager.delegate = nil; - self.listenerCallbackID = nil; -} - -/** - * Helper method to create a plugin result with the specified value. - * - * @param value The result's value. - * @param status The result's status. - * @returns A CDVPluginResult with specified value. - */ -- (CDVPluginResult *)pluginResultForValue:(id)value status:(CDVCommandStatus)status { - /* - NSString -> String - NSNumber --> (Integer | Double) - NSArray --> Array - NSDictionary --> Object - NSNull --> no return value - nil -> no return value - */ - - // String - if ([value isKindOfClass:[NSString class]]) { - NSCharacterSet *characters = [NSCharacterSet URLHostAllowedCharacterSet]; - return [CDVPluginResult resultWithStatus:status - messageAsString:[value stringByAddingPercentEncodingWithAllowedCharacters:characters]]; - } - - // Number - if ([value isKindOfClass:[NSNumber class]]) { - CFNumberType numberType = CFNumberGetType((CFNumberRef)value); - //note: underlyingly, BOOL values are typedefed as char - if (numberType == kCFNumberIntType || numberType == kCFNumberCharType) { - return [CDVPluginResult resultWithStatus:status messageAsInt:[value intValue]]; - } else { - return [CDVPluginResult resultWithStatus:status messageAsDouble:[value doubleValue]]; - } - } - - // Array - if ([value isKindOfClass:[NSArray class]]) { - return [CDVPluginResult resultWithStatus:status messageAsArray:value]; - } - - // Object - if ([value isKindOfClass:[NSDictionary class]]) { - return [CDVPluginResult resultWithStatus:status messageAsDictionary:value]; - } - - // Null - if ([value isKindOfClass:[NSNull class]]) { - return [CDVPluginResult resultWithStatus:status]; - } - - // Nil - if (!value) { - return [CDVPluginResult resultWithStatus:status]; - } - - UA_LERR(@"Cordova callback block returned unrecognized type: %@", NSStringFromClass([value class])); - return [CDVPluginResult resultWithStatus:status]; -} - -/** - * Helper method to perform a cordova command. - * - * @param command The cordova command. - * @param block The UACordovaExecutionBlock to execute. - */ -- (void)performCallbackWithCommand:(CDVInvokedUrlCommand *)command withBlock:(UACordovaExecutionBlock)block { - [self performCallbackWithCommand:command airshipRequired:YES withBlock:block]; -} - -/** - * Helper method to perform a cordova command. - * - * @param command The cordova command. - * @param block The UACordovaExecutionBlock to execute. - */ -- (void)performCallbackWithCommand:(CDVInvokedUrlCommand *)command - airshipRequired:(BOOL)airshipRequired - withBlock:(UACordovaExecutionBlock)block { - - if (airshipRequired && !self.pluginManager.isAirshipReady) { - UA_LERR(@"Unable to run Urban Airship command. Takeoff not called."); - id result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"TakeOff not called."]; - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - return; - } - - UACordovaCompletionHandler completionHandler = ^(CDVCommandStatus status, id value) { - CDVPluginResult *result = [self pluginResultForValue:value status:status]; - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - }; - - if (!block) { - completionHandler(CDVCommandStatus_OK, nil); - } else { - block(command.arguments, completionHandler); - } -} - -#pragma mark Cordova bridge - -- (void)registerListener:(CDVInvokedUrlCommand *)command { - UA_LTRACE(@"registerListener called with command: %@ and callback ID:%@", command, command.callbackId); - - self.listenerCallbackID = command.callbackId; - - if (self.listenerCallbackID) { - self.pluginManager.delegate = self; - } -} - -- (void)takeOff:(CDVInvokedUrlCommand *)command { - UA_LTRACE(@"takeOff called with command arguments: %@", command.arguments); - - [self performCallbackWithCommand:command - airshipRequired:NO - withBlock:^(NSArray *args, UACordovaCompletionHandler completionHandler) { - UA_LDEBUG(@"Performing takeOff with args: %@", args); - - NSDictionary *config = [args objectAtIndex:0]; - if (!config[@"production"] || !config[@"development"]) { - completionHandler(CDVCommandStatus_ERROR, @"Invalid config"); - return; - } - - if (self.pluginManager.isAirshipReady) { - UA_LINFO(@"TakeOff already called. Config will be applied next app start."); - } - - NSDictionary *development = config[@"development"]; - [self.pluginManager setDevelopmentAppKey:development[@"appKey"] appSecret:development[@"appSecret"]]; - - NSDictionary *production = config[@"production"]; - [self.pluginManager setProductionAppKey:production[@"appKey"] appSecret:production[@"appSecret"]]; - - [self.pluginManager setCloudSite:config[@"site"]]; - [self.pluginManager setMessageCenterStyleFile:config[@"messageCenterStyleConfig"]]; - - if (!self.pluginManager.isAirshipReady) { - [self.pluginManager attemptTakeOff]; - if (!self.pluginManager.isAirshipReady) { - completionHandler(CDVCommandStatus_ERROR, @"Invalid config. Airship unable to takeOff."); - } - } - - completionHandler(CDVCommandStatus_OK, nil); - }]; -} - -- (void)setAutoLaunchDefaultMessageCenter:(CDVInvokedUrlCommand *)command { - UA_LTRACE(@"setAutoLaunchDefaultMessageCenter called with command arguments: %@", command.arguments); - - [self performCallbackWithCommand:command withBlock:^(NSArray *args, UACordovaCompletionHandler completionHandler) { - BOOL enabled = [[args objectAtIndex:0] boolValue]; - self.pluginManager.autoLaunchMessageCenter = enabled; - completionHandler(CDVCommandStatus_OK, nil); - }]; -} - -- (void)setNotificationTypes:(CDVInvokedUrlCommand *)command { - UA_LTRACE(@"setNotificationTypes called with command arguments: %@", command.arguments); - - [self performCallbackWithCommand:command withBlock:^(NSArray *args, UACordovaCompletionHandler completionHandler) { - UANotificationOptions types = [[args objectAtIndex:0] intValue]; - - UA_LDEBUG(@"Setting notification types: %ld", (long)types); - [UAirship push].notificationOptions = types; - [[UAirship push] updateRegistration]; - - completionHandler(CDVCommandStatus_OK, nil); - }]; -} - -- (void)setPresentationOptions:(CDVInvokedUrlCommand *)command { - UA_LTRACE(@"setPresentationOptions called with command arguments: %@", command.arguments); - - [self performCallbackWithCommand:command withBlock:^(NSArray *args, UACordovaCompletionHandler completionHandler) { - UNNotificationPresentationOptions options = [[args objectAtIndex:0] intValue]; - - UA_LDEBUG(@"Setting presentation options types: %ld", (long)options); - [self.pluginManager setPresentationOptions:(NSUInteger)options]; - completionHandler(CDVCommandStatus_OK, nil); - }]; -} - -- (void)setUserNotificationsEnabled:(CDVInvokedUrlCommand *)command { - UA_LTRACE(@"setUserNotificationsEnabled called with command arguments: %@", command.arguments); - - [self performCallbackWithCommand:command withBlock:^(NSArray *args, UACordovaCompletionHandler completionHandler) { - BOOL enabled = [[args objectAtIndex:0] boolValue]; - - UA_LTRACE(@"setUserNotificationsEnabled set to:%@", enabled ? @"true" : @"false"); - - [UAirship push].userPushNotificationsEnabled = enabled; - - //forces a reregistration - [[UAirship push] updateRegistration]; - - completionHandler(CDVCommandStatus_OK, nil); - }]; -} - -- (void)enableUserNotifications:(CDVInvokedUrlCommand *)command { - UA_LTRACE(@"enableUserNotifications called with command arguments: %@", command.arguments); - - [self performCallbackWithCommand:command withBlock:^(NSArray *args, UACordovaCompletionHandler completionHandler) { - [[UAirship push] enableUserPushNotifications:^(BOOL success) { - completionHandler(CDVCommandStatus_OK, [NSNumber numberWithBool:success]); - }]; - }]; -} - -- (void)setAssociatedIdentifier:(CDVInvokedUrlCommand *)command { - UA_LTRACE(@"setAssociatedIdentifier called with command arguments: %@", command.arguments); - - [self performCallbackWithCommand:command withBlock:^(NSArray *args, UACordovaCompletionHandler completionHandler) { - NSString *key = [args objectAtIndex:0]; - NSString *identifier = [args objectAtIndex:1]; - - UAAssociatedIdentifiers *identifiers = [UAirship.analytics currentAssociatedDeviceIdentifiers]; - [identifiers setIdentifier:identifier forKey:key]; - [UAirship.analytics associateDeviceIdentifiers:identifiers]; - - completionHandler(CDVCommandStatus_OK, nil); - }]; -} - -- (void)setAnalyticsEnabled:(CDVInvokedUrlCommand *)command { - UA_LTRACE(@"setAnalyticsEnabled called with command arguments: %@", command.arguments); - - [self performCallbackWithCommand:command withBlock:^(NSArray *args, UACordovaCompletionHandler completionHandler) { - NSNumber *value = [args objectAtIndex:0]; - BOOL enabled = [value boolValue]; - if (enabled) { - [[UAirship shared].privacyManager enableFeatures:UAFeaturesAnalytics]; - } else { - [[UAirship shared].privacyManager disableFeatures:UAFeaturesAnalytics]; - } - - completionHandler(CDVCommandStatus_OK, nil); - }]; -} - -- (void)isAnalyticsEnabled:(CDVInvokedUrlCommand *)command { - UA_LTRACE(@"isAnalyticsEnabled called with command arguments: %@", command.arguments); - - [self performCallbackWithCommand:command withBlock:^(NSArray *args, UACordovaCompletionHandler completionHandler) { - BOOL enabled = [[UAirship shared].privacyManager isEnabled:UAFeaturesAnalytics]; - - completionHandler(CDVCommandStatus_OK, [NSNumber numberWithBool:enabled]); - }]; -} - -- (void)isUserNotificationsEnabled:(CDVInvokedUrlCommand *)command { - UA_LTRACE(@"isUserNotificationsEnabled called with command arguments: %@", command.arguments); - - [self performCallbackWithCommand:command withBlock:^(NSArray *args, UACordovaCompletionHandler completionHandler) { - BOOL enabled = [UAirship push].userPushNotificationsEnabled; - completionHandler(CDVCommandStatus_OK, [NSNumber numberWithBool:enabled]); - }]; -} - -- (void)isQuietTimeEnabled:(CDVInvokedUrlCommand *)command { - UA_LTRACE(@"isQuietTimeEnabled called with command arguments: %@", command.arguments); - - [self performCallbackWithCommand:command withBlock:^(NSArray *args, UACordovaCompletionHandler completionHandler) { - BOOL enabled = [UAirship push].quietTimeEnabled; - completionHandler(CDVCommandStatus_OK, [NSNumber numberWithBool:enabled]); - }]; -} - -- (void)isInQuietTime:(CDVInvokedUrlCommand *)command { - UA_LTRACE(@"isInQuietTime called with command arguments: %@", command.arguments); - - [self performCallbackWithCommand:command withBlock:^(NSArray *args, UACordovaCompletionHandler completionHandler) { - BOOL inQuietTime; - NSDictionary *quietTimeDictionary = [UAirship push].quietTime; - if (quietTimeDictionary) { - NSString *start = [quietTimeDictionary valueForKey:@"start"]; - NSString *end = [quietTimeDictionary valueForKey:@"end"]; - - NSDateFormatter *df = [NSDateFormatter new]; - df.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"]; - df.dateFormat = @"HH:mm"; - - NSDate *startDate = [df dateFromString:start]; - NSDate *endDate = [df dateFromString:end]; - - NSDate *now = [NSDate date]; - - inQuietTime = ([now earlierDate:startDate] == startDate && [now earlierDate:endDate] == now); - } else { - inQuietTime = NO; - } - - completionHandler(CDVCommandStatus_OK, [NSNumber numberWithBool:inQuietTime]); - }]; -} - -- (void)getLaunchNotification:(CDVInvokedUrlCommand *)command { - UA_LTRACE(@"getLaunchNotification called with command arguments: %@", command.arguments); - - [self performCallbackWithCommand:command withBlock:^(NSArray *args, UACordovaCompletionHandler completionHandler) { - id event = self.pluginManager.lastReceivedNotificationResponse; - - if ([args firstObject]) { - self.pluginManager.lastReceivedNotificationResponse = nil; - } - - completionHandler(CDVCommandStatus_OK, event); - }]; -} - -- (void)getDeepLink:(CDVInvokedUrlCommand *)command { - UA_LTRACE(@"getDeepLink called with command arguments: %@", command.arguments); - - [self performCallbackWithCommand:command withBlock:^(NSArray *args, UACordovaCompletionHandler completionHandler) { - NSString *deepLink = self.pluginManager.lastReceivedDeepLink; - - if ([args firstObject]) { - self.pluginManager.lastReceivedDeepLink = nil; - } - - completionHandler(CDVCommandStatus_OK, deepLink); - }]; -} - -- (void)getChannelID:(CDVInvokedUrlCommand *)command { - UA_LTRACE(@"getChannelID called with command arguments: %@", command.arguments); - - [self performCallbackWithCommand:command withBlock:^(NSArray *args, UACordovaCompletionHandler completionHandler) { - completionHandler(CDVCommandStatus_OK, [UAirship channel].identifier ?: @""); - }]; -} - -- (void)getQuietTime:(CDVInvokedUrlCommand *)command { - UA_LTRACE(@"getQuietTime called with command arguments: %@", command.arguments); - - [self performCallbackWithCommand:command withBlock:^(NSArray *args, UACordovaCompletionHandler completionHandler) { - NSDictionary *quietTimeDictionary = [UAirship push].quietTime; - - if (quietTimeDictionary) { - - NSString *start = [quietTimeDictionary objectForKey:@"start"]; - NSString *end = [quietTimeDictionary objectForKey:@"end"]; - - NSDateFormatter *df = [NSDateFormatter new]; - df.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"]; - df.dateFormat = @"HH:mm"; - - NSDate *startDate = [df dateFromString:start]; - NSDate *endDate = [df dateFromString:end]; - - // these will be nil if the dateformatter can't make sense of either string - if (startDate && endDate) { - NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian]; - NSDateComponents *startComponents = [gregorian components:NSCalendarUnitHour|NSCalendarUnitMinute fromDate:startDate]; - NSDateComponents *endComponents = [gregorian components:NSCalendarUnitHour|NSCalendarUnitMinute fromDate:endDate]; - - completionHandler(CDVCommandStatus_OK, @{ @"startHour": @(startComponents.hour), - @"startMinute": @(startComponents.minute), - @"endHour": @(endComponents.hour), - @"endMinute": @(endComponents.minute) }); - - return; - } - } - - completionHandler(CDVCommandStatus_OK, @{ @"startHour": @(0), - @"startMinute": @(0), - @"endHour": @(0), - @"endMinute": @(0) }); - }]; -} - -- (void)getTags:(CDVInvokedUrlCommand *)command { - UA_LTRACE(@"getTags called with command arguments: %@", command.arguments); - - [self performCallbackWithCommand:command withBlock:^(NSArray *args, UACordovaCompletionHandler completionHandler) { - completionHandler(CDVCommandStatus_OK, [UAirship channel].tags ?: [NSArray array]); - }]; -} - -- (void)getBadgeNumber:(CDVInvokedUrlCommand *)command { - UA_LTRACE(@"getBadgeNumber called with command arguments: %@", command.arguments); - - [self performCallbackWithCommand:command withBlock:^(NSArray *args, UACordovaCompletionHandler completionHandler) { - completionHandler(CDVCommandStatus_OK, @([UIApplication sharedApplication].applicationIconBadgeNumber)); - }]; -} - -- (void)getNamedUser:(CDVInvokedUrlCommand *)command { - UA_LTRACE(@"getNamedUser called with command arguments: %@", command.arguments); - - [self performCallbackWithCommand:command withBlock:^(NSArray *args, UACordovaCompletionHandler completionHandler) { - completionHandler(CDVCommandStatus_OK, UAirship.contact.namedUserID ?: @""); - }]; -} - -- (void)setTags:(CDVInvokedUrlCommand *)command { - UA_LTRACE(@"setTags called with command arguments: %@", command.arguments); - - [self performCallbackWithCommand:command withBlock:^(NSArray *args, UACordovaCompletionHandler completionHandler) { - NSMutableArray *tags = [NSMutableArray arrayWithArray:[args objectAtIndex:0]]; - [UAirship channel].tags = tags; - [[UAirship channel] updateRegistration]; - completionHandler(CDVCommandStatus_OK, nil); - }]; -} - -- (void)setQuietTimeEnabled:(CDVInvokedUrlCommand *)command { - UA_LTRACE(@"setQuietTimeEnabled called with command arguments: %@", command.arguments); - - [self performCallbackWithCommand:command withBlock:^(NSArray *args, UACordovaCompletionHandler completionHandler) { - NSNumber *value = [args objectAtIndex:0]; - BOOL enabled = [value boolValue]; - [UAirship push].quietTimeEnabled = enabled; - [[UAirship push] updateRegistration]; - - completionHandler(CDVCommandStatus_OK, nil); - }]; -} - -- (void)setQuietTime:(CDVInvokedUrlCommand *)command { - UA_LTRACE(@"setQuietTime called with command arguments: %@", command.arguments); - - [self performCallbackWithCommand:command withBlock:^(NSArray *args, UACordovaCompletionHandler completionHandler) { - id startHr = [args objectAtIndex:0]; - id startMin = [args objectAtIndex:1]; - id endHr = [args objectAtIndex:2]; - id endMin = [args objectAtIndex:3]; - - [[UAirship push] setQuietTimeStartHour:[startHr integerValue] startMinute:[startMin integerValue] endHour:[endHr integerValue] endMinute:[endMin integerValue]]; - [[UAirship push] updateRegistration]; - - completionHandler(CDVCommandStatus_OK, nil); - }]; -} - -- (void)setAutobadgeEnabled:(CDVInvokedUrlCommand *)command { - UA_LTRACE(@"setAutobadgeEnabled called with command arguments: %@", command.arguments); - - [self performCallbackWithCommand:command withBlock:^(NSArray *args, UACordovaCompletionHandler completionHandler) { - NSNumber *number = [args objectAtIndex:0]; - BOOL enabled = [number boolValue]; - [UAirship push].autobadgeEnabled = enabled; - - completionHandler(CDVCommandStatus_OK, nil); - }]; -} - -- (void)setBadgeNumber:(CDVInvokedUrlCommand *)command { - UA_LTRACE(@"setBadgeNumber called with command arguments: %@", command.arguments); - - [self performCallbackWithCommand:command withBlock:^(NSArray *args, UACordovaCompletionHandler completionHandler) { - id number = [args objectAtIndex:0]; - NSInteger badgeNumber = [number intValue]; - [[UAirship push] setBadgeNumber:badgeNumber]; - - completionHandler(CDVCommandStatus_OK, nil); - }]; -} - -- (void)setNamedUser:(CDVInvokedUrlCommand *)command { - UA_LTRACE(@"setNamedUser called with command arguments: %@", command.arguments); - - [self performCallbackWithCommand:command withBlock:^(NSArray *args, UACordovaCompletionHandler completionHandler) { - NSString *namedUserID = nil; - if ([[args objectAtIndex:0] isKindOfClass:[NSString class]]) { - namedUserID = [args objectAtIndex:0]; - namedUserID = [namedUserID stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; - } - - if (namedUserID.length) { - [UAirship.contact identify:namedUserID]; - } else { - [UAirship.contact reset]; - } - completionHandler(CDVCommandStatus_OK, nil); - }]; -} - -- (void)editNamedUserTagGroups:(CDVInvokedUrlCommand *)command { - UA_LTRACE(@"editNamedUserTagGroups called with command arguments: %@", command.arguments); - - [self performCallbackWithCommand:command withBlock:^(NSArray *args, UACordovaCompletionHandler completionHandler) { - - [UAirship.contact editTagGroups:^(UATagGroupsEditor * editor) { - [self applyTagGroupEdits:[args objectAtIndex:0] editor:editor]; - }]; - - completionHandler(CDVCommandStatus_OK, nil); - }]; -} - -- (void)editChannelTagGroups:(CDVInvokedUrlCommand *)command { - UA_LTRACE(@"editChannelTagGroups called with command arguments: %@", command.arguments); - - [self performCallbackWithCommand:command withBlock:^(NSArray *args, UACordovaCompletionHandler completionHandler) { - - [UAirship.channel editTagGroups:^(UATagGroupsEditor * editor) { - [self applyTagGroupEdits:[args objectAtIndex:0] editor:editor]; - }]; - - completionHandler(CDVCommandStatus_OK, nil); - }]; -} - -- (void)applyTagGroupEdits:(NSDictionary *)edits editor:(UATagGroupsEditor *)editor { - for (NSDictionary *edit in edits) { - NSString *group = edit[@"group"]; - if ([edit[@"operation"] isEqualToString:@"add"]) { - [editor addTags:edit[@"tags"] group:group]; - } else if ([edit[@"operation"] isEqualToString:@"remove"]) { - [editor removeTags:edit[@"tags"] group:group]; - } - } -} - -- (void)applyAttributeEdits:(NSDictionary *)edits editor:(UAAttributesEditor *)editor { - for (NSDictionary *edit in edits) { - NSString *action = edit[@"action"]; - NSString *name = edit[@"key"]; - - if ([action isEqualToString:@"set"]) { - id value = edit[@"value"]; - NSString *valueType = edit[@"type"]; - if ([valueType isEqualToString:@"string"]) { - [editor setString:value attribute:name]; - } else if ([valueType isEqualToString:@"number"]) { - [editor setNumber:value attribute:name]; - } else if ([valueType isEqualToString:@"date"]) { - // JavaScript's date type doesn't pass through the JS to native bridge. Dates are instead serialized as milliseconds since epoch. - NSDate *date = [NSDate dateWithTimeIntervalSince1970:[(NSNumber *)value doubleValue] / 1000.0]; - [editor setDate:date attribute:name]; - - } else { - UA_LWARN(@"Unknown attribute type: %@", valueType); - } - } else if ([action isEqualToString:@"remove"]) { - [editor removeAttribute:name]; - } - } -} - -- (void)editChannelSubscriptionLists:(CDVInvokedUrlCommand *)command { - UA_LTRACE(@"editChannelSubscriptionLists called with command arguments: %@", command.arguments); - - [self performCallbackWithCommand:command withBlock:^(NSArray *args, UACordovaCompletionHandler completionHandler) { - [UAirship.channel editSubscriptionLists:^(UASubscriptionListEditor *editor) { - for (NSDictionary *edit in [args objectAtIndex:0]) { - NSString *listID = edit[@"listId"]; - NSString *operation = edit[@"operation"]; - - if ([operation isEqualToString:@"subscribe"]) { - [editor subscribe:listID]; - } else if ([operation isEqualToString:@"unsubscribe"]) { - [editor unsubscribe:listID]; - } - } - }]; - - completionHandler(CDVCommandStatus_OK, nil); - }]; -} - -- (void)editContactSubscriptionLists:(CDVInvokedUrlCommand *)command { - UA_LTRACE(@"editContactSubscriptionLists called with command arguments: %@", command.arguments); - - NSArray *allChannelScope = @[@"sms", @"email", @"app", @"web"]; - - [self performCallbackWithCommand:command withBlock:^(NSArray *args, UACordovaCompletionHandler completionHandler) { - [UAirship.contact editSubscriptionLists:^(UAScopedSubscriptionListEditor *editor) { - for (NSDictionary *edit in [args objectAtIndex:0]) { - NSString *listID = edit[@"listId"]; - NSString *scope = edit[@"scope"]; - NSString *operation = edit[@"operation"]; - - if ((listID != nil) & [allChannelScope containsObject:scope]) { - UAChannelScope channelScope = [self getScope:scope]; - if ([operation isEqualToString:@"subscribe"]) { - [editor subscribe:listID scope:channelScope]; - } else if ([operation isEqualToString:@"unsubscribe"]) { - [editor unsubscribe:listID scope:channelScope]; - } - } - } - }]; - - completionHandler(CDVCommandStatus_OK, nil); - }]; -} - -- (UAChannelScope)getScope:(NSString* )scope { - if ([scope isEqualToString:@"sms"]) { - return UAChannelScopeSms; - } else if ([scope isEqualToString:@"email"]) { - return UAChannelScopeEmail; - } else if ([scope isEqualToString:@"app"]) { - return UAChannelScopeApp; - } else { - return UAChannelScopeWeb; - } -} - -- (NSString *)getScopeString:(UAChannelScope )scope { - switch (scope) { - case UAChannelScopeSms: - return @"sms"; - case UAChannelScopeEmail: - return @"email"; - case UAChannelScopeApp: - return @"app"; - case UAChannelScopeWeb: - return @"web"; - } -} - -- (void)getChannelSubscriptionLists:(CDVInvokedUrlCommand *)command { - UA_LTRACE(@"getChannelSubscriptionLists called with command arguments: %@", command.arguments); - - [self performCallbackWithCommand:command withBlock:^(NSArray *args, UACordovaCompletionHandler completionHandler) { - - [[UAChannel shared] fetchSubscriptionListsWithCompletionHandler:^(NSArray * _Nullable channelSubscriptionLists, NSError * _Nullable error) { - if (error) { - completionHandler(CDVCommandStatus_ERROR, error); - } - if (!channelSubscriptionLists) { - completionHandler(CDVCommandStatus_ERROR, @"channel subscription list null"); - } - completionHandler(CDVCommandStatus_OK, channelSubscriptionLists); - }]; - - }]; -} - -- (void)getContactSubscriptionLists:(CDVInvokedUrlCommand *)command { - UA_LTRACE(@"getContactSubscriptionLists called with command arguments: %@", command.arguments); - - [self performCallbackWithCommand:command withBlock:^(NSArray *args, UACordovaCompletionHandler completionHandler) { - - [[UAContact shared] fetchSubscriptionListsWithCompletionHandler:^(NSDictionary * _Nullable contactSubscriptionLists, NSError * _Nullable error) { - if (error) { - completionHandler(CDVCommandStatus_ERROR, error); - } - if (!contactSubscriptionLists) { - completionHandler(CDVCommandStatus_ERROR, @"contact subscription list null"); - } - - NSMutableDictionary *contactSubscriptionListDict = [NSMutableDictionary dictionary]; - for (NSString* identifier in contactSubscriptionLists.allKeys) { - UAChannelScopes *scopes = contactSubscriptionLists[identifier]; - NSMutableArray *scopesArray = [NSMutableArray array]; - for (id scope in scopes.values) { - UAChannelScope channelScope = (UAChannelScope)[scope intValue]; - [scopesArray addObject:[self getScopeString:channelScope]]; - } - [contactSubscriptionListDict setValue:scopesArray forKey:identifier]; - } - completionHandler(CDVCommandStatus_OK, contactSubscriptionListDict); - }]; - - }]; -} - - -- (void)resetBadge:(CDVInvokedUrlCommand *)command { - UA_LTRACE(@"resetBadge called with command arguments: %@", command.arguments); - - [self performCallbackWithCommand:command withBlock:^(NSArray *args, UACordovaCompletionHandler completionHandler) { - [[UAirship push] resetBadge]; - [[UAirship push] updateRegistration]; - - completionHandler(CDVCommandStatus_OK, nil); - }]; -} - -- (void)trackScreen:(CDVInvokedUrlCommand *)command { - UA_LTRACE(@"trackScreen called with command arguments: %@", command.arguments); - - [self performCallbackWithCommand:command withBlock:^(NSArray *args, UACordovaCompletionHandler completionHandler) { - NSString *screen = [args objectAtIndex:0]; - - UA_LTRACE(@"trackScreen set to:%@", screen); - - [[UAirship analytics] trackScreen:screen]; - - completionHandler(CDVCommandStatus_OK, nil); - }]; -} -- (void)runAction:(CDVInvokedUrlCommand *)command { - UA_LTRACE(@"runAction called with command arguments: %@", command.arguments); - - [self performCallbackWithCommand:command withBlock:^(NSArray *args, UACordovaCompletionHandler completionHandler) { - NSString *actionName = [args firstObject]; - id actionValue = args.count >= 2 ? [args objectAtIndex:1] : nil; - - [UAActionRunner runActionWithName:actionName - value:actionValue - situation:UASituationManualInvocation - completionHandler:^(UAActionResult *actionResult) { - - if (actionResult.status == UAActionStatusCompleted) { - - /* - * We are wrapping the value in an object to be consistent - * with the Android implementation. - */ - - NSMutableDictionary *result = [NSMutableDictionary dictionary]; - [result setValue:actionResult.value forKey:@"value"]; - completionHandler(CDVCommandStatus_OK, result); - } else { - NSString *error = [self errorMessageForAction:actionName result:actionResult]; - completionHandler(CDVCommandStatus_ERROR, error); - } - }]; - - }]; -} - -- (void)isAppNotificationsEnabled:(CDVInvokedUrlCommand *)command { - UA_LTRACE(@"isAppNotificationsEnabled called with command arguments: %@", command.arguments); - - [self performCallbackWithCommand:command withBlock:^(NSArray *args, UACordovaCompletionHandler completionHandler) { - BOOL optedIn = [UAirship push].authorizedNotificationSettings != 0; - completionHandler(CDVCommandStatus_OK, [NSNumber numberWithBool:optedIn]); - }]; -} - -/** - * Helper method to create an error message from an action result. - * - * @param actionName The name of the action. - * @param actionResult The action result. - * @return An error message, or nil if no error was found. - */ -- (NSString *)errorMessageForAction:(NSString *)actionName result:(UAActionResult *)actionResult { - switch (actionResult.status) { - case UAActionStatusActionNotFound: - return [NSString stringWithFormat:@"Action %@ not found.", actionName]; - case UAActionStatusArgumentsRejected: - return [NSString stringWithFormat:@"Action %@ rejected its arguments.", actionName]; - case UAActionStatusError: - if (actionResult.error.localizedDescription) { - return actionResult.error.localizedDescription; - } - case UAActionStatusCompleted: - return nil; - } - - return [NSString stringWithFormat:@"Action %@ failed with unspecified error", actionName]; -} - - -- (void)displayMessageCenter:(CDVInvokedUrlCommand *)command { - UA_LTRACE(@"displayMessageCenter called with command arguments: %@", command.arguments); - - [self performCallbackWithCommand:command withBlock:^(NSArray *args, UACordovaCompletionHandler completionHandler) { - [[UAMessageCenter shared] display]; - completionHandler(CDVCommandStatus_OK, nil); - }]; -} - -- (void)dismissMessageCenter:(CDVInvokedUrlCommand *)command { - UA_LTRACE(@"dismissMessageCenter called with command arguments: %@", command.arguments); - - [self performCallbackWithCommand:command withBlock:^(NSArray *args, UACordovaCompletionHandler completionHandler) { - [[UAMessageCenter shared] dismiss]; - completionHandler(CDVCommandStatus_OK, nil); - }]; -} - -- (void)getInboxMessages:(CDVInvokedUrlCommand *)command { - UA_LTRACE(@"getInboxMessages called with command arguments: %@", command.arguments); - UA_LDEBUG(@"Getting messages"); - - [self performCallbackWithCommand:command withBlock:^(NSArray *args, UACordovaCompletionHandler completionHandler) { - NSMutableArray *messages = [NSMutableArray array]; - - for (UAInboxMessage *message in [UAMessageCenter shared].messageList.messages) { - - NSDictionary *icons = [message.rawMessageObject objectForKey:@"icons"]; - NSString *iconUrl = [icons objectForKey:@"list_icon"]; - NSNumber *sentDate = @([message.messageSent timeIntervalSince1970] * 1000); - - NSMutableDictionary *messageInfo = [NSMutableDictionary dictionary]; - [messageInfo setValue:message.title forKey:@"title"]; - [messageInfo setValue:message.messageID forKey:@"id"]; - [messageInfo setValue:sentDate forKey:@"sentDate"]; - [messageInfo setValue:iconUrl forKey:@"listIconUrl"]; - [messageInfo setValue:message.unread ? @NO : @YES forKey:@"isRead"]; - [messageInfo setValue:message.extra forKey:@"extras"]; - - [messages addObject:messageInfo]; - } - - completionHandler(CDVCommandStatus_OK, messages); - }]; -} - -- (void)markInboxMessageRead:(CDVInvokedUrlCommand *)command { - UA_LTRACE(@"markInboxMessageRead called with command arguments: %@", command.arguments); - - [self performCallbackWithCommand:command withBlock:^(NSArray *args, UACordovaCompletionHandler completionHandler) { - NSString *messageID = [command.arguments firstObject]; - UAInboxMessage *message = [[UAMessageCenter shared].messageList messageForID:messageID]; - - if (!message) { - NSString *error = [NSString stringWithFormat:@"Message not found: %@", messageID]; - completionHandler(CDVCommandStatus_ERROR, error); - return; - } - - [[UAMessageCenter shared].messageList markMessagesRead:@[message] completionHandler:nil]; - completionHandler(CDVCommandStatus_OK, nil); - }]; -} - -- (void)deleteInboxMessage:(CDVInvokedUrlCommand *)command { - UA_LTRACE(@"deleteInboxMessage called with command arguments: %@", command.arguments); - - [self performCallbackWithCommand:command withBlock:^(NSArray *args, UACordovaCompletionHandler completionHandler) { - NSString *messageID = [command.arguments firstObject]; - UAInboxMessage *message = [[UAMessageCenter shared].messageList messageForID:messageID]; - - if (!message) { - NSString *error = [NSString stringWithFormat:@"Message not found: %@", messageID]; - completionHandler(CDVCommandStatus_ERROR, error); - return; - } - - [[UAMessageCenter shared].messageList markMessagesDeleted:@[message] completionHandler:nil]; - completionHandler(CDVCommandStatus_OK, nil); - }]; -} - -- (void)displayInboxMessage:(CDVInvokedUrlCommand *)command { - UA_LTRACE(@"displayInboxMessage called with command arguments: %@", command.arguments); - - [self performCallbackWithCommand:command withBlock:^(NSArray *args, UACordovaCompletionHandler completionHandler) { - [self.messageViewController dismissViewControllerAnimated:YES completion:nil]; - - UAMessageViewController *mvc = [[UAMessageViewController alloc] init]; - mvc.modalTransitionStyle = UIModalTransitionStyleCrossDissolve; - mvc.modalPresentationStyle = UIModalPresentationFullScreen; - [[UIApplication sharedApplication].keyWindow.rootViewController presentViewController:mvc animated:YES completion:nil]; - - // Load the message - [mvc loadMessageForID:[command.arguments firstObject]]; - - // Store a weak reference to the MessageViewController so we can dismiss it later - self.messageViewController = mvc; - - completionHandler(CDVCommandStatus_OK, nil); - }]; -} - -- (void)dismissInboxMessage:(CDVInvokedUrlCommand *)command { - UA_LTRACE(@"dismissInboxMessage called with command arguments: %@", command.arguments); - - [self performCallbackWithCommand:command withBlock:^(NSArray *args, UACordovaCompletionHandler completionHandler) { - [self.messageViewController dismissViewControllerAnimated:YES completion:nil]; - self.messageViewController = nil; - completionHandler(CDVCommandStatus_OK, nil); - }]; -} - -- (void)refreshInbox:(CDVInvokedUrlCommand *)command { - UA_LTRACE(@"refreshInbox called with command arguments: %@", command.arguments); - - [self performCallbackWithCommand:command withBlock:^(NSArray *args, UACordovaCompletionHandler completionHandler) { - [[UAMessageCenter shared].messageList retrieveMessageListWithSuccessBlock:^{ - completionHandler(CDVCommandStatus_OK, nil); - } withFailureBlock:^{ - completionHandler(CDVCommandStatus_ERROR, @"Inbox failed to refresh"); - }]; - }]; -} - -- (void)getActiveNotifications:(CDVInvokedUrlCommand *)command { - UA_LTRACE(@"getActiveNotifications called with command arguments: %@", command.arguments); - - [self performCallbackWithCommand:command withBlock:^(NSArray *args, UACordovaCompletionHandler completionHandler) { - if (@available(iOS 10.0, *)) { - [[UNUserNotificationCenter currentNotificationCenter] getDeliveredNotificationsWithCompletionHandler:^(NSArray * _Nonnull notifications) { - - NSMutableArray *result = [NSMutableArray array]; - for(UNNotification *unnotification in notifications) { - UNNotificationContent *content = unnotification.request.content; - [result addObject:[UACordovaPushEvent pushEventDataFromNotificationContent:content.userInfo]]; - } - - completionHandler(CDVCommandStatus_OK, result); - }]; - } else { - completionHandler(CDVCommandStatus_ERROR, @"Only available on iOS 10+"); - } - }]; -} - -- (void)clearNotification:(CDVInvokedUrlCommand *)command { - UA_LTRACE(@"clearNotification called with command arguments: %@", command.arguments); - - [self performCallbackWithCommand:command withBlock:^(NSArray *args, UACordovaCompletionHandler completionHandler) { - if (@available(iOS 10.0, *)) { - NSString *identifier = command.arguments.firstObject; - - if (identifier) { - [[UNUserNotificationCenter currentNotificationCenter] removeDeliveredNotificationsWithIdentifiers:@[identifier]]; - } - - completionHandler(CDVCommandStatus_OK, nil); - } - }]; -} - -- (void)clearNotifications:(CDVInvokedUrlCommand *)command { - UA_LTRACE(@"clearNotifications called with command arguments: %@", command.arguments); - - [self performCallbackWithCommand:command withBlock:^(NSArray *args, UACordovaCompletionHandler completionHandler) { - if (@available(iOS 10.0, *)) { - [[UNUserNotificationCenter currentNotificationCenter] removeAllDeliveredNotifications]; - } - - completionHandler(CDVCommandStatus_OK, nil); - }]; -} - -- (void)editChannelAttributes:(CDVInvokedUrlCommand *)command { - UA_LTRACE(@"editChannelAttributes called with command arguments: %@", command.arguments); - - [self performCallbackWithCommand:command withBlock:^(NSArray *args, UACordovaCompletionHandler completionHandler) { - - [UAirship.channel editAttributes:^(UAAttributesEditor *editor) { - [self applyAttributeEdits:[args objectAtIndex:0] editor:editor]; - }]; - }]; -} - -- (void)editNamedUserAttributes:(CDVInvokedUrlCommand *)command { - UA_LTRACE(@"editNamedUserAttributes called with command arguments: %@", command.arguments); - - [self performCallbackWithCommand:command withBlock:^(NSArray *args, UACordovaCompletionHandler completionHandler) { - [UAirship.contact editAttributes:^(UAAttributesEditor *editor) { - [self applyAttributeEdits:[args objectAtIndex:0] editor:editor]; - }]; - }]; -} - - -- (BOOL)notifyListener:(NSString *)eventType data:(NSDictionary *)data { - UA_LTRACE(@"notifyListener called with event type:%@ and data:%@", eventType, data); - - if (!self.listenerCallbackID) { - UA_LTRACE(@"Listener callback unavailable, event %@", eventType); - return false; - } - - NSMutableDictionary *message = [NSMutableDictionary dictionary]; - [message setValue:eventType forKey:@"eventType"]; - [message setValue:data forKey:@"eventData"]; - - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:message]; - [result setKeepCallbackAsBool:YES]; - - [self.commandDelegate sendPluginResult:result callbackId:self.listenerCallbackID]; - - return true; -} - -- (void)enableFeature:(CDVInvokedUrlCommand *)command { - UA_LTRACE(@"enableFeature called with command arguments: %@", command.arguments); - - [self performCallbackWithCommand:command withBlock:^(NSArray *args, UACordovaCompletionHandler completionHandler) { - NSArray *features = [args firstObject]; - if ([self isValidFeature:features]) { - [[UAirship shared].privacyManager enableFeatures:[self stringToFeature:features]]; - completionHandler(CDVCommandStatus_OK, nil); - } else { - completionHandler(CDVCommandStatus_ERROR, @"Invalid feature, cancelling the action."); - } - }]; -} - -- (void)disableFeature:(CDVInvokedUrlCommand *)command { - UA_LTRACE(@"disableFeature called with command arguments: %@", command.arguments); - - [self performCallbackWithCommand:command withBlock:^(NSArray *args, UACordovaCompletionHandler completionHandler) { - NSArray *features = [args firstObject]; - if ([self isValidFeature:features]) { - [[UAirship shared].privacyManager disableFeatures:[self stringToFeature:features]]; - completionHandler(CDVCommandStatus_OK, nil); - } else { - completionHandler(CDVCommandStatus_ERROR, @"Invalid feature, cancelling the action."); - } - }]; -} - -- (void)setEnabledFeatures:(CDVInvokedUrlCommand *)command { - UA_LTRACE(@"setEnabledFeatures called with command arguments: %@", command.arguments); - - [self performCallbackWithCommand:command withBlock:^(NSArray *args, UACordovaCompletionHandler completionHandler) { - NSArray *features = [args firstObject]; - if ([self isValidFeature:features]) { - [UAirship shared].privacyManager.enabledFeatures = [self stringToFeature:features]; - completionHandler(CDVCommandStatus_OK, nil); - } else { - completionHandler(CDVCommandStatus_ERROR, @"Invalid feature, cancelling the action."); - } - }]; -} - -- (void)getEnabledFeatures:(CDVInvokedUrlCommand *)command { - UA_LTRACE(@"getEnabledFeatures called with command arguments: %@", command.arguments); - - [self performCallbackWithCommand:command withBlock:^(NSArray *args, UACordovaCompletionHandler completionHandler) { - completionHandler(CDVCommandStatus_OK, [self featureToString:[UAirship shared].privacyManager.enabledFeatures]); - }]; -} - -- (void)isFeatureEnabled:(CDVInvokedUrlCommand *)command { - UA_LTRACE(@"isFeatureEnabled called with command arguments: %@", command.arguments); - - [self performCallbackWithCommand:command withBlock:^(NSArray *args, UACordovaCompletionHandler completionHandler) { - NSArray *features = [args firstObject]; - if ([self isValidFeature:features]) { - completionHandler(CDVCommandStatus_OK, @([[UAirship shared].privacyManager isEnabled:[self stringToFeature:features]])); - } else { - completionHandler(CDVCommandStatus_ERROR, @"Invalid feature, cancelling the action."); - } - }]; -} - -- (void)openPreferenceCenter:(CDVInvokedUrlCommand *)command { - UA_LTRACE(@"openPreferenceCenter called with command arguments: %@", command.arguments); - - [self performCallbackWithCommand:command withBlock:^(NSArray *args, UACordovaCompletionHandler completionHandler) { - NSString *preferenceCenterID = [args firstObject]; - [[UAPreferenceCenter shared] openPreferenceCenter:preferenceCenterID]; - completionHandler(CDVCommandStatus_OK, nil); - }]; -} - -- (void)getPreferenceCenterConfig:(CDVInvokedUrlCommand *)command { - UA_LTRACE(@"getPreferenceCenterConfig called with command arguments: %@", command.arguments); - [self performCallbackWithCommand:command withBlock:^(NSArray *args, UACordovaCompletionHandler completionHandler) { - NSString *preferenceCenterID = [args firstObject]; - [[UAPreferenceCenter shared] jsonConfigForPreferenceCenterID:preferenceCenterID completionHandler:^(NSDictionary *config) { - completionHandler(CDVCommandStatus_OK, config); - }]; - }]; -} - -- (void)setUseCustomPreferenceCenterUi:(CDVInvokedUrlCommand *)command { - UA_LTRACE(@"setUseCustomPreferenceCenterUi called with command arguments: %@", command.arguments); - [self performCallbackWithCommand:command withBlock:^(NSArray *args, UACordovaCompletionHandler completionHandler) { - NSString *preferenceCenterID = [args firstObject]; - BOOL useCustomUI = [[args objectAtIndex:1] boolValue]; - [self.pluginManager setPreferenceCenter:preferenceCenterID useCustomUI:useCustomUI]; - completionHandler(CDVCommandStatus_OK, nil); - }]; -} - -- (void)getCurrentLocale:(CDVInvokedUrlCommand *)command { - UA_LTRACE(@"getCurrentLocale called with command arguments: %@", command.arguments); - [self performCallbackWithCommand:command withBlock:^(NSArray *args, UACordovaCompletionHandler completionHandler) { - NSLocale *airshipLocale = [[UAirship shared].localeManager currentLocale]; - completionHandler(CDVCommandStatus_OK, airshipLocale.localeIdentifier); - }]; -} - -- (void)setCurrentLocale:(CDVInvokedUrlCommand *)command { - UA_LTRACE(@"setCurrentLocale called with command arguments: %@", command.arguments); - [self performCallbackWithCommand:command withBlock:^(NSArray *args, UACordovaCompletionHandler completionHandler) { - NSString *localeIdentifier = [args firstObject]; - [UAirship.shared.localeManager setCurrentLocale:[NSLocale localeWithLocaleIdentifier:localeIdentifier]]; - completionHandler(CDVCommandStatus_OK, nil); - }]; -} - -- (void)clearLocale:(CDVInvokedUrlCommand *)command { - UA_LTRACE(@"clearLocale called with command arguments: %@", command.arguments); - [self performCallbackWithCommand:command withBlock:^(NSArray *args, UACordovaCompletionHandler completionHandler) { - [[UAirship shared].localeManager clearLocale]; - completionHandler(CDVCommandStatus_OK, nil); - }]; -} - -- (BOOL)isValidFeature:(NSArray *)features { - if (!features || [features count] == 0) { - return NO; - } - NSDictionary *authorizedFeatures = [self authorizedFeatures]; - - for (NSString *feature in features) { - if (![authorizedFeatures objectForKey:feature]) { - return NO; - } - } - return YES; -} - -- (UAFeatures)stringToFeature:(NSArray *)features { - NSDictionary *authorizedFeatures = [self authorizedFeatures]; - - NSNumber *objectFeature = authorizedFeatures[[features objectAtIndex:0]]; - UAFeatures convertedFeatures = [objectFeature longValue]; - - if ([features count] > 1) { - int i; - for (i = 1; i < [features count]; i++) { - NSNumber *objectFeature = authorizedFeatures[[features objectAtIndex:i]]; - convertedFeatures |= [objectFeature longValue]; - } - } - return convertedFeatures; -} - -- (NSArray *)featureToString:(UAFeatures)features { - NSMutableArray *convertedFeatures = [[NSMutableArray alloc] init]; - - NSDictionary *authorizedFeatures = [self authorizedFeatures]; - - if (features == UAFeaturesAll) { - [convertedFeatures addObject:@"FEATURE_ALL"]; - } else if (features == UAFeaturesNone) { - [convertedFeatures addObject:@"FEATURE_NONE"]; - } else { - for (NSString *feature in authorizedFeatures) { - NSNumber *objectFeature = authorizedFeatures[feature]; - long longFeature = [objectFeature longValue]; - if ((longFeature & features) && (longFeature != UAFeaturesAll)) { - [convertedFeatures addObject:feature]; - } - } - } - return convertedFeatures; -} - -- (NSDictionary *)authorizedFeatures { - NSMutableDictionary *authorizedFeatures = [[NSMutableDictionary alloc] init]; - [authorizedFeatures setValue:@(UAFeaturesNone) forKey:@"FEATURE_NONE"]; - [authorizedFeatures setValue:@(UAFeaturesInAppAutomation) forKey:@"FEATURE_IN_APP_AUTOMATION"]; - [authorizedFeatures setValue:@(UAFeaturesMessageCenter) forKey:@"FEATURE_MESSAGE_CENTER"]; - [authorizedFeatures setValue:@(UAFeaturesPush) forKey:@"FEATURE_PUSH"]; - [authorizedFeatures setValue:@(UAFeaturesChat) forKey:@"FEATURE_CHAT"]; - [authorizedFeatures setValue:@(UAFeaturesAnalytics) forKey:@"FEATURE_ANALYTICS"]; - [authorizedFeatures setValue:@(UAFeaturesTagsAndAttributes) forKey:@"FEATURE_TAGS_AND_ATTRIBUTES"]; - [authorizedFeatures setValue:@(UAFeaturesContacts) forKey:@"FEATURE_CONTACTS"]; - [authorizedFeatures setValue:@(UAFeaturesLocation) forKey:@"FEATURE_LOCATION"]; - [authorizedFeatures setValue:@(UAFeaturesAll) forKey:@"FEATURE_ALL"]; - return authorizedFeatures; -} - -@end - diff --git a/urbanairship-cordova/src/ios/events/UACordovaDeepLinkEvent.h b/urbanairship-cordova/src/ios/events/UACordovaDeepLinkEvent.h deleted file mode 100644 index 48699e9e..00000000 --- a/urbanairship-cordova/src/ios/events/UACordovaDeepLinkEvent.h +++ /dev/null @@ -1,37 +0,0 @@ -/* Copyright Urban Airship and Contributors */ - -#import "UACordovaEvent.h" - -NS_ASSUME_NONNULL_BEGIN - -extern NSString *const EventDeepLink; - -/** - * Deep link event when a new deep link is received. - */ -@interface UACordovaDeepLinkEvent : NSObject - -/** - * The event type. - * - * @return The event type. - */ -@property (nonatomic, strong, nullable) NSString *type; - -/** - * The event data. - * - * @return The event data. - */ -@property (nonatomic, strong, nullable) NSDictionary *data; - -/** - * Deep link event when a new deep link is received. - * - * @param deepLink The deep link url. - */ -+ (instancetype)eventWithDeepLink:(NSURL *)deepLink; - -@end - -NS_ASSUME_NONNULL_END diff --git a/urbanairship-cordova/src/ios/events/UACordovaDeepLinkEvent.m b/urbanairship-cordova/src/ios/events/UACordovaDeepLinkEvent.m deleted file mode 100644 index 60d7bffc..00000000 --- a/urbanairship-cordova/src/ios/events/UACordovaDeepLinkEvent.m +++ /dev/null @@ -1,23 +0,0 @@ -/* Copyright Urban Airship and Contributors */ - -#import "UACordovaDeepLinkEvent.h" - -NSString *const EventDeepLink = @"urbanairship.deep_link"; -NSString *const DeepLinkKey = @"deepLink"; - -@implementation UACordovaDeepLinkEvent - -+ (instancetype)eventWithDeepLink:(NSURL *)deepLink { - return [[UACordovaDeepLinkEvent alloc] initWithDeepLink:deepLink]; -} - -- (instancetype)initWithDeepLink:(NSURL *)deepLink { - self = [super init]; - if (self) { - self.data = @{DeepLinkKey:[deepLink absoluteString]}; - self.type = EventDeepLink; - } - return self; -} - -@end diff --git a/urbanairship-cordova/src/ios/events/UACordovaEvent.h b/urbanairship-cordova/src/ios/events/UACordovaEvent.h deleted file mode 100644 index 4727765b..00000000 --- a/urbanairship-cordova/src/ios/events/UACordovaEvent.h +++ /dev/null @@ -1,28 +0,0 @@ -/* Copyright Urban Airship and Contributors */ - -#import - -NS_ASSUME_NONNULL_BEGIN - -/** - * Interface for Urban Airship Cordova events. - */ -@protocol UACordovaEvent - -/** - * The event type. - * - * @return The event type. - */ -@property (nonatomic, strong, nullable) NSString *type; - -/** - * The event data. - * - * @return The event data. - */ -@property (nonatomic, strong, nullable) NSDictionary *data; - -@end - -NS_ASSUME_NONNULL_END diff --git a/urbanairship-cordova/src/ios/events/UACordovaInboxUpdatedEvent.h b/urbanairship-cordova/src/ios/events/UACordovaInboxUpdatedEvent.h deleted file mode 100644 index 55e32040..00000000 --- a/urbanairship-cordova/src/ios/events/UACordovaInboxUpdatedEvent.h +++ /dev/null @@ -1,38 +0,0 @@ -/* Copyright Urban Airship and Contributors */ - -#import "UACordovaEvent.h" - -NS_ASSUME_NONNULL_BEGIN - -extern NSString *const EventInboxUpdated; - -/** - * Inbox update event. - */ -@interface UACordovaInboxUpdatedEvent : NSObject - -/** - * The event type. - * - * @return The event type. - */ -@property (nonatomic, strong, nullable) NSString *type; - -/** - * The event data. - * - * @return The event data. - */ -@property (nonatomic, strong, nullable) NSDictionary *data; - -/** - * The default event. - * - * @return The default event. - */ -+ (instancetype)event; - - -@end - -NS_ASSUME_NONNULL_END diff --git a/urbanairship-cordova/src/ios/events/UACordovaInboxUpdatedEvent.m b/urbanairship-cordova/src/ios/events/UACordovaInboxUpdatedEvent.m deleted file mode 100644 index febcf801..00000000 --- a/urbanairship-cordova/src/ios/events/UACordovaInboxUpdatedEvent.m +++ /dev/null @@ -1,22 +0,0 @@ -/* Copyright Urban Airship and Contributors */ - -#import "UACordovaInboxUpdatedEvent.h" - -NSString *const EventInboxUpdated = @"urbanairship.inbox_updated"; - -@implementation UACordovaInboxUpdatedEvent - -+ (instancetype)event { - return [[UACordovaInboxUpdatedEvent alloc] init]; -} - -- (instancetype)init { - self = [super init]; - if (self) { - self.data = nil; - self.type = EventInboxUpdated; - } - return self; -} - -@end diff --git a/urbanairship-cordova/src/ios/events/UACordovaNotificationOpenedEvent.h b/urbanairship-cordova/src/ios/events/UACordovaNotificationOpenedEvent.h deleted file mode 100644 index 84f8918b..00000000 --- a/urbanairship-cordova/src/ios/events/UACordovaNotificationOpenedEvent.h +++ /dev/null @@ -1,23 +0,0 @@ -/* Copyright Urban Airship and Contributors */ - -#import "UACordovaPushEvent.h" - -NS_ASSUME_NONNULL_BEGIN - -extern NSString *const EventNotificationOpened; - -/** - * Notification opened event. - */ -@interface UACordovaNotificationOpenedEvent : UACordovaPushEvent - -/** - * Notification opened event with notification response. - * - * @param content The notification response. -*/ -+ (instancetype)eventWithNotificationResponse:(UNNotificationResponse *)response; - -@end - -NS_ASSUME_NONNULL_END diff --git a/urbanairship-cordova/src/ios/events/UACordovaNotificationOpenedEvent.m b/urbanairship-cordova/src/ios/events/UACordovaNotificationOpenedEvent.m deleted file mode 100644 index 89b9cbcd..00000000 --- a/urbanairship-cordova/src/ios/events/UACordovaNotificationOpenedEvent.m +++ /dev/null @@ -1,80 +0,0 @@ -/* Copyright Urban Airship and Contributors */ - -#if __has_include("AirshipLib.h") -#import "AirshipLib.h" -#else -@import AirshipKit; -#endif - -#import "UACordovaNotificationOpenedEvent.h" - -NSString *const EventNotificationOpened = @"urbanairship.notification_opened"; - -@implementation UACordovaNotificationOpenedEvent - -- (instancetype)initWithNotificationResponse:(UNNotificationResponse *)response { - self = [super init]; - - if (self) { - self.type = EventNotificationOpened; - - NSDictionary *pushEvent = [[self class] pushEventDataFromNotificationContent:response.notification.request.content.userInfo]; - NSMutableDictionary *data = [NSMutableDictionary dictionaryWithDictionary:pushEvent]; - - if ([response.actionIdentifier isEqualToString:UNNotificationDefaultActionIdentifier]) { - [data setValue:@(YES) forKey:@"isForeground"]; - } else { - UNNotificationAction *notificationAction = [self notificationActionForCategory:response.notification.request.content.categoryIdentifier - actionIdentifier:response.actionIdentifier]; - - BOOL isForeground = notificationAction.options & UNNotificationActionOptionForeground; - [data setValue:@(isForeground) forKey:@"isForeground"]; - [data setValue:response.actionIdentifier forKey:@"actionID"]; - } - - self.data = data; - } - - return self; -} - -+ (instancetype)eventWithNotificationResponse:(UNNotificationResponse *)response { - return [[self alloc] initWithNotificationResponse:response]; -} - -- (UNNotificationAction *)notificationActionForCategory:(NSString *)category actionIdentifier:(NSString *)identifier { - NSSet *categories = [UAirship push].combinedCategories; - - UNNotificationCategory *notificationCategory; - UNNotificationAction *notificationAction; - - for (UNNotificationCategory *possibleCategory in categories) { - if ([possibleCategory.identifier isEqualToString:category]) { - notificationCategory = possibleCategory; - break; - } - } - - if (!notificationCategory) { - UA_LERR(@"Unknown notification category identifier %@", category); - return nil; - } - - NSMutableArray *possibleActions = [NSMutableArray arrayWithArray:notificationCategory.actions]; - - for (UNNotificationAction *possibleAction in possibleActions) { - if ([possibleAction.identifier isEqualToString:identifier]) { - notificationAction = possibleAction; - break; - } - } - - if (!notificationAction) { - UA_LERR(@"Unknown notification action identifier %@", identifier); - return nil; - } - - return notificationAction; -} - -@end diff --git a/urbanairship-cordova/src/ios/events/UACordovaNotificationOptInEvent.h b/urbanairship-cordova/src/ios/events/UACordovaNotificationOptInEvent.h deleted file mode 100644 index 42b212ed..00000000 --- a/urbanairship-cordova/src/ios/events/UACordovaNotificationOptInEvent.h +++ /dev/null @@ -1,44 +0,0 @@ -/* Copyright Urban Airship and Contributors */ - -#if __has_include("AirshipLib.h") -#import "AirshipLib.h" -#else -@import AirshipKit; -#endif - -#import "UACordovaEvent.h" - -NS_ASSUME_NONNULL_BEGIN - -extern NSString *const EventNotificationOptInStatus; - -/** - * Notification opt-in status event. - */ -@interface UACordovaNotificationOptInEvent : NSObject - -/** - * The event type. - * - * @return The event type. - */ -@property (nonatomic, strong, nullable) NSString *type; - -/** - * The event data. - * - * @return The event data. - */ -@property (nonatomic, strong, nullable) NSDictionary *data; - -/** - * The opt-in event constructor. - * - * @param authorizedSettings The authorized notification settings - * @return The event opt-in event. - */ -+ (instancetype)eventWithAuthorizedSettings:(UAAuthorizedNotificationSettings)authorizedSettings; - -@end - -NS_ASSUME_NONNULL_END diff --git a/urbanairship-cordova/src/ios/events/UACordovaNotificationOptInEvent.m b/urbanairship-cordova/src/ios/events/UACordovaNotificationOptInEvent.m deleted file mode 100644 index 02a49984..00000000 --- a/urbanairship-cordova/src/ios/events/UACordovaNotificationOptInEvent.m +++ /dev/null @@ -1,80 +0,0 @@ -/* Copyright Urban Airship and Contributors */ - -#import "UACordovaNotificationOptInEvent.h" - -NSString *const EventNotificationOptInStatus = @"urbanairship.notification_opt_in_status"; - -NSString *const UACordovaNotificationOptInEventAlertKey = @"alert"; -NSString *const UACordovaNotificationOptInEventBadgeKey = @"badge"; -NSString *const UACordovaNotificationOptInEventSoundKey = @"sound"; -NSString *const UACordovaNotificationOptInEventCarPlayKey = @"carPlay"; -NSString *const UACordovaNotificationOptInEventLockScreenKey = @"lockScreen"; -NSString *const UACordovaNotificationOptInEventNotificationCenterKey = @"notificationCenter"; - -@implementation UACordovaNotificationOptInEvent - -+ (instancetype)eventWithAuthorizedSettings:(UAAuthorizedNotificationSettings)authorizedSettings { - return [[UACordovaNotificationOptInEvent alloc] initWithAuthorizedSettings:authorizedSettings]; -} - -- (instancetype)initWithAuthorizedSettings:(UAAuthorizedNotificationSettings)authorizedSettings { - self = [super init]; - - if (self) { - self.type = EventNotificationOptInStatus; - self.data = [self eventDataForAuthorizedSettings:authorizedSettings]; - } - - return self; -} - -- (NSDictionary *)eventDataForAuthorizedSettings:(UAAuthorizedNotificationSettings)authorizedSettings { - BOOL optedIn = NO; - - BOOL alertBool = NO; - BOOL badgeBool = NO; - BOOL soundBool = NO; - BOOL carPlayBool = NO; - BOOL lockScreenBool = NO; - BOOL notificationCenterBool = NO; - - if (authorizedSettings & UAAuthorizedNotificationSettingsAlert) { - alertBool = YES; - } - - if (authorizedSettings & UAAuthorizedNotificationSettingsBadge) { - badgeBool = YES; - } - - if (authorizedSettings & UAAuthorizedNotificationSettingsSound) { - soundBool = YES; - } - - if (authorizedSettings & UAAuthorizedNotificationSettingsCarPlay) { - carPlayBool = YES; - } - - if (authorizedSettings & UAAuthorizedNotificationSettingsLockScreen) { - lockScreenBool = YES; - } - - if (authorizedSettings & UAAuthorizedNotificationSettingsNotificationCenter) { - notificationCenterBool = YES; - } - - optedIn = authorizedSettings != UAAuthorizedNotificationSettingsNone; - - NSDictionary *eventBody = @{ @"optIn": @(optedIn), - @"authorizedNotificationSettings" : @{ - UACordovaNotificationOptInEventAlertKey : @(alertBool), - UACordovaNotificationOptInEventBadgeKey : @(badgeBool), - UACordovaNotificationOptInEventSoundKey : @(soundBool), - UACordovaNotificationOptInEventCarPlayKey : @(carPlayBool), - UACordovaNotificationOptInEventLockScreenKey : @(lockScreenBool), - UACordovaNotificationOptInEventNotificationCenterKey : @(notificationCenterBool) - }}; - - return eventBody; -} - -@end diff --git a/urbanairship-cordova/src/ios/events/UACordovaPreferenceCenterEvent.h b/urbanairship-cordova/src/ios/events/UACordovaPreferenceCenterEvent.h deleted file mode 100644 index 61273b3a..00000000 --- a/urbanairship-cordova/src/ios/events/UACordovaPreferenceCenterEvent.h +++ /dev/null @@ -1,38 +0,0 @@ - /* Copyright Urban Airship and Contributors */ - - #import "UACordovaEvent.h" - - NS_ASSUME_NONNULL_BEGIN - - extern NSString *const PreferenceCenterLink; - - /** - * Preference Center event when the open preference center listener is called. - */ - @interface UACordovaPreferenceCenterEvent : NSObject - - /** - * The event type. - * - * @return The event type. - */ - @property (nonatomic, strong, nullable) NSString *type; - - /** - * The event data. - * - * @return The event data. - */ - @property (nonatomic, strong, nullable) NSDictionary *data; - - /** - * Preference Center event when the open preference center listener is called. - * - * @param preferenceCenterId The preference center Id. - */ - + (instancetype)eventWithPreferenceCenterId:(NSString *)preferenceCenterId; - - @end - - NS_ASSUME_NONNULL_END - diff --git a/urbanairship-cordova/src/ios/events/UACordovaPreferenceCenterEvent.m b/urbanairship-cordova/src/ios/events/UACordovaPreferenceCenterEvent.m deleted file mode 100644 index 44fdffa1..00000000 --- a/urbanairship-cordova/src/ios/events/UACordovaPreferenceCenterEvent.m +++ /dev/null @@ -1,23 +0,0 @@ -/* Copyright Urban Airship and Contributors */ - -#import "UACordovaPreferenceCenterEvent.h" - -NSString *const PreferenceCenterLink = @"urbanairship.open_preference_center"; -NSString *const PreferenceCenterKey = @"prefrenceCenter"; - -@implementation UACordovaPreferenceCenterEvent - -+ (instancetype)eventWithPreferenceCenterId:(NSString *)preferenceCenterId { - return [[UACordovaPreferenceCenterEvent alloc] initWithPreferenceCenterId:preferenceCenterId]; -} - -- (instancetype)initWithPreferenceCenterId:(NSString *)preferenceCenterId { - self = [super init]; - if (self) { - self.data = @{PreferenceCenterKey:preferenceCenterId}; - self.type = PreferenceCenterLink; - } - return self; -} - -@end \ No newline at end of file diff --git a/urbanairship-cordova/src/ios/events/UACordovaPushEvent.h b/urbanairship-cordova/src/ios/events/UACordovaPushEvent.h deleted file mode 100644 index e7b2bbf9..00000000 --- a/urbanairship-cordova/src/ios/events/UACordovaPushEvent.h +++ /dev/null @@ -1,51 +0,0 @@ -/* Copyright Urban Airship and Contributors */ - -#if __has_include("AirshipLib.h") -#import "AirshipLib.h" -#else -@import AirshipKit; -#endif - -#import "UACordovaEvent.h" - -NS_ASSUME_NONNULL_BEGIN - -extern NSString *const EventPushReceived; - -/** - * Push event. - */ -@interface UACordovaPushEvent : NSObject - -/** - * The event type. - * - * @return The event type. - */ -@property (nonatomic, strong, nullable) NSString *type; - -/** - * The event data. - * - * @return The event data. - */ -@property (nonatomic, strong, nullable) NSDictionary *data; - -/** - * Push event with notification content. - * - * @param userInfo The notification content. - */ -+ (instancetype)eventWithNotificationContent:(NSDictionary *)userInfo; - -/** - * Helper method for producing sanitized push payloads from notification content. - * - * @param userInfo The notification content. - * @return A push payload dictionary. - */ -+ (NSDictionary *)pushEventDataFromNotificationContent:(NSDictionary *)userInfo; - -@end - -NS_ASSUME_NONNULL_END diff --git a/urbanairship-cordova/src/ios/events/UACordovaPushEvent.m b/urbanairship-cordova/src/ios/events/UACordovaPushEvent.m deleted file mode 100644 index ddc5f21e..00000000 --- a/urbanairship-cordova/src/ios/events/UACordovaPushEvent.m +++ /dev/null @@ -1,87 +0,0 @@ -/* Copyright Urban Airship and Contributors */ - -#import "UACordovaPushEvent.h" - -NSString *const EventPushReceived = @"urbanairship.push"; - -@implementation UACordovaPushEvent - -+ (instancetype)eventWithNotificationContent:(NSDictionary *)userInfo { - return [[self alloc] initWithNotificationContent:userInfo]; -} - -- (instancetype)initWithNotificationContent:(NSDictionary *)userInfo { - self = [super init]; - - if (self) { - self.type = EventPushReceived; - self.data = [[self class] pushEventDataFromNotificationContent:userInfo]; - } - - return self; -} - -+ (NSDictionary *)pushEventDataFromNotificationContent:(NSDictionary *)userInfo { - if (!userInfo) { - return @{ @"message": @"", @"extras": @{}}; - } - - NSMutableDictionary *info = [NSMutableDictionary dictionaryWithDictionary:userInfo]; - - // remove the send ID - if([[info allKeys] containsObject:@"_"]) { - [info removeObjectForKey:@"_"]; - } - - NSMutableDictionary *result = [NSMutableDictionary dictionary];; - - // If there is an aps dictionary in the extras, remove it and set it as a top level object - if([[info allKeys] containsObject:@"aps"]) { - NSDictionary* aps = info[@"aps"]; - - if ([[aps allKeys] containsObject:@"alert"]) { - - id alert = aps[@"alert"]; - if ([alert isKindOfClass:[NSDictionary class]]) { - if ([[alert allKeys] containsObject:@"body"]) { - result[@"message"] = alert[@"body"]; - } else { - result[@"message"] = @""; - } - if ([[alert allKeys] containsObject:@"title"]) { - [result setValue:alert[@"title"] forKey:@"title"]; - } - if ([[alert allKeys] containsObject:@"subtitle"]) { - [result setValue:alert[@"subtitle"] forKey:@"subtitle"]; - } - } else { - [result setValue:alert forKey:@"message"]; - } - - } - result[@"aps"] = info[@"aps"]; - [info removeObjectForKey:@"aps"]; - } - - NSMutableDictionary *actions = [NSMutableDictionary dictionary]; - for (id key in info.allKeys) { - if (![key isKindOfClass:[NSString class]]) { - continue; - } - - if ([UAirship.shared.actionRegistry registryEntryWithName:key]) { - actions[key] = info[key]; - } - } - - result[@"actions"] = actions; - - // Set the remaining info as extras - result[@"extras"] = info; - - - - return result; -} - -@end diff --git a/urbanairship-cordova/src/ios/events/UACordovaRegistrationEvent.h b/urbanairship-cordova/src/ios/events/UACordovaRegistrationEvent.h deleted file mode 100644 index dce57979..00000000 --- a/urbanairship-cordova/src/ios/events/UACordovaRegistrationEvent.h +++ /dev/null @@ -1,46 +0,0 @@ -/* Copyright Urban Airship and Contributors */ - -#import "UACordovaEvent.h" - -NS_ASSUME_NONNULL_BEGIN - -extern NSString *const EventRegistration; - -/** - * Registration event. - */ -@interface UACordovaRegistrationEvent : NSObject - -/** - * The event type. - * - * @return The event type. - */ -@property (nonatomic, strong, nullable) NSString *type; - -/** - * The event data. - * - * @return The event data. - */ -@property (nonatomic, strong, nullable) NSDictionary *data; - -/** - * The registration succeeded event constructor. - * - * @param channelID The channel ID. - * @param deviceToken The device token. - * @return registration event. - */ -+ (instancetype)registrationSucceededEventWithChannelID:channelID deviceToken:(NSString *)deviceToken; - -/** - * The registration failed event constructor. - * - * @return registration event. -*/ -+ (instancetype)registrationFailedEvent; - -@end - -NS_ASSUME_NONNULL_END diff --git a/urbanairship-cordova/src/ios/events/UACordovaRegistrationEvent.m b/urbanairship-cordova/src/ios/events/UACordovaRegistrationEvent.m deleted file mode 100644 index c982e841..00000000 --- a/urbanairship-cordova/src/ios/events/UACordovaRegistrationEvent.m +++ /dev/null @@ -1,42 +0,0 @@ -/* Copyright Urban Airship and Contributors */ - -#import "UACordovaRegistrationEvent.h" - -NSString *const EventRegistration = @"urbanairship.registration"; - -@implementation UACordovaRegistrationEvent - -+ (instancetype)registrationSucceededEventWithChannelID:channelID deviceToken:(NSString *)deviceToken { - return [[self alloc] initWithData:[self registrationSucceededData:channelID deviceToken:deviceToken]]; -} - -+ (instancetype)registrationFailedEvent { - return [[self alloc] initWithData:[self registrationFailedData]]; -} - -- (instancetype)initWithData:(NSDictionary *)data { - self = [super init]; - if (self) { - self.type = EventRegistration; - self.data = data; - } - return self; -} - -+ (NSDictionary *)registrationSucceededData:(NSString *)channelID deviceToken:(NSString *)deviceToken { - NSDictionary *data; - - if (deviceToken) { - data = @{ @"channelID":channelID, @"deviceToken":deviceToken, @"registrationToken":deviceToken }; - } else { - data = @{ @"channelID":channelID }; - } - - return data; -} - -+ (NSDictionary *)registrationFailedData { - return @{ @"error": @"Registration failed." }; -} - -@end diff --git a/urbanairship-cordova/src/ios/events/UACordovaShowInboxEvent.h b/urbanairship-cordova/src/ios/events/UACordovaShowInboxEvent.h deleted file mode 100644 index 4e3eb923..00000000 --- a/urbanairship-cordova/src/ios/events/UACordovaShowInboxEvent.h +++ /dev/null @@ -1,44 +0,0 @@ -/* Copyright Urban Airship and Contributors */ - -#import "UACordovaEvent.h" - -NS_ASSUME_NONNULL_BEGIN - -extern NSString *const EventShowInbox; - -/** - * Show inbox event. - */ -@interface UACordovaShowInboxEvent : NSObject - -/** - * The event type. - * - * @return The event type. - */ -@property (nonatomic, strong, nullable) NSString *type; - -/** - * The event data. - * - * @return The event data. - */ -@property (nonatomic, strong, nullable) NSDictionary *data; - -/** - * Show default inbox event - * - * @return The default inbox event. - */ -+ (instancetype)event; - -/** - * Show inbox event with message id. - * - * @return The inbox event with message identifier data. - */ -+ (instancetype)eventWithMessageID:(NSString *)identifier; - -@end - -NS_ASSUME_NONNULL_END diff --git a/urbanairship-cordova/src/ios/events/UACordovaShowInboxEvent.m b/urbanairship-cordova/src/ios/events/UACordovaShowInboxEvent.m deleted file mode 100644 index ebdb72a8..00000000 --- a/urbanairship-cordova/src/ios/events/UACordovaShowInboxEvent.m +++ /dev/null @@ -1,36 +0,0 @@ -/* Copyright Urban Airship and Contributors */ - -#import "UACordovaShowInboxEvent.h" - -NSString *const EventShowInbox = @"urbanairship.show_inbox"; - -@implementation UACordovaShowInboxEvent - -+ (instancetype)event { - return [[UACordovaShowInboxEvent alloc] initWithMessageID:nil]; -} - -+ (instancetype)eventWithMessageID:(NSString *)identifier { - return [[UACordovaShowInboxEvent alloc] initWithMessageID:identifier]; -} - -- (instancetype)init { - self = [super init]; - if (self) { - self.type = EventShowInbox; - self.data = nil; - } - return self; -} - -- (instancetype)initWithMessageID:(nullable NSString *)identifier { - self = [super init]; - if (self) { - self.type = EventShowInbox; - self.data = identifier ? @{@"messageId":identifier} : @{}; - } - - return self; -} - -@end diff --git a/urbanairship-cordova/www/UrbanAirship.js b/urbanairship-cordova/www/UrbanAirship.js deleted file mode 100644 index f36b495b..00000000 --- a/urbanairship-cordova/www/UrbanAirship.js +++ /dev/null @@ -1,1406 +0,0 @@ -/* Copyright Urban Airship and Contributors */ - -var cordova = require("cordova"), - exec = require("cordova/exec"), - argscheck = require('cordova/argscheck') - -// Argcheck values: -// * : allow anything, -// f : function -// a : array -// d : date -// n : number -// s : string -// o : object -// lowercase = required, uppercase = optional - -// Helper method to call into the native plugin -function callNative(success, failure, name, args) { - args = args || [] - exec(success, failure, "UAirship", name, args) -} - -// Helper method to run an action -function _runAction(actionName, actionValue, success, failure) { - var successWrapper = function(result) { - if (success) { - success(result.value) - } - } - - callNative(successWrapper, failure, "runAction", [actionName, actionValue]) -} - -/** - * Constant for Feature NONE. - */ -const FEATURE_NONE = "FEATURE_NONE" -/** - * Constant for InApp Automation Feature. - */ -const FEATURE_IN_APP_AUTOMATION = "FEATURE_IN_APP_AUTOMATION" -/** - * Constant for Message Center Feature. - */ -const FEATURE_MESSAGE_CENTER = "FEATURE_MESSAGE_CENTER" -/** - * Constant for Push Feature. - */ -const FEATURE_PUSH = "FEATURE_PUSH" -/** - * Constant for Chat Feature. - */ -const FEATURE_CHAT = "FEATURE_CHAT" -/** - * Constant for Analytics Feature. - */ -const FEATURE_ANALYTICS = "FEATURE_ANALYTICS" -/** - * Constant for Tags and Attributes Feature. - */ -const FEATURE_TAGS_AND_ATTRIBUTES = "FEATURE_TAGS_AND_ATTRIBUTES" -/** - * Constant for Contacts Feature. - */ -const FEATURE_CONTACTS = "FEATURE_CONTACTS" -/** - * Constant for Location Feature. - */ -const FEATURE_LOCATION = "FEATURE_LOCATION" -/** - * Constant for all Feature. - */ -const FEATURE_ALL = "FEATURE_ALL" - -/** - * Helper object to edit tag groups. - * - * Normally not created directly. Instead use [UrbanAirship.editNamedUserTagGroups]{@link module:UrbanAirship.editNamedUserTagGroups} - * or [UrbanAirship.editChannelTagGroups]{@link module:UrbanAirship.editChannelTagGroups}. - * - * @class TagGroupEditor - * @param nativeMethod The native method to call on apply. - */ -function TagGroupEditor(nativeMethod) { - - // Store the raw operations and let the SDK combine them - var operations = [] - - var editor = {} - - /** - * Adds tags to a tag group. - * @instance - * @memberof TagGroupEditor - * @function addTags - * - * @param {string} tagGroup The tag group. - * @param {array} tags Tags to add. - * @return {TagGroupEditor} The tag group editor instance. - */ - editor.addTags = function(tagGroup, tags) { - argscheck.checkArgs('sa', "TagGroupEditor#addTags", arguments) - var operation = { "operation": "add", "group": tagGroup, "tags": tags } - operations.push(operation) - return editor - } - - /** - * Removes a tag from the tag group. - * @instance - * @memberof TagGroupEditor - * @function removeTags - * - * @param {string} tagGroup The tag group. - * @param {array} tags Tags to remove. - * @return {TagGroupEditor} The tag group editor instance. - */ - editor.removeTags = function(tagGroup, tags) { - argscheck.checkArgs('sa', "TagGroupEditor#removeTags", arguments) - var operation = { "operation": "remove", "group": tagGroup, "tags": tags } - operations.push(operation) - return editor - } - - /** - * Applies the tag changes. - * @instance - * @memberof TagGroupEditor - * @function apply - * - * @param {function} [success] Success callback. - * @param {function(message)} [failure] Failure callback. - * @param {string} failure.message The failure message. - * @return {TagGroupEditor} The tag group editor instance. - */ - editor.apply = function(success, failure) { - argscheck.checkArgs('FF', "TagGroupEditor#apply", arguments) - callNative(success, failure, nativeMethod, [operations]) - operations = [] - return editor - } - - return editor -} - -/** -* Helper object to subscribe/unsubscribe to/from a list. -* -* Normally not created directly. Instead use [UrbanAirship.editSubscriptionLists]{@link module:UrbanAirship.editSubscriptionLists}. -* -* @class ChannelSubscriptionListEditor -* @param nativeMethod The native method to call on apply. -*/ -function ChannelSubscriptionListEditor(nativeMethod) { - - // Store the raw operations and let the SDK combine them - var operations = [] - - var editor = {} - - /** - * Subscribes to a list. - * @instance - * @memberof ChannelSubscriptionListEditor - * @function subscribe - * - * @param {subscriptionListID} subscriptionListID The subscription list identifier. - * @return {ChannelSubscriptionListEditor} The subscription list editor instance. - */ - editor.subscribe = function(subscriptionListID) { - argscheck.checkArgs('s', "ChannelSubscriptionListEditor#subscribe", arguments) - var operation = { "operation": "subscribe", "listId": subscriptionListID} - operations.push(operation) - return editor - } - - /** - * Unsubscribes from a list. - * @instance - * @memberof ChannelSubscriptionListEditor - * @function unsubscribe - * - * @param {subscriptionListID} subscriptionListID The subscription list identifier. - * @return {ChannelSubscriptionListEditor} The subscription list editor instance. - */ - editor.unsubscribe = function(subscriptionListID) { - argscheck.checkArgs('s', "ChannelSubscriptionListEditor#unsubscribe", arguments) - var operation = { "operation": "unsubscribe", "listId": subscriptionListID} - operations.push(operation) - return editor - } - - /** - * Applies subscription list changes. - * @instance - * @memberof ChannelSubscriptionListEditor - * @function apply - * - * @param {function} [success] Success callback. - * @param {function(message)} [failure] Failure callback. - * @param {string} failure.message The failure message. - * @return {ChannelSubscriptionListEditor} The subscription List editor instance. - */ - editor.apply = function(success, failure) { - argscheck.checkArgs('FF', "ChannelSubscriptionListEditor#apply", arguments) - callNative(success, failure, nativeMethod, [operations]) - operations = [] - return editor - } - - return editor -} - -/** -* Helper object to subscribe/unsubscribe to/from a list. -* -* Normally not created directly. Instead use [UrbanAirship.editContactSubscriptionLists]{@link module:UrbanAirship.editContactSubscriptionLists}. -* -* @class ContactSubscriptionListEditor -* @param nativeMethod The native method to call on apply. -*/ -function ContactSubscriptionListEditor(nativeMethod) { - - // Store the raw operations and let the SDK combine them - var operations = [] - - var editor = {} - - /** - * Subscribes to a contact list. - * @instance - * @memberof ContactSubscriptionListEditor - * @function subscribe - * - * @param {subscriptionListID} subscriptionListID The subscription list identifier. - * @param {contactScope} contactScope Defines the channel types that the change applies to. - * @return {ContactSubscriptionListEditor} The subscription list editor instance. - */ - editor.subscribe = function(contactSubscriptionListID, contactScope) { - argscheck.checkArgs('ss', "ContactSubscriptionListEditor#subscribe", arguments) - var operation = { "operation": "subscribe", "listId": contactSubscriptionListID, "scope": contactScope} - operations.push(operation) - return editor - } - - /** - * Unsubscribes from a contact list. - * @instance - * @memberof ContactSubscriptionListEditor - * @function unsubscribe - * - * @param {subscriptionListID} subscriptionListID The subscription list identifier. - * @param {contactScope} contactScope Defines the channel types that the change applies to. - * @return {ContactSubscriptionListEditor} The subscription list editor instance. - */ - editor.unsubscribe = function(contactSubscriptionListID, contactScope) { - argscheck.checkArgs('ss', "ContactSubscriptionListEditor#unsubscribe", arguments) - var operation = { "operation": "unsubscribe", "listId": contactSubscriptionListID, "scope": contactScope} - operations.push(operation) - return editor - } - - /** - * Applies subscription list changes. - * @instance - * @memberof ContactSubscriptionListEditor - * @function apply - * - * @param {function} [success] Success callback. - * @param {function(message)} [failure] Failure callback. - * @param {string} failure.message The failure message. - * @return {ContactSubscriptionListEditor} The subscription List editor instance. - */ - editor.apply = function(success, failure) { - argscheck.checkArgs('FF', "ContactSubscriptionListEditor#apply", arguments) - callNative(success, failure, nativeMethod, [operations]) - operations = [] - return editor - } - - return editor -} - -/** - * Helper object to edit attributes groups. - * - * Normally not created directly. Instead use [UrbanAirship.editChannelAttributes]{@link module:UrbanAirship.editChannelAttributes}. - * - * @class AttributeEditor - * @param nativeMethod The native method to call on apply. - */ -function AttributesEditor(nativeMethod) { - var operations = [] - var editor = {} - - /** - * Sets an attribute. - * @instance - * @memberof AttributesEditor - * @function setAttribute - * - * @param {string} name The attribute name. - * @param {string|number|Date} value The attribute's value. - * @return {AttributesEditor} The attribute editor instance. - */ - editor.setAttribute = function(name, value) { - argscheck.checkArgs('s*', "AttributesEditor#setAttribute", arguments) - - var operation = { "action": "set", "value": value, "key": name } - - if (typeof value === "string") { - operation["type"] = "string" - } else if (typeof value === "number") { - operation["type"] = "number" - } else if (typeof value === "boolean") { - // No boolean attribute type. Convert value to string. - operation["type"] = "string" - operation["value"] = value.toString(); - } else if (value instanceof Date) { - // JavaScript's date type doesn't pass through the JS to native bridge. Dates are instead serialized as milliseconds since epoch. - operation["type"] = "date" - operation["value"] = value.getTime() - } else { - throw("Unsupported attribute type: " + typeof value) - } - - operations.push(operation) - - return editor - } - - /** - * Removes an attribute. - * @instance - * @memberof AttributesEditor - * @function removeAttribute - * - * @param {string} name The attribute's name. - * @return {AttributesEditor} The attribute editor instance. - */ - editor.removeAttribute = function(name) { - argscheck.checkArgs('s', "AttributesEditor#removeAttribute", arguments) - var operation = { "action": "remove", "key": name } - operations.push(operation) - return editor - } - - /** - * Applies the attribute changes. - * @instance - * @memberof AttributesEditor - * @function apply - * - * @param {function} [success] Success callback. - * @param {function(message)} [failure] Failure callback. - * @param {string} failure.message The failure message. - * @return {TagGroupEditor} The tag group editor instance. - */ - editor.apply = function(success, failure) { - argscheck.checkArgs('FF', "AttributesEditor#apply", arguments) - callNative(success, failure, nativeMethod, [operations]) - operations = [] - return editor - } - - return editor -} - -function bindDocumentEvent() { - callNative(function(e) { - console.log("Firing document event: " + e.eventType) - cordova.fireDocumentEvent(e.eventType, e.eventData) - }, null, "registerListener") -} - -document.addEventListener("deviceready", bindDocumentEvent, false) - -/** - * @module UrbanAirship - */ -module.exports = { - - FEATURE_NONE: FEATURE_NONE, - FEATURE_IN_APP_AUTOMATION: FEATURE_IN_APP_AUTOMATION, - FEATURE_MESSAGE_CENTER: FEATURE_MESSAGE_CENTER, - FEATURE_PUSH: FEATURE_PUSH, - FEATURE_CHAT: FEATURE_CHAT, - FEATURE_ANALYTICS: FEATURE_ANALYTICS, - FEATURE_TAGS_AND_ATTRIBUTES: FEATURE_TAGS_AND_ATTRIBUTES, - FEATURE_CONTACTS: FEATURE_CONTACTS, - FEATURE_LOCATION: FEATURE_LOCATION, - FEATURE_ALL: FEATURE_ALL, - - /** - * Event fired when a new deep link is received. - * - * @event deep_link - * @type {object} - * @param {string} [deepLink] The deep link. - */ - - /** - * Event fired when a channel registration occurs. - * - * @event registration - * @type {object} - * @param {string} [channelID] The channel ID. - * @param {string} [registrationToken] The deviceToken on iOS, and the FCM/ADM token on Android. - * @param {string} [error] Error message if an error occurred. - */ - - /** - * Event fired when the inbox is updated. - * - * @event inbox_updated - */ - - /** - * Event fired when the inbox needs to be displayed. This event is only emitted if auto - * launch message center is disabled. - * - * @event show_inbox - * @type {object} - * @param {string} [messageId] The optional message ID. - */ - - /** - * Event fired when a push is received. - * - * @event push - * @type {object} - * @param {string} message The push alert message. - * @param {string} title The push title. - * @param {string} subtitle The push subtitle. - * @param {object} extras Any push extras. - * @param {object} aps The raw aps dictionary (iOS only) - * @param {number} [notification_id] The Android notification ID. Deprecated in favor of notificationId. - * @param {string} [notificationId] The notification ID. - */ - - /** - * Event fired when notification opened. - * - * @event notification_opened - * @type {object} - * @param {string} message The push alert message. - * @param {object} extras Any push extras. - * @param {number} [notification_id] The Android notification ID. Deprecated in favor of notificationId. - * @param {string} [notificationId] The notification ID. - * @param {string} [actionID] The ID of the notification action button if available. - * @param {boolean} isForeground Will always be true if the user taps the main notification. Otherwise its defined by the notification action button. - */ - - /** - * Event fired when the user notification opt-in status changes. - * - * @event notification_opt_in_status - * @type {object} - * @param {boolean} optIn If the user is opted in or not to user notifications. - * @param {object} [authorizedNotificationSettings] iOS only. A map of authorized settings. - * @param {boolean} authorizedNotificationSettings.alert If alerts are authorized. - * @param {boolean} authorizedNotificationSettings.sound If sounds are authorized. - * @param {boolean} authorizedNotificationSettings.badge If badges are authorized. - * @param {boolean} authorizedNotificationSettings.carPlay If car play is authorized. - * @param {boolean} authorizedNotificationSettings.lockScreen If the lock screen is authorized. - * @param {boolean} authorizedNotificationSettings.notificationCenter If the notification center is authorized. - */ - - /** - * Re-attaches document event listeners in this webview - */ - reattach: bindDocumentEvent, - - /** - * Initailizes Urban Airship. - * - * The plugin will automatically call takeOff during the next app init in - * order to properly handle incoming push. If takeOff is called multiple times - * in a session, or if the config is different than the previous sesssion, the - * new config will not be used until the next app start. - * - * @param {object} config The Urban Airship config. - * @param {string} config.site Sets the cloud site, must be either EU or US. - * @param {string} config.messageCenterStyleConfig The message center style config file. By default it's "messageCenterStyleConfig" - * @param {object} config.development The Urban Airship development config. - * @param {string} config.development.appKey The development appKey. - * @param {string} config.development.appSecret The development appSecret. - * @param {object} config.production The Urban Airship production config. - * @param {string} config.production.appKey The production appKey. - * @param {string} config.production.appSecret The production appSecret. - */ - takeOff: function(config, success, failure) { - argscheck.checkArgs("*FF", "UAirship.takeOff", arguments); - callNative(success, failure, "takeOff", [config]); - }, - - /** - * Sets the Android notification config. Values not set will fallback to any values set in the config.xml. - * - * @param {object} config The notification config. - * @param {string} [config.icon] The name of the drawable resource to use as the notification icon. - * @param {string} [config.largeIcon] The name of the drawable resource to use as the notification large icon. - * @param {string} [config.accentColor] The notification accent color. Format is #AARRGGBB. - */ - setAndroidNotificationConfig: function(config, success, failure) { - argscheck.checkArgs("*FF", "UAirship.setAndroidNotificationConfig", arguments); - callNative(success, failure, "setAndroidNotificationConfig", [config]); - }, - - /** - * Sets the default behavior when the message center is launched from a push - * notification. If set to false the message center must be manually launched. - * - * @param {boolean} enabled true to automatically launch the default message center, false to disable. - * @param {function} [success] Success callback. - * @param {function(message)} [failure] Failure callback. - * @param {string} failure.message The error message. - */ - setAutoLaunchDefaultMessageCenter: function(enabled, success, failure) { - argscheck.checkArgs('*FF', 'UAirship.setAutoLaunchDefaultMessageCenter', arguments) - callNative(success, failure, "setAutoLaunchDefaultMessageCenter", [!!enabled]); - }, - - /** - * Enables or disables user notifications. - * - * @param {boolean} enabled true to enable notifications, false to disable. - * @param {function} [success] Success callback. - * @param {function(message)} [failure] Failure callback. - * @param {string} failure.message The error message. - */ - setUserNotificationsEnabled: function(enabled, success, failure) { - argscheck.checkArgs('*FF', 'UAirship.setUserNotificationsEnabled', arguments) - callNative(success, failure, "setUserNotificationsEnabled", [!!enabled]) - }, - - /** - * Checks if user notifications are enabled or not. - * - * @param {function(enabled)} success Success callback. - * @param {boolean} success.enabled Flag indicating if user notifications is enabled or not. - * @param {function(message)} [failure] Failure callback. - * @param {string} failure.message The error message. - */ - isUserNotificationsEnabled: function(success, failure) { - argscheck.checkArgs('fF', 'UAirship.isUserNotificationsEnabled', arguments) - callNative(success, failure, "isUserNotificationsEnabled") - }, - - /** - * Enables user notifications. - * - * @param {function} success Success callback. - * @param {boolean} success.enabled Flag indicating if user notifications enablement was authorized or not. - * @param {function(message)} [failure] Failure callback. - * @param {string} failure.message The error message. - */ - enableUserNotifications: function(success, failure) { - argscheck.checkArgs('fF', 'UAirship.enableUserNotifications', arguments) - callNative(success, failure, "enableUserNotifications") - }, - - /** - * Checks if app notifications are enabled or not. Its possible to have `userNotificationsEnabled` - * but app notifications being disabled if the user opted out of notifications. - * - * @param {function(enabled)} success Success callback. - * @param {boolean} success.enabled Flag indicating if app notifications is enabled or not. - * @param {function(message)} [failure] Failure callback. - * @param {string} failure.message The error message. - */ - isAppNotificationsEnabled: function(success, failure) { - argscheck.checkArgs('fF', 'UAirship.isAppNotificationsEnabled', arguments) - callNative(success, failure, "isAppNotificationsEnabled") - }, - - /** - * Returns the channel ID. - * - * @param {function(ID)} success The function to call on success. - * @param {string} success.ID The channel ID string - * @param {failureCallback} [failure] The function to call on failure. - * @param {string} failure.message The error message. - */ - getChannelID: function(success, failure) { - argscheck.checkArgs('fF', 'UAirship.getChannelID', arguments) - callNative(success, failure, "getChannelID") - }, - - /** - * Returns the last notification that launched the application. - * - * @param {Boolean} clear true to clear the notification. - * @param {function(push)} success The function to call on success. - * @param {object} success.push The push message object containing data associated with a push notification. - * @param {string} success.push.message The push alert message. - * @param {object} success.push.extras Any push extras. - * @param {number} [success.push.notification_id] The Android notification ID. - * @param {failureCallback} [failure] The function to call on failure. - * @param {string} failure.message The error message. - */ - getLaunchNotification: function(clear, success, failure) { - argscheck.checkArgs('*fF', 'UAirship.getLaunchNotification', arguments) - callNative(success, failure, "getLaunchNotification", [!!clear]) - }, - - /** - * Returns the last received deep link. - * - * @param {Boolean} clear true to clear the deep link. - * @param {function(push)} success The function to call on success. - * @param {string} success.deepLink The deep link. - * @param {failureCallback} [failure] The function to call on failure. - * @param {string} failure.message The error message. - */ - getDeepLink: function(clear, success, failure) { - argscheck.checkArgs('*fF', 'UAirship.getDeepLink', arguments) - callNative(success, failure, "getDeepLink", [!!clear]) - }, - - /** - * Returns the tags as an array. - * - * @param {function(tags)} success The function to call on success. - * @param {array} success.tags The tags as an array. - * @param {failureCallback} [failure] The function to call on failure. - * @param {string} failure.message The error message. - */ - getTags: function(success, failure) { - argscheck.checkArgs('fF', 'UAirship.getTags', arguments); - callNative(success, failure, "getTags") - }, - - /** - * Sets the tags. - * - * @param {Array} tags an array of strings. - * @param {function} [success] Success callback. - * @param {function(message)} [failure] Failure callback. - * @param {string} failure.message The error message. - */ - setTags: function(tags, success, failure) { - argscheck.checkArgs('aFF', 'UAirship.setTags', arguments); - callNative(success, failure, "setTags", [tags]) - }, - - /** - * Returns the alias. - * - * @deprecated Deprecated since 6.7.0 - to be removed in a future version of the plugin - please use getNamedUser - * - * @param {function(currentAlias)} success The function to call on success. - * @param {string} success.currentAlias The alias as a string. - * @param {function(message)} [failure] Failure callback. - * @param {string} failure.message The error message. - */ - getAlias: function(success, failure) { - argscheck.checkArgs('fF', 'UAirship.getAlias', arguments) - callNative(success, failure, "getAlias") - }, - - /** - * Sets the alias. - * - * @deprecated Deprecated since 6.7.0 - to be removed in a future version of the plugin - please use setNamedUser - * - * @param {String} alias string - * @param {function} [success] Success callback. - * @param {function(message)} [failure] Failure callback. - * @param {string} failure.message The error message. - */ - setAlias: function(alias, success, failure) { - argscheck.checkArgs('sFF', 'UAirship.setAlias', arguments) - callNative(success, failure, "setAlias", [alias]) - }, - - /** - * Checks if quiet time is enabled or not. - * - * @param {function(enabled)} success Success callback. - * @param {boolean} success.enabled Flag indicating if quiet time is enabled or not. - * @param {function(message)} [failure] Failure callback. - * @param {string} failure.message The error message. - */ - isQuietTimeEnabled: function(success, failure) { - argscheck.checkArgs('fF', 'UAirship.isQuietTimeEnabled', arguments) - callNative(success, failure, "isQuietTimeEnabled") - }, - - /** - * Enables or disables quiet time. - * - * @param {Boolean} enabled true to enable quiet time, false to disable. - * @param {function} [success] Success callback. - * @param {function(message)} [failure] Failure callback. - * @param {string} failure.message The error message. - */ - setQuietTimeEnabled: function(enabled, success, failure) { - argscheck.checkArgs('*FF', 'UAirship.setQuietTimeEnabled', arguments) - callNative(success, failure, "setQuietTimeEnabled", [!!enabled]) - }, - - /** - * Checks if the device is currently in quiet time. - * - * @param {function(inQuietTime)} success Success callback. - * @param {boolean} success.inQuietTime Flag indicating if quiet time is currently in effect. - * @param {function(message)} [failure] Failure callback. - * @param {string} failure.message The error message. - */ - isInQuietTime: function(success, failure) { - argscheck.checkArgs('fF', 'UAirship.isInQuietTime', arguments) - callNative(success, failure, "isInQuietTime") - }, - - /** - * Returns the quiet time as an object with the following: - * "startHour": Number, - * "startMinute": Number, - * "endHour": Number, - * "endMinute": Number - * - * @param {function(quietTime)} success The function to call on success. - * @param {object} success.quietTime The quietTime object represents a timespan during - * which notifications should be silenced. - * @param {function(message)} [failure] Failure callback. - * @param {string} failure.message The error message. - */ - getQuietTime: function(success, failure) { - argscheck.checkArgs('fF', 'UAirship.getQuietTime', arguments) - callNative(success, failure, "getQuietTime") - }, - - /** - * Sets the quiet time. - * - * @param {Number} startHour for quiet time. - * @param {Number} startMinute for quiet time. - * @param {Number} endHour for quiet time. - * @param {Number} endMinute for quiet time. - * @param {function} [success] Success callback. - * @param {function(message)} [failure] Failure callback. - * @param {string} failure.message The error message. - */ - setQuietTime: function(startHour, startMinute, endHour, endMinute, success, failure) { - argscheck.checkArgs('nnnnFF', 'UAirship.setQuietTime', arguments) - callNative(success, failure, "setQuietTime", [startHour, startMinute, endHour, endMinute]) - }, - - /** - * Enables or disables analytics. - * - * Disabling analytics will delete any locally stored events - * and prevent any events from uploading. Features that depend on analytics being - * enabled may not work properly if it's disabled (reports, region triggers, - * location segmentation, push to local time). - * - * @param {Boolean} enabled true to enable analytics, false to disable. - * @param {function} [success] Success callback. - * @param {function(message)} [failure] Failure callback. - * @param {string} failure.message The error message. - */ - setAnalyticsEnabled: function(enabled, success, failure) { - argscheck.checkArgs('*FF', 'UAirship.setAnalyticsEnabled', arguments) - callNative(success, failure, "setAnalyticsEnabled", [!!enabled]) - }, - - /** - * Checks if analytics is enabled or not. - * - * @param {function(enabled)} success Success callback. - * @param {boolean} success.enabled Flag indicating if analytics is enabled or not. - * @param {function(message)} [failure] Failure callback. - * @param {string} failure.message The error message. - */ - isAnalyticsEnabled: function(success, failure) { - argscheck.checkArgs('fF', 'UAirship.isAnalyticsEnabled', arguments) - callNative(success, failure, "isAnalyticsEnabled") - }, - - /** - * Returns the named user ID. - * - * @param {function(namedUser)} success The function to call on success. - * @param {string} success.namedUser The named user ID as a string. - * @param {function(message)} [failure] Failure callback. - * @param {string} failure.message The error message. - */ - getNamedUser: function(success, failure) { - argscheck.checkArgs('fF', 'UAirship.getNamedUser', arguments) - callNative(success, failure, "getNamedUser") - }, - - /** - * Sets the named user ID. - * - * @param {String} namedUser identifier string. - * @param {function} [success] Success callback. - * @param {function(message)} [failure] Failure callback. - * @param {string} failure.message The error message. - */ - setNamedUser: function(namedUser, success, failure) { - argscheck.checkArgs('SFF', 'UAirship.setNamedUser', arguments) - callNative(success, failure, "setNamedUser", [namedUser]) - }, - - /** - * Runs an Urban Airship action. - * - * @param {String} actionName action as a string. - * @param {*} actionValue - * @param {function(result)} [success] The function to call on success. - * @param {object} success.result The result's value. - * @param {function(message)} [failure] Failure callback. - * @param {string} failure.message The error message. - */ - runAction: function(actionName, actionValue, success, failure) { - argscheck.checkArgs('s*FF', 'UAirship.runAction', arguments) - _runAction(actionName, actionValue, success, failure) - }, - - /** - * Creates an editor to modify the named user tag groups. - * - * @return {TagGroupEditor} A tag group editor instance. - */ - editNamedUserTagGroups: function() { - return new TagGroupEditor('editNamedUserTagGroups') - }, - - /** - * Creates an editor to modify the channel tag groups. - * - * @return {TagGroupEditor} A tag group editor instance. - */ - editChannelTagGroups: function() { - return new TagGroupEditor('editChannelTagGroups') - }, - - /** - * Creates an editor to modify the channel attributes. - * - * @return {AttributesEditor} An attributes editor instance. - */ - editChannelAttributes: function() { - return new AttributesEditor('editChannelAttributes') - }, - - /** - * Creates an editor to modify the channel subscription lists. - * - * @return {ChannelSubscriptionListEditor} A subscription list editor instance. - */ - editChannelSubscriptionLists: function() { - return new ChannelSubscriptionListEditor('editChannelSubscriptionLists') - }, - - /** - * Creates an editor to modify the contact subscription lists. - * - * @return {ContacttSubscriptionListEditor} A subscription list editor instance. - */ - editContactSubscriptionLists: function() { - return new ContactSubscriptionListEditor('editContactSubscriptionLists') - }, - - /** - * Creates an editor to modify the named user attributes. - * - * @return {AttributesEditor} An attributes editor instance. - */ - editNamedUserAttributes: function() { - return new AttributesEditor('editNamedUserAttributes') - }, - - /** - * Sets an associated identifier for the Connect data stream. - * - * @param {string} Custom key for identifier. - * @param {string} The identifier value. - * @param {function} [success] Success callback. - * @param {function(message)} [failure] Failure callback. - * @param {string} failure.message The error message. - */ - setAssociatedIdentifier: function(key, identifier, success, failure) { - argscheck.checkArgs('ssFF', 'UAirship.setAssociatedIdentifier', arguments) - callNative(success, failure, "setAssociatedIdentifier", [key, identifier]) - }, - - /** - * Displays the message center. - * - * @param {function} [success] Success callback. - * @param {function(message)} [failure] Failure callback. - * @param {string} failure.message The error message. - */ - displayMessageCenter: function(success, failure) { - argscheck.checkArgs('FF', 'UAirship.displayMessageCenter', arguments) - callNative(success, failure, "displayMessageCenter") - }, - - /** - * Dismiss the message center. - * - * @param {function} [success] Success callback. - * @param {function(message)} [failure] Failure callback. - * @param {string} failure.message The error message. - */ - dismissMessageCenter: function(success, failure) { - argscheck.checkArgs('FF', 'UAirship.dismissMessageCenter', arguments) - callNative(success, failure, "dismissMessageCenter") - }, - - /** - * Dismiss the inbox message. - * - * @param {function} [success] Success callback. - * @param {function(message)} [failure] Failure callback. - * @param {string} failure.message The error message. - */ - dismissInboxMessage: function(success, failure) { - argscheck.checkArgs('FF', 'UAirship.dismissInboxMessage', arguments) - callNative(success, failure, "dismissInboxMessage") - }, - - /** - * Gets the array of inbox messages. Each message will have the following properties: - * "id": string - The messages ID. Needed to display, mark as read, or delete the message. - * "title": string - The message title. - * "sentDate": number - The message sent date in milliseconds. - * "listIconUrl": string, optional - The icon url for the message. - * "isRead": boolean - The unread/read status of the message. - * "extras": object - String to String map of any message extras. - * - * @param {function(messages)} success The function to call on success. - * @param {array} success.messages The array of inbox messages. - * @param {function(message)} [failure] Failure callback. - * @param {string} failure.message The error message. - */ - getInboxMessages: function(success, failure) { - argscheck.checkArgs('fF', 'UAirship.getInboxMessages', arguments) - callNative(success, failure, "getInboxMessages") - }, - - /** - * Marks an inbox message read. - * - * @param {String} messageId The ID of the message to mark as read. - * @param {function} [success] Success callback. - * @param {function(message)} [failure] Failure callback. - * @param {string} failure.message The error message. - */ - markInboxMessageRead: function(messageId, success, failure) { - argscheck.checkArgs('sFF', 'UAirship.markInboxMessageRead', arguments) - callNative(success, failure, 'markInboxMessageRead', [messageId]) - }, - - /** - * Deletes an inbox message. - * - * @param {String} messageId The ID of the message to delete. - * @param {function} [success] Success callback. - * @param {function(message)} [failure] Failure callback. - * @param {string} failure.message The error message. - */ - deleteInboxMessage: function(messageId, success, failure) { - argscheck.checkArgs('sFF', 'UAirship.deleteInboxMessage', arguments) - callNative(success, failure, 'deleteInboxMessage', [messageId]) - }, - - /** - * Displays the inbox message using a full screen view. - * - * @param {String} messageId The ID of the message to display. - * @param {function} [success] Success callback. - * @param {function(message)} [failure] Failure callback. - * @param {string} failure.message The error message. - */ - displayInboxMessage: function(messageId, success, failure) { - argscheck.checkArgs('sFF', 'UAirship.displayInboxMessage', arguments) - callNative(success, failure, 'displayInboxMessage', [messageId]) - }, - - /** - * Forces the inbox to refresh. This is normally not needed as the inbox - * will automatically refresh on foreground or when a push arrives thats - * associated with a message, but it can be useful when providing a refresh - * button for the message listing. - * - * @param {function} [success] Success callback. - * @param {function(message)} [failure] Failure callback. - * @param {string} failure.message The error message. - */ - refreshInbox: function(success, failure) { - argscheck.checkArgs('FF', 'UAirship.refreshInbox', arguments) - callNative(success, failure, 'refreshInbox') - }, - - /** - * Clears a notification by identifier. - * - * @param {string} identifier The notification identifier. - * @param {function} [success] Success callback. - * @param {function(message)} [failure] Failure callback. - */ - clearNotification: function(identifier, success, failure) { - argscheck.checkArgs('sFF', 'UAirship.clearNotification', arguments) - callNative(success, failure, "clearNotification", [identifier]) - }, - - /** - * Clears all notifications posted by the application. - * - * @param {function} [success] Success callback. - * @param {function(message)} [failure] Failure callback. - * @param {string} failure.message The error message. - */ - clearNotifications: function(success, failure) { - argscheck.checkArgs('FF', 'UAirship.clearNotifications', arguments) - callNative(success, failure, "clearNotifications") - }, - - /** - * Gets currently active notifications. - * - * Note: On Android this functionality is only supported on Android M or higher. - * - * @param {function(messages)} [success] Success callback. - * @param {function(message)} [failure] Failure callback. - */ - getActiveNotifications: function(success, failure) { - argscheck.checkArgs('fF', 'UAirship.getActiveNotifications', arguments) - callNative(success, failure, "getActiveNotifications") - }, - - // iOS only - - /** - * Enables or disables auto badge. Defaults to `NO`. - * - * @param {Boolean} enabled true to enable auto badge, false to disable. - * @param {function} [success] Success callback. - * @param {function(message)} [failure] Failure callback. - * @param {string} failure.message The error message. - */ - setAutobadgeEnabled: function(enabled, success, failure) { - argscheck.checkArgs('*FF', 'UAirship.setAutobadgeEnabled', arguments) - callNative(success, failure, "setAutobadgeEnabled", [!!enabled]) - }, - - /** - * Sets the badge number. - * - * @param {Number} number specified badge to set. - * @param {function} [success] Success callback. - * @param {function(message)} [failure] Failure callback. - * @param {string} failure.message The error message. - */ - setBadgeNumber: function(number, success, failure) { - argscheck.checkArgs('nFF', 'UAirship.setBadgeNumber', arguments) - callNative(success, failure, "setBadgeNumber", [number]) - }, - - /** - * Returns the current badge number. - * - * @param {function(badgeNumber)} success The function to call on success. - * @param {int} success.badgeNumber The current application badge number. - * @param {function(message)} [failure] Failure callback. - * @param {string} failure.message The error message. - */ - getBadgeNumber: function(success, failure) { - argscheck.checkArgs('fF', 'UAirship.getBadgeNumber', arguments) - callNative(success, failure, "getBadgeNumber") - }, - - /** - * Clears the badge. - * - * @param {function} [success] Success callback. - * @param {function(message)} [failure] Failure callback. - * @param {string} failure.message The error message. - */ - resetBadge: function(success, failure) { - argscheck.checkArgs('FF', 'UAirship.resetBadge', arguments) - callNative(success, failure, "resetBadge") - }, - - /** - * Sets the iOS notification types. Specify the combination of - * badges, sound and alerts that are desired. - * - * @param {notificationType} types specified notification types. - * @param {function} [success] Success callback. - * @param {function(message)} [failure] Failure callback. - * @param {string} failure.message The error message. - */ - setNotificationTypes: function(types, success, failure) { - argscheck.checkArgs('nFF', 'UAirship.setNotificationTypes', arguments) - callNative(success, failure, "setNotificationTypes", [types]) - }, - - /** - * Sets the iOS presentation options. Specify the combination of - * badges, sound and alerts that are desired. - * - * @param {presentationOptions} types specified presentation options. - * @param {function} [success] Success callback. - * @param {function(message)} [failure] Failure callback. - * @param {string} failure.message The error message. - */ - setPresentationOptions: function(options, success, failure) { - argscheck.checkArgs('nFF', 'UAirship.setPresentationOptions', arguments) - callNative(success, failure, "setPresentationOptions", [options]) - }, - - /** - * Enables/Disables foreground notifications display on Android. - * - * @param {Boolean} enabled true to enable foreground notifications, false to disable. - * @param {function} [success] Success callback. - * @param {function(message)} [failure] Failure callback. - * @param {string} failure.message The error message. - */ - setAndroidForegroundNotificationsEnabled: function(enabled, success, failure) { - argscheck.checkArgs('*FF', 'UAirship.setAndroidForegroundNotificationsEnabled', arguments) - callNative(success, failure, "setAndroidForegroundNotificationsEnabled", [!!enabled]) - }, - - /** - * Enum for notification types. - * @readonly - * @enum {number} - */ - notificationType: { - none: 0, - badge: 1, - sound: 2, - alert: 4 - }, - - /** - * Enum for presentation options. - * @readonly - * @enum {number} - */ - presentationOptions: { - none: 0, - badge: 1, - sound: 2, - alert: 4 - }, - - // Android only - - /** - * Checks if notification sound is enabled or not. - * - * @param {function(enabled)} success Success callback. - * @param {boolean} success.enabled Flag indicating if sound is enabled or not. - * @param {function(message)} [failure] Failure callback. - * @param {string} failure.message The error message. - */ - isSoundEnabled: function(success, failure) { - argscheck.checkArgs('fF', 'UAirship.isSoundEnabled', arguments) - callNative(success, failure, "isSoundEnabled") - }, - - /** - * Enables or disables notification sound. - * - * @param {Boolean} enabled true to enable sound, false to disable. - * @param {function} [success] Success callback. - * @param {function(message)} [failure] Failure callback. - * @param {string} failure.message The error message. - */ - setSoundEnabled: function(enabled, success, failure) { - argscheck.checkArgs('*FF', 'UAirship.setSoundEnabled', arguments) - callNative(success, failure, "setSoundEnabled", [!!enabled]) - }, - - /** - * Checks if notification vibration is enabled or not. - * - * @param {function(enabled)} success Success callback. - * @param {boolean} success.enabled Flag indicating if vibration is enabled or not. - * @param {function(message)} [failure] Failure callback. - * @param {string} failure.message The error message. - */ - isVibrateEnabled: function(success, failure) { - argscheck.checkArgs('fF', 'UAirship.isVibrateEnabled', arguments) - callNative(success, failure, "isVibrateEnabled") - }, - - /** - * Enables or disables notification vibration. - * - * @param {Boolean} enabled true to enable vibration, false to disable. - * @param {function} [success] Success callback. - * @param {function(message)} [failure] Failure callback. - * @param {string} failure.message The error message. - */ - setVibrateEnabled: function(enabled, success, failure) { - argscheck.checkArgs('*FF', 'UAirship.setVibrateEnabled', arguments) - callNative(success, failure, "setVibrateEnabled", [!!enabled]) - }, - - /** - * Adds a custom event. - * - * @param {object} event The custom event object. - * @param {string} event.name The event's name. - * @param {number} [event.value] The event's value. - * @param {string} [event.transactionId] The event's transaction ID. - * @param {object} [event.properties] The event's properties. Only numbers, booleans, strings, and array of strings are supported. - * @param {function} [success] Success callback. - * @param {function(message)} [failure] Failure callback. - * @param {string} failure.message The error message. - */ - addCustomEvent: function(event, success, failure) { - argscheck.checkArgs('oFF', 'UAirship.addCustomEvent', arguments) - - var actionArg = { - event_name: event.name, - event_value: event.value, - transaction_id: event.transactionId, - properties: event.properties - } - - _runAction("add_custom_event_action", actionArg, success, failure) - }, - - /** - * Initiates screen tracking for a specific app screen, must be called once per tracked screen. - * - * @param {string} screen The screen's string identifier. - * @param {function} [success] Success callback. - * @param {function(message)} [failure] Failure callback. - * @param {string} failure.message The error message. - */ - trackScreen: function(screen, success, failure) { - argscheck.checkArgs('sFF', 'UAirship.trackScreen', arguments) - callNative(success, failure, "trackScreen", [screen]) - }, - - /** - * Enables features, adding them to the set of currently enabled features. - * - * @param {array} features The features to enable. - * @param {function} [success] Success callback. - * @param {function(message)} [failure] Failure callback. - * @param {string} failure.message The error message. - */ - enableFeature: function(features, success, failure) { - argscheck.checkArgs('aFF', 'UAirship.enableFeature', arguments) - callNative(success, failure, "enableFeature", [features]) - }, - - /** - * Disables features, removing them from the set of currently enabled features. - * - * @param {array} features The features to disable. - * @param {function} [success] Success callback. - * @param {function(message)} [failure] Failure callback. - * @param {string} failure.message The error message. - */ - disableFeature: function(features, success, failure) { - argscheck.checkArgs('aFF', 'UAirship.disableFeature', arguments) - callNative(success, failure, "disableFeature", [features]) - }, - - /** - * Sets the current enabled features, replacing any currently enabled features with the given set. - * - * @param {array} features The features to set as enabled. - * @param {function} [success] Success callback. - * @param {function(message)} [failure] Failure callback. - * @param {string} failure.message The error message. - */ - setEnabledFeatures: function(features, success, failure) { - argscheck.checkArgs('aFF', 'UAirship.setEnabledFeatures', arguments) - callNative(success, failure, "setEnabledFeatures", [features]) - }, - - /** - * Gets the current enabled features. - * - * @param {function} [success] Success callback. - * @param {function(message)} [failure] Failure callback. - * @param {string} failure.message The error message. - */ - getEnabledFeatures: function(success, failure) { - argscheck.checkArgs('FF', 'UAirship.getEnabledFeatures', arguments) - callNative(success, failure, "getEnabledFeatures") - }, - - /** - * Checks if all of the given features are enabled. - * - * @param {array} features The features to check. - * @param {function} [success] Success callback. - * @param {function(message)} [failure] Failure callback. - * @param {string} failure.message The error message. - */ - isFeatureEnabled: function(features, success, failure) { - argscheck.checkArgs('aFF', 'UAirship.isFeatureEnabled', arguments) - callNative(success, failure, "isFeatureEnabled", [features]) - }, - - /** - * Opens the Preference Center with the given preferenceCenterId. - * - * @param {string} preferenceCenterId The preference center ID. - * @param {function} [success] Success callback. - * @param {function(message)} [failure] Failure callback. - * @param {string} failure.message The error message. - */ - openPreferenceCenter: function(preferenceCenterId, success, failure) { - argscheck.checkArgs('sFF', 'UAirship.openPreferenceCenter', arguments) - callNative(success, failure, "openPreferenceCenter", [preferenceCenterId]) - }, - - /** - * Returns the configuration of the Preference Center with the given ID trough a callback method. - * - * @param {string} preferenceCenterId The preference center ID. - * @param {function} [success] Success callback. - * @param {function(message)} [failure] Failure callback. - * @param {string} failure.message The error message. - */ - getPreferenceCenterConfig: function(preferenceCenterId, success, failure) { - argscheck.checkArgs('sFF', 'UAirship.getPreferenceCenterConfig', arguments) - callNative(success, failure, "getPreferenceCenterConfig", [preferenceCenterId]) - }, - - /** - * Returns the current set of subscription lists for the current channel, - * optionally applying pending subscription list changes that will be applied during the next channel update. - * An empty set indicates that this contact is not subscribed to any lists. - * - * @param {function} [success] Success callback. - * @param {string} failure.message The error message. - */ - getChannelSubscriptionLists: function(success, failure) { - argscheck.checkArgs('fF', 'UAirship.getChannelSubscriptionLists', arguments) - callNative(success, failure, "getChannelSubscriptionLists") - }, - - /** - * Returns the current set of subscription lists for the current contact, - * optionally applying pending subscription list changes that will be applied during the next contact update. - * An empty set indicates that this contact is not subscribed to any lists. - * - * @param {function} [success] Success callback. - * @param {string} failure.message The error message. - */ - getContactSubscriptionLists: function(success, failure) { - argscheck.checkArgs('fF', 'UAirship.getContactSubscriptionLists', arguments) - callNative(success, failure, "getContactSubscriptionLists") - }, - - /** - * Sets the use custom preference center. - * - * @param {string} preferenceCenterId The preference center ID. - * @param {boolean} useCustomUi The preference center use custom UI. - */ - setUseCustomPreferenceCenterUi: function(preferenceCenterId, useCustomUi, success, failure) { - argscheck.checkArgs("s*FF", "UAirship.setUseCustomPreferenceCenterUi", arguments) - callNative(success, failure, "setUseCustomPreferenceCenterUi", [preferenceCenterId, useCustomUi]) - }, - - /** - * Overriding the locale. - * - * @param {string} localeIdentifier The locale identifier. - */ - setCurrentLocale: function(localeIdentifier, success, failure) { - argscheck.checkArgs("sFF", "UAirship.setCurrentLocale", arguments) - callNative(success, failure, "setCurrentLocale", [localeIdentifier]) - }, - - /** - * Getting the locale currently used by Airship. - * - * @param {function} [success] Success callback. - * @param {string} failure.message The error message. - */ - getCurrentLocale: function(success, failure) { - argscheck.checkArgs('fF', 'UAirship.getCurrentLocale', arguments) - callNative(success, failure, "getCurrentLocale") - }, - - /** - * Resets the current locale. - * - * @param {function} [success] Success callback. - * @param {function(message)} [failure] Failure callback. - * @param {string} failure.message The error message. - */ - clearLocale: function(success, failure) { - argscheck.checkArgs('FF', 'UAirship.clearLocale', arguments) - callNative(success, failure, "clearLocale") - } - -}