Repository: EddyVerbruggen/nativescript-local-notifications
Branch: master
Commit: 40c599656b37
Files: 150
Total size: 265.6 KB
Directory structure:
gitextract_jbw4v8s9/
├── .gitignore
├── .travis.yml
├── LICENSE
├── README.md
├── demo/
│ ├── app/
│ │ ├── App_Resources/
│ │ │ ├── Android/
│ │ │ │ ├── app.gradle
│ │ │ │ └── src/
│ │ │ │ └── main/
│ │ │ │ ├── AndroidManifest.xml
│ │ │ │ └── res/
│ │ │ │ ├── drawable-nodpi/
│ │ │ │ │ └── splash_screen.xml
│ │ │ │ ├── values/
│ │ │ │ │ ├── colors.xml
│ │ │ │ │ └── styles.xml
│ │ │ │ └── values-v21/
│ │ │ │ ├── colors.xml
│ │ │ │ └── styles.xml
│ │ │ └── iOS/
│ │ │ ├── Assets.xcassets/
│ │ │ │ ├── AppIcon.appiconset/
│ │ │ │ │ └── Contents.json
│ │ │ │ ├── Contents.json
│ │ │ │ ├── LaunchImage.launchimage/
│ │ │ │ │ └── Contents.json
│ │ │ │ ├── LaunchScreen.AspectFill.imageset/
│ │ │ │ │ └── Contents.json
│ │ │ │ └── LaunchScreen.Center.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── Info.plist
│ │ │ ├── LaunchScreen.storyboard
│ │ │ └── build.xcconfig
│ │ ├── README.md
│ │ ├── app-root.xml
│ │ ├── app.css
│ │ ├── app.ts
│ │ ├── bundle-config.ts
│ │ ├── main-page.ts
│ │ ├── main-page.xml
│ │ ├── main-view-model.ts
│ │ └── package.json
│ ├── package.json
│ ├── references.d.ts
│ ├── tsconfig.json
│ └── tsconfig.tns.json
├── demo-ng/
│ ├── App_Resources/
│ │ ├── Android/
│ │ │ ├── app.gradle
│ │ │ └── src/
│ │ │ └── main/
│ │ │ ├── AndroidManifest.xml
│ │ │ └── res/
│ │ │ ├── drawable-nodpi/
│ │ │ │ └── splash_screen.xml
│ │ │ ├── values/
│ │ │ │ ├── colors.xml
│ │ │ │ └── styles.xml
│ │ │ └── values-v21/
│ │ │ ├── colors.xml
│ │ │ └── styles.xml
│ │ └── iOS/
│ │ ├── Assets.xcassets/
│ │ │ ├── AppIcon.appiconset/
│ │ │ │ └── Contents.json
│ │ │ ├── Contents.json
│ │ │ ├── LaunchImage.launchimage/
│ │ │ │ └── Contents.json
│ │ │ ├── LaunchScreen.AspectFill.imageset/
│ │ │ │ └── Contents.json
│ │ │ └── LaunchScreen.Center.imageset/
│ │ │ └── Contents.json
│ │ ├── Info.plist
│ │ ├── LaunchScreen.storyboard
│ │ └── build.xcconfig
│ ├── README.md
│ ├── angular.json
│ ├── nsconfig.json
│ ├── package.json
│ ├── references.d.ts
│ ├── src/
│ │ ├── app/
│ │ │ ├── app-routing.module.ts
│ │ │ ├── app.component.html
│ │ │ ├── app.component.ts
│ │ │ ├── app.module.ts
│ │ │ └── item/
│ │ │ ├── items.component.html
│ │ │ └── items.component.ts
│ │ ├── app.css
│ │ ├── main.ts
│ │ └── package.json
│ ├── tsconfig.json
│ └── tsconfig.tns.json
├── demo-vue/
│ ├── .gitignore
│ ├── README.md
│ ├── app/
│ │ ├── App_Resources/
│ │ │ ├── Android/
│ │ │ │ ├── app.gradle
│ │ │ │ └── src/
│ │ │ │ └── main/
│ │ │ │ ├── AndroidManifest.xml
│ │ │ │ └── res/
│ │ │ │ ├── drawable-nodpi/
│ │ │ │ │ └── splash_screen.xml
│ │ │ │ ├── values/
│ │ │ │ │ ├── colors.xml
│ │ │ │ │ ├── strings.xml
│ │ │ │ │ └── styles.xml
│ │ │ │ └── values-v21/
│ │ │ │ ├── colors.xml
│ │ │ │ ├── strings.xml
│ │ │ │ └── styles.xml
│ │ │ └── iOS/
│ │ │ ├── Assets.xcassets/
│ │ │ │ ├── AppIcon.appiconset/
│ │ │ │ │ └── Contents.json
│ │ │ │ ├── Contents.json
│ │ │ │ ├── LaunchImage.launchimage/
│ │ │ │ │ └── Contents.json
│ │ │ │ ├── LaunchScreen.AspectFill.imageset/
│ │ │ │ │ └── Contents.json
│ │ │ │ └── LaunchScreen.Center.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── Info.plist
│ │ │ ├── LaunchScreen.storyboard
│ │ │ └── build.xcconfig
│ │ ├── app.scss
│ │ ├── components/
│ │ │ └── App.vue
│ │ ├── fonts/
│ │ │ └── .gitkeep
│ │ ├── main.js
│ │ └── package.json
│ └── package.json
├── native-src/
│ ├── android/
│ │ ├── .gitattributes
│ │ ├── .gitignore
│ │ ├── README.md
│ │ ├── android.iml
│ │ ├── app/
│ │ │ ├── .gitignore
│ │ │ ├── app.iml
│ │ │ ├── build.gradle
│ │ │ ├── proguard-rules.pro
│ │ │ └── src/
│ │ │ └── main/
│ │ │ ├── AndroidManifest.xml
│ │ │ ├── java/
│ │ │ │ └── com/
│ │ │ │ └── telerik/
│ │ │ │ └── localnotifications/
│ │ │ │ ├── Action.java
│ │ │ │ ├── ActionGroup.java
│ │ │ │ ├── Builder.java
│ │ │ │ ├── DownloadFileFromUrl.java
│ │ │ │ ├── LifecycleCallbacks.java
│ │ │ │ ├── LocalNotificationsPlugin.java
│ │ │ │ ├── LocalNotificationsPluginListener.java
│ │ │ │ ├── NotificationActionReceiver.java
│ │ │ │ ├── NotificationAlarmReceiver.java
│ │ │ │ ├── NotificationClearedReceiver.java
│ │ │ │ ├── NotificationRestoreReceiver.java
│ │ │ │ └── Store.java
│ │ │ └── res/
│ │ │ └── values/
│ │ │ └── strings.xml
│ │ ├── build.gradle
│ │ ├── gradle/
│ │ │ └── wrapper/
│ │ │ ├── gradle-wrapper.jar
│ │ │ └── gradle-wrapper.properties
│ │ ├── gradle.properties
│ │ ├── gradlew
│ │ ├── gradlew.bat
│ │ ├── locnotplugin.iml
│ │ └── settings.gradle
│ └── ios/
│ ├── .gitattributes
│ ├── .gitignore
│ ├── LocalNotificationsPlugin/
│ │ ├── Info.plist
│ │ ├── LocalNotificationsPlugin.h
│ │ ├── Notification.h
│ │ ├── Notification.m
│ │ ├── NotificationManager.h
│ │ └── NotificationManager.m
│ ├── LocalNotificationsPlugin.xcodeproj/
│ │ ├── project.pbxproj
│ │ └── project.xcworkspace/
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata/
│ │ └── PushPlugin.xccheckout
│ └── README.md
├── publish/
│ ├── pack.sh
│ ├── package.json
│ └── publish.sh
├── src/
│ ├── .npmignore
│ ├── index.d.ts
│ ├── local-notifications-common.ts
│ ├── local-notifications.android.ts
│ ├── local-notifications.ios.ts
│ ├── package.json
│ ├── platforms/
│ │ ├── android/
│ │ │ └── app-release.aar
│ │ └── ios/
│ │ ├── LocalNotificationsPlugin.framework/
│ │ │ ├── Headers/
│ │ │ │ ├── LocalNotificationsPlugin.h
│ │ │ │ ├── Notification.h
│ │ │ │ └── NotificationManager.h
│ │ │ ├── Info.plist
│ │ │ ├── LocalNotificationsPlugin
│ │ │ └── Modules/
│ │ │ └── module.modulemap
│ │ └── typings/
│ │ └── objc!LocalNotificationsPlugin.d.ts
│ ├── references.d.ts
│ └── tsconfig.json
└── tslint.json
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
.idea/
.vscode/
node_modules/
*.js
!demo-vue/app/main.js
src/*.d.ts
!src/index.d.ts
!src/references.d.ts
demo/platforms
demo-ng/platforms
publish/package/
native-src/android/.project
native-src/android/local.properties
native-src/android/.settings/
================================================
FILE: .travis.yml
================================================
matrix:
include:
- stage: "Lint"
language: node_js
os: linux
node_js: "10"
script: cd src && npm run ci.tslint
- stage: "WebPack, Build"
os: osx
env:
- WebPack="iOS"
osx_image: xcode11.2
language: node_js
node_js: "10"
jdk: oraclejdk8
before_script: pod repo update
script: cd demo && npm run build.plugin && npm i && tns build ios --bundle --env.uglify
- language: android
os: linux
env:
- WebPack="Android"
jdk: oraclejdk8
before_install: nvm install 8
script: cd demo && npm run build.plugin && npm i && tns build android --bundle --env.uglify --env.snapshot
- language: android
env:
- BuildAndroid="28"
os: linux
dist: trusty
jdk: oraclejdk8
before_install: nvm install 10
script:
- cd src && npm run build && cd ../demo && tns build android
- os: osx
osx_image: xcode11.2
language: node_js
node_js: "10"
jdk: oraclejdk8
before_script: pod repo update
script:
- cd src && npm run build && cd ../demo && tns build ios
android:
components:
- tools
- platform-tools
- build-tools-28.0.3
- android-28
- extra-android-m2repository
- sys-img-armeabi-v7a-android-21
before_install:
- sudo pip install --upgrade pip
- sudo pip install six
install:
- echo no | npm install -g nativescript@6
- tns usage-reporting disable
- tns error-reporting disable
================================================
FILE: LICENSE
================================================
The MIT License (MIT)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
# NativeScript Local Notifications Plugin
[![NPM version][npm-image]][npm-url]
[![Downloads][downloads-image]][npm-url]
[![Twitter Follow][twitter-image]][twitter-url]
[build-status]:https://travis-ci.org/EddyVerbruggen/nativescript-local-notifications.svg?branch=master
[build-url]:https://travis-ci.org/EddyVerbruggen/nativescript-local-notifications
[npm-image]:http://img.shields.io/npm/v/nativescript-local-notifications.svg
[npm-url]:https://npmjs.org/package/nativescript-local-notifications
[downloads-image]:http://img.shields.io/npm/dm/nativescript-local-notifications.svg
[twitter-image]:https://img.shields.io/twitter/follow/eddyverbruggen.svg?style=social&label=Follow%20me
[twitter-url]:https://twitter.com/eddyverbruggen
The Local Notifications plugin allows your app to show notifications when the app is not running.
Just like remote push notifications, but a few orders of magnitude easier to set up.
> ⚠️ Plugin version 4.0.0 should be used with NativeScript 6+. If you have an older `tns --version`, please use an older plugin version.
> ⚠️ Looking for NativeScript 7 compatibilty? Go to [the NativeScript/plugins repo](https://github.com/NativeScript/plugins/tree/master/packages/local-notifications).
## Installation
From the command prompt go to your app's root folder and execute:
```bash
tns plugin add nativescript-local-notifications
```
## Setup (since plugin version 3.0.0)
Add this so for iOS 10+ we can do some wiring (set the iOS `UNUserNotificationCenter.delegate`, to be precise).
Not needed if your app loads the plugin on startup anyway.
You'll know you need this if on iOS 10+ notifications are not received by your app or `addOnMessageReceivedCallback` is not invoked... better safe than sorry, though!
```js
require ("nativescript-local-notifications");
```
Now you can import the plugin as an object into your `.ts` file as follows:
```typescript
// either
import { LocalNotifications } from "nativescript-local-notifications";
// or (if that doesn't work for you)
import * as LocalNotifications from "nativescript-local-notifications";
// then use it as:
LocalNotifications.hasPermission()
```
## Demo apps
### NativeScript-Core (XML)
This demo is the one with the most options, so it's a cool one to check out:
```bash
git clone https://github.com/EddyVerbruggen/nativescript-local-notifications
cd nativescript-local-notifications/src
npm run demo.ios # or demo.android
```
### NativeScript-Angular
This plugin is part of the [plugin showcase app](https://github.com/EddyVerbruggen/nativescript-pluginshowcase/tree/master/app/feedback) I built using Angular.
There's also a simple Angular [demo in this repo](https://github.com/EddyVerbruggen/nativescript-local-notifications/tree/master/demo-ng):
```bash
git clone https://github.com/EddyVerbruggen/nativescript-local-notifications
cd nativescript-local-notifications/src
npm run demo-ng.ios # or demo-ng.android
```
### NativeScript-Vue
We also have a [Vue demo](https://github.com/EddyVerbruggen/nativescript-local-notifications/tree/master/demo-vue):
```bash
git clone https://github.com/EddyVerbruggen/nativescript-local-notifications
cd nativescript-local-notifications/src
npm run demo-vue.ios # or demo-vue.android
```
## Plugin API
### schedule
On iOS you need to ask permission to schedule a notification.
You can have the `schedule` funtion do that for you automatically (the notification will be scheduled in case the user granted permission),
or you can manually invoke `requestPermission` if that's your thing.
You can pass several options to this function, everything is optional:
|option|description|
|------|-----------|
|`id` |A number so you can easily distinguish your notifications. Will be generated if not set.|
|`title` |The title which is shown in the statusbar. Default not set.|
|`subtitle` |Shown below the title on iOS, and next to the App name on Android. Default not set. All android and iOS >= 10 only.|
|`body` |The text below the title. If not provided, the subtitle or title (in this order or priority) will be swapped for it on iOS, as iOS won't display notifications without a body. Default not set on Android, `' '` on iOS, as otherwise the notification won't show up at all.|
|`color` |Custom color for the notification icon and title that will be applied when the notification center is expanded. (**Android Only**)|
|`bigTextStyle` |Allow more than 1 line of the body text to show in the notification centre. Mutually exclusive with `image`. Default `false`. (**Android Only**)|
|`groupedMessages`| An array of atmost 5 messages that would be displayed using android's notification [inboxStyle](https://developer.android.com/reference/android/app/Notification.InboxStyle.html). Note: The array would be trimed from the top if the messages exceed five. Default not set |
|`groupSummary`| An [inboxStyle](https://developer.android.com/reference/android/app/Notification.InboxStyle.html) notification summary. Default empty|
|`ticker` |On Android you can show a different text in the statusbar, instead of the `body`. Default not set, so `body` is used.|
|`at` |A JavaScript Date object indicating when the notification should be shown. Default not set (the notification will be shown immediately).|
|`badge` |On iOS (and some Android devices) you see a number on top of the app icon. On most Android devices you'll see this number in the notification center. Default not set (0).|
|`sound` |Notification sound. For custom notification sound (iOS only), copy the file to `App_Resources/iOS`. Set this to "default" (or do not set at all) in order to use default OS sound. Set this to `null` to suppress sound.|
|`interval` |Set to one of `second`, `minute`, `hour`, `day`, `week`, `month`, `year` if you want a recurring notification.|
|`icon`|On Android you can set a custom icon in the system tray. Pass in `res://filename` (without the extension) which lives in `App_Resouces/Android/drawable` folders. If not passed, we'll look there for a file named `ic_stat_notify.png`. By default the app icon is used. Android < Lollipop (21) only (see `silhouetteIcon` below).|
|`silhouetteIcon`|Same as `icon`, but for Android >= Lollipop (21). Should be an alpha-only image. Defaults to `res://ic_stat_notify_silhouette`, or the app icon if not present.|
|`image` |*URL* (`http..`) of the image to use as an expandable notification image. On Android this is mutually exclusive with `bigTextStyle`.|
|`thumbnail` |Custom thumbnail/icon to show in the notification center (to the right) on Android, this can be either: `true` (if you want to use the `image` as the thumbnail), a resource URL (that lives in the `App_Resouces/Android/drawable` folders, e.g.: `res://filename`), or a http URL from anywhere on the web. (**Android Only**). Default not set.|
|`ongoing` |Default is (`false`). Set whether this is an `ongoing` notification. Ongoing notifications cannot be dismissed by the user, so your application must take care of canceling them. (**Android Only**) |
|`channel` |Default is (`Channel`). Set the channel name for Android API >= 26, which is shown when the user longpresses a notification. (**Android Only**) |
|`forceShowWhenInForeground` |Default is `false`. Set to `true` to always show the notification. Note that on iOS < 10 this is ignored (the notification is not shown), and on newer Androids it's currently ignored as well (the notification always shows, per platform default). |
|`priority` |Default is `0`. Will override `forceShowWhenInForeground` if set. This can be set to `2` for Android "heads-up" notifications. See [#114](https://github.com/EddyVerbruggen/nativescript-local-notifications/issues/114) for details. |
|`actions` |Add an array of `NotificationAction` objects (see below) to add buttons or text input to a notification. |
|`notificationLed` |Enable the notification LED light on Android (if supported by the device), this can be either: `true` (if you want to use the default color), or a custom color for the notification LED light (if supported by the device). (**Android Only**). Default not set.|
#### `NotificationAction`
|option|description|
|------|-----------|
|`id` |An id so you can easily distinguish your actions.|
|`type` |Either `button` or `input`.|
|`title` |The label for `type` = `button`.|
|`launch` |Launch the app when the action completes.|
|`submitLabel` |The submit button label for `type` = `input`.|
|`placeholder` |The placeholder text for `type` = `input`.|
```js
LocalNotifications.schedule([{
id: 1, // generated id if not set
title: 'The title',
body: 'Recurs every minute until cancelled',
ticker: 'The ticker',
color: new Color("red"),
badge: 1,
groupedMessages:["The first", "Second", "Keep going", "one more..", "OK Stop"], //android only
groupSummary:"Summary of the grouped messages above", //android only
ongoing: true, // makes the notification ongoing (Android only)
icon: 'res://heart',
image: "https://cdn-images-1.medium.com/max/1200/1*c3cQvYJrVezv_Az0CoDcbA.jpeg",
thumbnail: true,
interval: 'minute',
channel: 'My Channel', // default: 'Channel'
sound: "customsound-ios.wav", // falls back to the default sound on Android
at: new Date(new Date().getTime() + (10 * 1000)) // 10 seconds from now
}]).then(
function(scheduledIds) {
console.log("Notification id(s) scheduled: " + JSON.stringify(scheduledIds));
},
function(error) {
console.log("scheduling error: " + error);
}
)
```
### Notification icons (Android)
These options default to `res://ic_stat_notify` and `res://ic_stat_notify_silhouette` respectively, or the app icon if not present.
`silhouetteIcon` should be an alpha-only image and will be used in Android >= Lollipop (21).
[These are the official icon size guidelines](https://developer.android.com/guide/practices/ui_guidelines/icon_design_status_bar.html),
and [here's a great guide on how to easily create these icons on Android](https://developer.android.com/studio/write/image-asset-studio).
| Density qualifier | px | dpi
| ------- | ------- | ---
| ldpi | 18 × 18 | 120
| mdpi | 24 × 24 | 160
| hdpi | 36 × 36 | 240
| xhdpi | 48 × 48 | 320
| xxhdpi | 72 × 72 | 480
| xxxhdpi | 96 × 96 | 640 approx.
__Source:__ [Density Qualifier Docs](https://developer.android.com/guide/topics/resources/providing-resources.html#DensityQualifier)
### addOnMessageReceivedCallback
Tapping a notification in the notification center will launch your app.
But what if you scheduled two notifications and you want to know which one the user tapped?
Use this function to have a callback invoked when a notification was used to launch your app.
Note that on iOS it will even be triggered when your app is in the foreground and a notification is received.
```js
LocalNotifications.addOnMessageReceivedCallback(
function (notification) {
console.log("ID: " + notification.id);
console.log("Title: " + notification.title);
console.log("Body: " + notification.body);
}
).then(
function() {
console.log("Listener added");
}
)
```
### getScheduledIds
If you want to know the ID's of all notifications which have been scheduled, do this:
Note that all functions have an error handler as well (see `schedule`), but to keep things readable we won't repeat ourselves.
```js
LocalNotifications.getScheduledIds().then(
function(ids) {
console.log("ID's: " + ids);
}
)
```
### cancel
If you want to cancel a previously scheduled notification (and you know its ID), you can cancel it:
```js
LocalNotifications.cancel(5 /* the ID */).then(
function(foundAndCanceled) {
if (foundAndCanceled) {
console.log("OK, it's gone!");
} else {
console.log("No ID 5 was scheduled");
}
}
)
```
### cancelAll
If you just want to cancel all previously scheduled notifications, do this:
```js
LocalNotifications.cancelAll();
```
### requestPermission
On Android you don't need permission, but on iOS you do. Android will simply return true.
If the `requestPermission` or `schedule` function previously ran the user has already been prompted to grant permission.
If the user granted permission this function returns `true`, but if he denied permission this function will return `false`,
since an iOS can only request permission once. In which case the user needs to go to the iOS settings app and manually
enable permissions for your app.
```js
LocalNotifications.requestPermission().then(
function(granted) {
console.log("Permission granted? " + granted);
}
)
```
### hasPermission
On Android you don't need permission, but on iOS you do. Android will simply return true.
If the `requestPermission` or `schedule` functions previously ran you may want to check whether or not the user granted permission:
```js
LocalNotifications.hasPermission().then(
function(granted) {
console.log("Permission granted? " + granted);
}
)
```
================================================
FILE: demo/app/App_Resources/Android/app.gradle
================================================
// Add your native dependencies here:
// Uncomment to add recyclerview-v7 dependency
//dependencies {
// compile 'com.android.support:recyclerview-v7:+'
//}
android {
defaultConfig {
generatedDensities = []
applicationId = "org.nativescript.plugindemo.localnotifications"
}
aaptOptions {
additionalParameters "--no-version-vectors"
}
}
================================================
FILE: demo/app/App_Resources/Android/src/main/AndroidManifest.xml
================================================
================================================
FILE: demo/app/App_Resources/Android/src/main/res/drawable-nodpi/splash_screen.xml
================================================
-
-
================================================
FILE: demo/app/App_Resources/Android/src/main/res/values/colors.xml
================================================
#F5F5F5
#757575
#33B5E5
#272734
================================================
FILE: demo/app/App_Resources/Android/src/main/res/values/styles.xml
================================================
================================================
FILE: demo/app/App_Resources/Android/src/main/res/values-v21/colors.xml
================================================
#3d5afe
================================================
FILE: demo/app/App_Resources/Android/src/main/res/values-v21/styles.xml
================================================
================================================
FILE: demo/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/Contents.json
================================================
{
"images" : [
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "icon-29.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "icon-29@2x.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "icon-29@3x.png",
"scale" : "3x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "icon-40@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "icon-40@3x.png",
"scale" : "3x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "icon-60@2x.png",
"scale" : "2x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "icon-60@3x.png",
"scale" : "3x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "icon-29.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "icon-29@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "icon-40.png",
"scale" : "1x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "icon-40@2x.png",
"scale" : "2x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "icon-76.png",
"scale" : "1x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "icon-76@2x.png",
"scale" : "2x"
},
{
"size" : "83.5x83.5",
"idiom" : "ipad",
"filename" : "icon-83.5@2x.png",
"scale" : "2x"
},
{
"size" : "1024x1024",
"idiom" : "ios-marketing",
"filename" : "icon-1024.png",
"scale" : "1x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: demo/app/App_Resources/iOS/Assets.xcassets/Contents.json
================================================
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: demo/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Contents.json
================================================
{
"images" : [
{
"extent" : "full-screen",
"idiom" : "iphone",
"subtype" : "2436h",
"filename" : "Default-1125h.png",
"minimum-system-version" : "11.0",
"orientation" : "portrait",
"scale" : "3x"
},
{
"orientation" : "landscape",
"idiom" : "iphone",
"extent" : "full-screen",
"filename" : "Default-Landscape-X.png",
"minimum-system-version" : "11.0",
"subtype" : "2436h",
"scale" : "3x"
},
{
"extent" : "full-screen",
"idiom" : "iphone",
"subtype" : "736h",
"filename" : "Default-736h@3x.png",
"minimum-system-version" : "8.0",
"orientation" : "portrait",
"scale" : "3x"
},
{
"extent" : "full-screen",
"idiom" : "iphone",
"subtype" : "736h",
"filename" : "Default-Landscape@3x.png",
"minimum-system-version" : "8.0",
"orientation" : "landscape",
"scale" : "3x"
},
{
"extent" : "full-screen",
"idiom" : "iphone",
"subtype" : "667h",
"filename" : "Default-667h@2x.png",
"minimum-system-version" : "8.0",
"orientation" : "portrait",
"scale" : "2x"
},
{
"orientation" : "portrait",
"idiom" : "iphone",
"filename" : "Default@2x.png",
"extent" : "full-screen",
"minimum-system-version" : "7.0",
"scale" : "2x"
},
{
"extent" : "full-screen",
"idiom" : "iphone",
"subtype" : "retina4",
"filename" : "Default-568h@2x.png",
"minimum-system-version" : "7.0",
"orientation" : "portrait",
"scale" : "2x"
},
{
"orientation" : "portrait",
"idiom" : "ipad",
"filename" : "Default-Portrait.png",
"extent" : "full-screen",
"minimum-system-version" : "7.0",
"scale" : "1x"
},
{
"orientation" : "landscape",
"idiom" : "ipad",
"filename" : "Default-Landscape.png",
"extent" : "full-screen",
"minimum-system-version" : "7.0",
"scale" : "1x"
},
{
"orientation" : "portrait",
"idiom" : "ipad",
"filename" : "Default-Portrait@2x.png",
"extent" : "full-screen",
"minimum-system-version" : "7.0",
"scale" : "2x"
},
{
"orientation" : "landscape",
"idiom" : "ipad",
"filename" : "Default-Landscape@2x.png",
"extent" : "full-screen",
"minimum-system-version" : "7.0",
"scale" : "2x"
},
{
"orientation" : "portrait",
"idiom" : "iphone",
"filename" : "Default.png",
"extent" : "full-screen",
"scale" : "1x"
},
{
"orientation" : "portrait",
"idiom" : "iphone",
"filename" : "Default@2x.png",
"extent" : "full-screen",
"scale" : "2x"
},
{
"orientation" : "portrait",
"idiom" : "iphone",
"filename" : "Default-568h@2x.png",
"extent" : "full-screen",
"subtype" : "retina4",
"scale" : "2x"
},
{
"orientation" : "portrait",
"idiom" : "ipad",
"extent" : "to-status-bar",
"scale" : "1x"
},
{
"orientation" : "portrait",
"idiom" : "ipad",
"filename" : "Default-Portrait.png",
"extent" : "full-screen",
"scale" : "1x"
},
{
"orientation" : "landscape",
"idiom" : "ipad",
"extent" : "to-status-bar",
"scale" : "1x"
},
{
"orientation" : "landscape",
"idiom" : "ipad",
"filename" : "Default-Landscape.png",
"extent" : "full-screen",
"scale" : "1x"
},
{
"orientation" : "portrait",
"idiom" : "ipad",
"extent" : "to-status-bar",
"scale" : "2x"
},
{
"orientation" : "portrait",
"idiom" : "ipad",
"filename" : "Default-Portrait@2x.png",
"extent" : "full-screen",
"scale" : "2x"
},
{
"orientation" : "landscape",
"idiom" : "ipad",
"extent" : "to-status-bar",
"scale" : "2x"
},
{
"orientation" : "landscape",
"idiom" : "ipad",
"filename" : "Default-Landscape@2x.png",
"extent" : "full-screen",
"scale" : "2x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: demo/app/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"filename" : "LaunchScreen-AspectFill.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "LaunchScreen-AspectFill@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: demo/app/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"filename" : "LaunchScreen-Center.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "LaunchScreen-Center@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: demo/app/App_Resources/iOS/Info.plist
================================================
CFBundleDevelopmentRegion
en
CFBundleDisplayName
${PRODUCT_NAME}
CFBundleExecutable
${EXECUTABLE_NAME}
CFBundleInfoDictionaryVersion
6.0
CFBundleName
${PRODUCT_NAME}
CFBundlePackageType
APPL
CFBundleShortVersionString
1.0
CFBundleSignature
????
CFBundleVersion
1.0
LSRequiresIPhoneOS
UILaunchStoryboardName
LaunchScreen
UIRequiresFullScreen
UIRequiredDeviceCapabilities
armv7
UISupportedInterfaceOrientations
UIInterfaceOrientationPortrait
UIInterfaceOrientationLandscapeLeft
UIInterfaceOrientationLandscapeRight
UISupportedInterfaceOrientations~ipad
UIInterfaceOrientationPortrait
UIInterfaceOrientationPortraitUpsideDown
UIInterfaceOrientationLandscapeLeft
UIInterfaceOrientationLandscapeRight
================================================
FILE: demo/app/App_Resources/iOS/LaunchScreen.storyboard
================================================
================================================
FILE: demo/app/App_Resources/iOS/build.xcconfig
================================================
// You can add custom settings here
// for example you can uncomment the following line to force distribution code signing
// CODE_SIGN_IDENTITY = iPhone Distribution
// To build for device with XCode 8 you need to specify your development team. More info: https://developer.apple.com/library/prerelease/content/releasenotes/DeveloperTools/RN-Xcode/Introduction.html
// DEVELOPMENT_TEAM = YOUR_TEAM_ID;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
================================================
FILE: demo/app/README.md
================================================
# NativeScript TypeScript Template
This template creates a NativeScript app with the NativeScript hello world example,
however, in this template the example is built with TypeScript.
You can create a new app that uses this template with either the `--template` option.
```
tns create my-app-name --template tns-template-hello-world-ts
```
Or the `--tsc` shorthand.
```
tns create my-app-name --tsc
```
> Note: Both commands will create a new NativeScript app that uses the latest version of this template published to [npm] (https://www.npmjs.com/package/tns-template-hello-world-ts).
If you want to create a new app that uses the source of the template from the `master` branch, you can execute the following:
```
tns create my-app-name --template https://github.com/NativeScript/template-hello-world-ts.git#master
```
================================================
FILE: demo/app/app-root.xml
================================================
================================================
FILE: demo/app/app.css
================================================
@import '~nativescript-theme-core/css/core.light.css';
page {
background-color: #F4F4F4;
}
.tab-content {
color: #808080;
padding: 18;
}
.title {
font-size: 18;
margin: 0 0 8 0;
color: #3c3c3c;
/*horizontal-align: center;*/
}
label {
font-size: 16;
}
Label.notification,
Label.hint {
font-size: 14;
margin: 8;
}
button {
background-color: #E0A458;
padding: 8;
margin: 8;
font-size: 14;
border-radius: 4;
}
.button {
color: #FFFFFF;
}
.button-positive {
background-color: #90A959;
}
.button-danger {
background-color: #A63D40;
}
.button-neutral {
background-color: #6494AA;
}
================================================
FILE: demo/app/app.ts
================================================
import "./bundle-config";
import * as application from "tns-core-modules/application";
// Add this so for iOS 10+ we can do some wiring (set the iOS UNUserNotificationCenter delegate, to be precise).
// Not needed if your app loads the plugin on startup anyway.
// You'll know you need this if on iOS 10+ notifications are not received by your app.
require ("nativescript-local-notifications");
application.run({moduleName: "app-root"});
================================================
FILE: demo/app/bundle-config.ts
================================================
if ((global).TNS_WEBPACK) {
// Register tns-core-modules UI framework modules
require("bundle-entry-points");
// Register application modules
// This will register each `root`, `page`, `fragment` postfixed xml, css, js, ts, scss file in the app/ folder
const context = (require).context("~/", true, /(root|page|fragment)\.(xml|css|js|ts|scss|less|sass)$/);
global.registerWebpackModules(context);
}
================================================
FILE: demo/app/main-page.ts
================================================
import { EventData } from "tns-core-modules/data/observable";
import { Page } from "tns-core-modules/ui/page";
import { HelloWorldModel } from "./main-view-model";
export function navigatingTo(args: EventData) {
const page = args.object;
page.bindingContext = new HelloWorldModel();
}
================================================
FILE: demo/app/main-page.xml
================================================
================================================
FILE: demo/app/main-view-model.ts
================================================
import { Observable } from "tns-core-modules/data/observable";
import { alert } from "tns-core-modules/ui/dialogs";
import { LocalNotifications } from "nativescript-local-notifications";
import { Color } from "tns-core-modules/color";
import { ScheduleOptions } from "../../src";
export class HelloWorldModel extends Observable {
public notification: string;
constructor() {
super();
LocalNotifications.addOnMessageReceivedCallback(notificationData => {
console.log("Notification received: " + JSON.stringify(notificationData));
this.set("notification", "Notification received: " + JSON.stringify(notificationData));
});
}
public doCheckHasPermission(): void {
LocalNotifications.hasPermission()
.then(granted => {
alert({
title: "Permission granted?",
message: granted ? "YES" : "NO",
okButtonText: "OK"
});
});
};
public doRequestPermission(): void {
LocalNotifications.requestPermission()
.then(granted => {
alert({
title: "Permission granted?",
message: granted ? "YES" : "NO",
okButtonText: "OK"
});
});
}
public doScheduleWithButtons(): void {
const options: Array = [
{
id: 1,
title: 'THE TITLE',
subtitle: 'The subtitle',
body: 'The big body. The big body. The big body. The big body. The big body. The big body. The big body. The big body. The big fat body. The big fat body. The big fat body. The big fat body. The big fat body. The big fat body. The big fat body.',
bigTextStyle: true, // Allow more than 1 row of the 'body' text
sound: "customsound",
color: new Color("green"),
forceShowWhenInForeground: true,
channel: "My Awesome Channel", // not that this is revealed in the notification tray when you longpress it on Android
ticker: "Special ticker text (Android only)",
at: new Date(new Date().getTime() + (10 * 1000)),
notificationLed: true,
actions: [
{
id: "yes",
type: "button",
title: "Yes (and launch app)",
launch: true
},
{
id: "no",
type: "button",
title: "No",
launch: false
}
]
},
{
title: 'Generated ID',
at: new Date(new Date().getTime() + (5 * 1000))
}
];
LocalNotifications.schedule(options)
.then((scheduledIds: Array) => {
alert({
title: "Notification scheduled",
message: `ID: ${JSON.stringify(scheduledIds)}`,
okButtonText: "OK, thanks"
});
})
.catch(error => console.log("doSchedule error: " + error))
};
public doScheduleNoSound(): void {
LocalNotifications.schedule(
[{
id: 2,
title: "Red Alert",
subtitle: "Remember this game?",
icon: 'res://ic_stat_notify',
color: new Color("red"),
image: "https://images-na.ssl-images-amazon.com/images/I/61mx-VbrS0L.jpg",
thumbnail: "https://2.bp.blogspot.com/-H_SZ3nAmNsI/VrJeARpbuSI/AAAAAAAABfc/szsV7_F609k/s200/emoji.jpg",
forceShowWhenInForeground: false, // default
body: "RTS FTW!",
sound: null,
at: new Date(new Date().getTime() + 10 * 1000)
}])
.then(() => {
alert({
title: "Notification scheduled",
message: 'ID: 2',
okButtonText: "OK, thanks"
});
})
.catch(error => console.log("doScheduleSilent error: " + error));
}
public doScheduleAndSetBadgeNumber(): void {
LocalNotifications.schedule(
[{
id: 3,
title: 'Hi',
subtitle: 'Whatsubtitle',
image: "https://2.bp.blogspot.com/-H_SZ3nAmNsI/VrJeARpbuSI/AAAAAAAABfc/szsV7_F609k/s200/emoji.jpg",
thumbnail: true,
// body: 'You should see a \'3\' somewhere',
at: new Date(new Date().getTime() + 10 * 1000),
badge: 3
}])
.then(() => {
alert({
title: "Notification scheduled",
message: 'ID: 3',
okButtonText: "OK, thanks"
});
})
.catch(error => console.log("doScheduleAndSetBadgeNumber error: " + error));
}
public doScheduleId4GroupedWithCustomIcon(): void {
LocalNotifications.schedule(
[{
id: 4,
title: 'Custom icon',
body: 'Check it out!',
thumbnail: "https://2.bp.blogspot.com/-H_SZ3nAmNsI/VrJeARpbuSI/AAAAAAAABfc/szsV7_F609k/s200/emoji.jpg",
icon: 'res://ic_stat_smiley',
at: new Date(new Date().getTime() + 10 * 1000),
groupedMessages: ["The first", "Second", "Keep going", "one more..", "OK Stop"], // android only
groupSummary: "Summary of the grouped messages above" // android only
}])
.then(() => {
alert({
title: "Notification scheduled",
message: 'ID: 4',
okButtonText: "OK, thanks"
});
})
.catch(error => console.log("doScheduleId4WithCustomIcon error: " + error));
}
public doScheduleId5WithInput(): void {
LocalNotifications.schedule(
[{
id: 5,
thumbnail: true,
title: 'Richard wants your input',
body: '"Hey man, what do you think of the new design?" (swipe down to reply, or tap to open the app)',
forceShowWhenInForeground: true,
at: new Date(new Date().getTime() + 10 * 1000),
actions: [
{
id: "input-richard",
type: "input",
title: "Tap here to reply",
placeholder: "Type to reply..",
submitLabel: "Reply",
launch: true,
editable: true,
// choices: ["Red", "Yellow", "Green"] // TODO Android only, but yet to see it in action
}
]
}])
.then(() => {
alert({
title: "Notification scheduled",
message: "ID: 5",
okButtonText: "OK, thanks"
});
})
.catch(error => console.log("doScheduleId5WithInput error: " + error));
}
public doScheduleEveryMinute(): void {
LocalNotifications.schedule(
[{
id: 6,
title: 'Every minute!',
interval: 'minute', // some constant
body: 'I\'m repeating until cancelled',
icon: 'res://ic_stat_smiley',
thumbnail: "res://ic_stat_notify",
forceShowWhenInForeground: true,
at: new Date(new Date().getTime() + 10 * 1000)
}])
.then(() => {
alert({
title: "Notification scheduled",
message: 'ID: 6, repeating',
okButtonText: "OK, thanks"
});
})
.catch(error => console.log("doScheduleEveryMinute error: " + error));
}
public doScheduleMultiple(): void {
LocalNotifications.schedule(
[
{
id: 7,
title: 'Multiple - id 7',
icon: 'res://ic_stat_smiley',
at: new Date(new Date().getTime() + 5 * 1000)
},
{
id: 8,
title: 'Multiple - id 8',
icon: 'res://ic_stat_notify',
at: new Date(new Date().getTime() + 6 * 1000)
},
{
id: 9,
title: 'Multiple - id 9',
icon: 'res://ic_stat_smiley',
at: new Date(new Date().getTime() + 7 * 1000)
},
{
id: 10,
title: 'Multiple - id 10',
icon: 'res://ic_stat_smiley',
at: new Date(new Date().getTime() + 8 * 1000)
},
])
.then(() => {
alert({
title: "Notification 7-10 scheduled",
okButtonText: "OK, thanks"
});
})
.catch(error => console.log("doScheduleMultiple error: " + error));
}
public doGetScheduledIds(): void {
LocalNotifications.getScheduledIds()
.then(ids => {
alert({
title: "Scheduled ID's",
message: 'ID\'s: ' + ids,
okButtonText: "Sweet!"
});
})
.catch(error => console.log("doGetScheduledIds error: " + error));
}
public doCancelAll(): void {
LocalNotifications.cancelAll()
.then(() => {
alert({
title: "All canceled",
okButtonText: "Awesome!"
});
})
.catch(error => console.log("doCancelAll error: " + error));
}
public doCancelId6(): void {
LocalNotifications.cancel(6)
.then(foundAndCanceled => {
if (foundAndCanceled) {
alert({
title: "ID 6 canceled",
okButtonText: "OK, coolness"
});
} else {
alert({
title: "No ID 6 was scheduled",
okButtonText: "OK, woops"
});
}
})
.catch(error => console.log("doCancelId6 error: " + error));
}
}
================================================
FILE: demo/app/package.json
================================================
{
"android": {
"v8Flags": "--expose_gc",
"markingMode": "none"
},
"main": "app.js",
"name": "tns-template-hello-world-ts",
"version": "4.1.0"
}
================================================
FILE: demo/package.json
================================================
{
"description": "NativeScript Application",
"license": "SEE LICENSE IN ",
"readme": "NativeScript Application",
"repository": "",
"nativescript": {
"id": "org.nativescript.plugindemo.localnotifications",
"tns-ios": {
"version": "6.0.1"
},
"tns-android": {
"version": "6.0.0"
}
},
"dependencies": {
"nativescript-local-notifications": "file:../src",
"nativescript-theme-core": "~1.0.6",
"tns-core-modules": "~6.0.0"
},
"devDependencies": {
"babel-traverse": "6.26.0",
"babel-types": "6.26.0",
"babylon": "6.18.0",
"lazy": "1.0.11",
"nativescript-dev-webpack": "1.0.1",
"tns-platform-declarations": "~6.0.0",
"typescript": "3.4.5"
},
"scripts": {
"build.plugin": "cd ../src && npm run build"
}
}
================================================
FILE: demo/references.d.ts
================================================
///
///
///
================================================
FILE: demo/tsconfig.json
================================================
{
"compilerOptions": {
"target": "es6",
"module": "commonjs",
"declaration": false,
"removeComments": true,
"noLib": false,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"pretty": true,
"allowUnreachableCode": false,
"allowUnusedLabels": false,
"noEmitHelpers": true,
"noEmitOnError": false,
"noImplicitAny": false,
"noImplicitReturns": true,
"noImplicitUseStrict": false,
"noFallthroughCasesInSwitch": true,
"typeRoots": [
"./node_modules/@types",
"./node_modules"
],
"types": [],
"lib": [
"es6",
"dom"
],
"baseUrl": ".",
"paths": {
"~/*": [
"app/*"
],
"*": [
"./node_modules/tns-core-modules/*",
"./node_modules/*"
]
}
},
"exclude": [
"node_modules",
"platforms"
],
"compileOnSave": false
}
================================================
FILE: demo/tsconfig.tns.json
================================================
{
"extends": "./tsconfig",
"compilerOptions": {
"module": "es2015",
"moduleResolution": "node"
}
}
================================================
FILE: demo-ng/App_Resources/Android/app.gradle
================================================
// Add your native dependencies here:
// Uncomment to add recyclerview-v7 dependency
//dependencies {
// implementation 'com.android.support:recyclerview-v7:+'
//}
// If you want to add something to be applied before applying plugins' include.gradle files
// e.g. project.ext.googlePlayServicesVersion = "15.0.1"
// create a file named before-plugins.gradle in the current directory and place it there
android {
defaultConfig {
generatedDensities = []
}
aaptOptions {
additionalParameters "--no-version-vectors"
}
}
================================================
FILE: demo-ng/App_Resources/Android/src/main/AndroidManifest.xml
================================================
================================================
FILE: demo-ng/App_Resources/Android/src/main/res/drawable-nodpi/splash_screen.xml
================================================
-
-
================================================
FILE: demo-ng/App_Resources/Android/src/main/res/values/colors.xml
================================================
#F5F5F5
#757575
#33B5E5
#272734
================================================
FILE: demo-ng/App_Resources/Android/src/main/res/values/styles.xml
================================================
================================================
FILE: demo-ng/App_Resources/Android/src/main/res/values-v21/colors.xml
================================================
#3d5afe
================================================
FILE: demo-ng/App_Resources/Android/src/main/res/values-v21/styles.xml
================================================
================================================
FILE: demo-ng/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/Contents.json
================================================
{
"images" : [
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "icon-20@2x.png",
"scale" : "2x"
},
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "icon-20@3x.png",
"scale" : "3x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "icon-29.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "icon-29@2x.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "icon-29@3x.png",
"scale" : "3x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "icon-40@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "icon-40@3x.png",
"scale" : "3x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "icon-60@2x.png",
"scale" : "2x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "icon-60@3x.png",
"scale" : "3x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "icon-20.png",
"scale" : "1x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "icon-20@2x.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "icon-29.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "icon-29@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "icon-40.png",
"scale" : "1x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "icon-40@2x.png",
"scale" : "2x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "icon-76.png",
"scale" : "1x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "icon-76@2x.png",
"scale" : "2x"
},
{
"size" : "83.5x83.5",
"idiom" : "ipad",
"filename" : "icon-83.5@2x.png",
"scale" : "2x"
},
{
"size" : "1024x1024",
"idiom" : "ios-marketing",
"filename" : "icon-1024.png",
"scale" : "1x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: demo-ng/App_Resources/iOS/Assets.xcassets/Contents.json
================================================
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: demo-ng/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Contents.json
================================================
{
"images" : [
{
"extent" : "full-screen",
"idiom" : "iphone",
"subtype" : "2688h",
"filename" : "Phone XS Max - Portarit iOS 12.png",
"minimum-system-version" : "12.0",
"orientation" : "portrait",
"scale" : "3x"
},
{
"extent" : "full-screen",
"idiom" : "iphone",
"subtype" : "2688h",
"filename" : "iPhone XS Max – Landscape iOS 12.png",
"minimum-system-version" : "12.0",
"orientation" : "landscape",
"scale" : "3x"
},
{
"extent" : "full-screen",
"idiom" : "iphone",
"subtype" : "1792h",
"filename" : "iPhone XR - Portarit iOS 12.png",
"minimum-system-version" : "12.0",
"orientation" : "portrait",
"scale" : "2x"
},
{
"extent" : "full-screen",
"idiom" : "iphone",
"subtype" : "1792h",
"filename" : "iPhone XR - Landscape iOS 12.png",
"minimum-system-version" : "12.0",
"orientation" : "landscape",
"scale" : "2x"
},
{
"extent" : "full-screen",
"idiom" : "iphone",
"subtype" : "2436h",
"filename" : "Default-1125h.png",
"minimum-system-version" : "11.0",
"orientation" : "portrait",
"scale" : "3x"
},
{
"extent" : "full-screen",
"idiom" : "iphone",
"subtype" : "2436h",
"filename" : "Default-Landscape-X.png",
"minimum-system-version" : "11.0",
"orientation" : "landscape",
"scale" : "3x"
},
{
"extent" : "full-screen",
"idiom" : "iphone",
"subtype" : "736h",
"filename" : "Default-736h@3x.png",
"minimum-system-version" : "8.0",
"orientation" : "portrait",
"scale" : "3x"
},
{
"extent" : "full-screen",
"idiom" : "iphone",
"subtype" : "736h",
"filename" : "Default-Landscape@3x.png",
"minimum-system-version" : "8.0",
"orientation" : "landscape",
"scale" : "3x"
},
{
"extent" : "full-screen",
"idiom" : "iphone",
"subtype" : "667h",
"filename" : "Default-667h@2x.png",
"minimum-system-version" : "8.0",
"orientation" : "portrait",
"scale" : "2x"
},
{
"orientation" : "portrait",
"idiom" : "iphone",
"filename" : "Default@2x.png",
"extent" : "full-screen",
"minimum-system-version" : "7.0",
"scale" : "2x"
},
{
"extent" : "full-screen",
"idiom" : "iphone",
"subtype" : "retina4",
"filename" : "Default-568h@2x.png",
"minimum-system-version" : "7.0",
"orientation" : "portrait",
"scale" : "2x"
},
{
"orientation" : "portrait",
"idiom" : "ipad",
"filename" : "Default-Portrait.png",
"extent" : "full-screen",
"minimum-system-version" : "7.0",
"scale" : "1x"
},
{
"orientation" : "landscape",
"idiom" : "ipad",
"filename" : "Default-Landscape.png",
"extent" : "full-screen",
"minimum-system-version" : "7.0",
"scale" : "1x"
},
{
"orientation" : "portrait",
"idiom" : "ipad",
"filename" : "Default-Portrait@2x.png",
"extent" : "full-screen",
"minimum-system-version" : "7.0",
"scale" : "2x"
},
{
"orientation" : "landscape",
"idiom" : "ipad",
"filename" : "Default-Landscape@2x.png",
"extent" : "full-screen",
"minimum-system-version" : "7.0",
"scale" : "2x"
},
{
"orientation" : "portrait",
"idiom" : "iphone",
"filename" : "Default.png",
"extent" : "full-screen",
"scale" : "1x"
},
{
"orientation" : "portrait",
"idiom" : "iphone",
"filename" : "Default@2x.png",
"extent" : "full-screen",
"scale" : "2x"
},
{
"orientation" : "portrait",
"idiom" : "iphone",
"filename" : "Default-568h@2x.png",
"extent" : "full-screen",
"subtype" : "retina4",
"scale" : "2x"
},
{
"orientation" : "portrait",
"idiom" : "ipad",
"extent" : "to-status-bar",
"scale" : "1x"
},
{
"orientation" : "portrait",
"idiom" : "ipad",
"filename" : "Default-Portrait.png",
"extent" : "full-screen",
"scale" : "1x"
},
{
"orientation" : "landscape",
"idiom" : "ipad",
"extent" : "to-status-bar",
"scale" : "1x"
},
{
"orientation" : "landscape",
"idiom" : "ipad",
"filename" : "Default-Landscape.png",
"extent" : "full-screen",
"scale" : "1x"
},
{
"orientation" : "portrait",
"idiom" : "ipad",
"extent" : "to-status-bar",
"scale" : "2x"
},
{
"orientation" : "portrait",
"idiom" : "ipad",
"filename" : "Default-Portrait@2x.png",
"extent" : "full-screen",
"scale" : "2x"
},
{
"orientation" : "landscape",
"idiom" : "ipad",
"extent" : "to-status-bar",
"scale" : "2x"
},
{
"orientation" : "landscape",
"idiom" : "ipad",
"filename" : "Default-Landscape@2x.png",
"extent" : "full-screen",
"scale" : "2x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: demo-ng/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"filename" : "LaunchScreen-AspectFill.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "LaunchScreen-AspectFill@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "LaunchScree.AspectFill@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: demo-ng/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"filename" : "LaunchScreen-Center.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "LaunchScreen-Center@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "LaunchScreen.Center@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: demo-ng/App_Resources/iOS/Info.plist
================================================
CFBundleDevelopmentRegion
en
CFBundleDisplayName
${PRODUCT_NAME}
CFBundleExecutable
${EXECUTABLE_NAME}
CFBundleInfoDictionaryVersion
6.0
CFBundleName
${PRODUCT_NAME}
CFBundlePackageType
APPL
CFBundleShortVersionString
1.0
CFBundleSignature
????
CFBundleVersion
1.0
LSRequiresIPhoneOS
UILaunchStoryboardName
LaunchScreen
UIRequiresFullScreen
UIRequiredDeviceCapabilities
armv7
UISupportedInterfaceOrientations
UIInterfaceOrientationPortrait
UIInterfaceOrientationLandscapeLeft
UIInterfaceOrientationLandscapeRight
UISupportedInterfaceOrientations~ipad
UIInterfaceOrientationPortrait
UIInterfaceOrientationPortraitUpsideDown
UIInterfaceOrientationLandscapeLeft
UIInterfaceOrientationLandscapeRight
================================================
FILE: demo-ng/App_Resources/iOS/LaunchScreen.storyboard
================================================
================================================
FILE: demo-ng/App_Resources/iOS/build.xcconfig
================================================
// You can add custom settings here
// for example you can uncomment the following line to force distribution code signing
// CODE_SIGN_IDENTITY = iPhone Distribution
// To build for device with Xcode 8 you need to specify your development team. More info: https://developer.apple.com/library/prerelease/content/releasenotes/DeveloperTools/RN-Xcode/Introduction.html
// DEVELOPMENT_TEAM = YOUR_TEAM_ID;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
================================================
FILE: demo-ng/README.md
================================================
# NativeScript Angular Template
This template creates a "Hello, world" NativeScript app using TypeScript and Angular.
You can create a new app that uses this template with either the `--template` option.
```
tns create my-app-name --template tns-template-hello-world-ng
```
Or the `--ng` shorthand.
```
tns create my-app-name --ng
```
> Note: Both commands will create a new NativeScript app that uses the latest version of this template published to [npm] (https://www.npmjs.com/package/tns-template-hello-world-ng).
If you want to create a new app that uses the source of the template from the `master` branch, you can execute the following:
```
tns create my-app-name --template https://github.com/NativeScript/template-hello-world-ng.git#master
```
**NB:** Please, have in mind that the master branch may refer to dependencies that are not on NPM yet!
# Issues
Issues related to `template-hello-world-ng` template should be logged in the https://github.com/NativeScript/NativeScript repository.
================================================
FILE: demo-ng/angular.json
================================================
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"cli": {
"defaultCollection": "@nativescript/schematics"
},
"projects": {
"hello-world": {
"root": "",
"sourceRoot": "src",
"projectType": "application",
"prefix": "ns"
}
},
"defaultProject": "hello-world"
}
================================================
FILE: demo-ng/nsconfig.json
================================================
{
"appResourcesPath": "App_Resources",
"appPath": "src"
}
================================================
FILE: demo-ng/package.json
================================================
{
"nativescript": {
"id": "org.nativescript.demong",
"tns-android": {
"version": "5.1.0"
},
"tns-ios": {
"version": "5.1.0"
}
},
"description": "NativeScript Application",
"license": "SEE LICENSE IN ",
"repository": "",
"dependencies": {
"@angular/animations": "~7.1.0",
"@angular/common": "~7.1.0",
"@angular/compiler": "~7.1.0",
"@angular/core": "~7.1.0",
"@angular/forms": "~7.1.0",
"@angular/http": "~7.1.0",
"@angular/platform-browser": "~7.1.0",
"@angular/platform-browser-dynamic": "~7.1.0",
"@angular/router": "~7.1.0",
"nativescript-angular": "~7.1.0",
"nativescript-local-notifications": "file:../src",
"nativescript-theme-core": "~1.0.4",
"reflect-metadata": "~0.1.8",
"rxjs": "~6.3.0",
"tns-core-modules": "~5.1.0",
"zone.js": "^0.8.26"
},
"devDependencies": {
"@nativescript/schematics": "~0.5.0",
"nativescript-dev-typescript": "libs",
"nativescript-dev-webpack": "~0.19.0",
"@angular/compiler-cli": "~7.1.0",
"@ngtools/webpack": "~7.1.0"
},
"readme": "NativeScript Application"
}
================================================
FILE: demo-ng/references.d.ts
================================================
///
///
///
================================================
FILE: demo-ng/src/app/app-routing.module.ts
================================================
import { NgModule } from "@angular/core";
import { Routes } from "@angular/router";
import { NativeScriptRouterModule } from "nativescript-angular/router";
import { ItemsComponent } from "./item/items.component";
const routes: Routes = [
{path: "", redirectTo: "/items", pathMatch: "full"},
{path: "items", component: ItemsComponent}
];
@NgModule({
imports: [NativeScriptRouterModule.forRoot(routes)],
exports: [NativeScriptRouterModule]
})
export class AppRoutingModule {
}
================================================
FILE: demo-ng/src/app/app.component.html
================================================
================================================
FILE: demo-ng/src/app/app.component.ts
================================================
import { Component } from "@angular/core";
@Component({
selector: "ns-app",
moduleId: module.id,
templateUrl: "./app.component.html",
})
export class AppComponent { }
================================================
FILE: demo-ng/src/app/app.module.ts
================================================
import { NgModule, NO_ERRORS_SCHEMA } from "@angular/core";
import { NativeScriptModule } from "nativescript-angular/nativescript.module";
import { AppRoutingModule } from "./app-routing.module";
import { AppComponent } from "./app.component";
import { ItemsComponent } from "./item/items.component";
// Uncomment and add to NgModule imports if you need to use two-way binding
// import { NativeScriptFormsModule } from "nativescript-angular/forms";
// Uncomment and add to NgModule imports if you need to use the HttpClient wrapper
// import { NativeScriptHttpClientModule } from "nativescript-angular/http-client";
@NgModule({
bootstrap: [
AppComponent
],
imports: [
NativeScriptModule,
AppRoutingModule
],
declarations: [
AppComponent,
ItemsComponent
],
providers: [],
schemas: [
NO_ERRORS_SCHEMA
]
})
export class AppModule {
}
================================================
FILE: demo-ng/src/app/item/items.component.html
================================================
================================================
FILE: demo-ng/src/app/item/items.component.ts
================================================
import { Component } from "@angular/core";
import { LocalNotifications } from "nativescript-local-notifications";
@Component({
selector: "ns-items",
moduleId: module.id,
templateUrl: "./items.component.html",
})
export class ItemsComponent {
constructor() {
LocalNotifications.addOnMessageReceivedCallback(notificationData => {
console.log("Notification received: " + JSON.stringify(notificationData));
});
}
schedule(): void {
LocalNotifications.schedule(
[{
id: 5,
thumbnail: true,
title: 'Richard wants your input',
body: '"Hey man, what do you think of the new design?" (swipe down to reply, or tap to open the app)',
forceShowWhenInForeground: true,
at: new Date(new Date().getTime() + 10 * 1000),
actions: [
{
id: "input-richard",
type: "input",
title: "Tap here to reply",
placeholder: "Type to reply..",
submitLabel: "Reply",
launch: true,
editable: true,
// choices: ["Red", "Yellow", "Green"] // TODO Android only, but yet to see it in action
}
]
}])
.then(() => {
alert({
title: "Notification scheduled",
message: "ID: 5",
okButtonText: "OK, thanks"
});
})
.catch(error => console.log("doScheduleId5WithInput error: " + error));
}
}
================================================
FILE: demo-ng/src/app.css
================================================
/*
In NativeScript, the app.css file is where you place CSS rules that
you would like to apply to your entire application. Check out
http://docs.nativescript.org/ui/styling for a full list of the CSS
selectors and properties you can use to style UI components.
/*
In many cases you may want to use the NativeScript core theme instead
of writing your own CSS rules. For a full list of class names in the theme
refer to http://docs.nativescript.org/ui/theme.
*/
@import '~nativescript-theme-core/css/core.light.css';
================================================
FILE: demo-ng/src/main.ts
================================================
// this import should be first in order to load some required settings (like globals and reflect-metadata)
import { platformNativeScriptDynamic } from "nativescript-angular/platform";
import { AppModule } from "./app/app.module";
// Add this so for iOS 10+ we can do some wiring (set the iOS UNUserNotificationCenter delegate, to be precise).
// Not needed if your app loads the plugin on startup anyway.
// You'll know you need this if on iOS 10+ notifications are not received by your app.
require ("nativescript-local-notifications");
// A traditional NativeScript application starts by initializing global objects, setting up global CSS rules, creating, and navigating to the main page.
// Angular applications need to take care of their own initialization: modules, components, directives, routes, DI providers.
// A NativeScript Angular app needs to make both paradigms work together, so we provide a wrapper platform object, platformNativeScriptDynamic,
// that sets up a NativeScript application and can bootstrap the Angular framework.
platformNativeScriptDynamic().bootstrapModule(AppModule);
================================================
FILE: demo-ng/src/package.json
================================================
{
"main": "main.js",
"android": {
"v8Flags": "--expose_gc"
}
}
================================================
FILE: demo-ng/tsconfig.json
================================================
{
"compilerOptions": {
"module": "commonjs",
"target": "es5",
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"noEmitHelpers": true,
"noEmitOnError": true,
"lib": [
"es6",
"dom",
"es2015.iterable"
],
"baseUrl": ".",
"paths": {
"~/*": [
"src/*"
],
"*": [
"./node_modules/tns-core-modules/*",
"./node_modules/*"
]
}
},
"exclude": [
"node_modules",
"platforms"
]
}
================================================
FILE: demo-ng/tsconfig.tns.json
================================================
{
"extends": "./tsconfig",
"compilerOptions": {
"module": "es2015",
"moduleResolution": "node"
}
}
================================================
FILE: demo-vue/.gitignore
================================================
# JetBrains project files
.idea
# NPM
node_modules
# NativeScript application
hooks
platforms
================================================
FILE: demo-vue/README.md
================================================
# Local Notifications
> Vue demo app for the Local Notifications plugin
## Usage
``` bash
# Install dependencies
npm install
# Build for production
tns build --bundle
# Build, watch for changes and debug the application
tns debug --bundle
# Build, watch for changes and run the application
tns run --bundle
```
================================================
FILE: demo-vue/app/App_Resources/Android/app.gradle
================================================
// Add your native dependencies here:
android {
defaultConfig {
generatedDensities = []
applicationId = "org.nativescript.plugindemo.vue.localnotifications"
}
aaptOptions {
additionalParameters "--no-version-vectors"
}
}
================================================
FILE: demo-vue/app/App_Resources/Android/src/main/AndroidManifest.xml
================================================
================================================
FILE: demo-vue/app/App_Resources/Android/src/main/res/drawable-nodpi/splash_screen.xml
================================================
-
-
================================================
FILE: demo-vue/app/App_Resources/Android/src/main/res/values/colors.xml
================================================
#F5F5F5
#53ba82
#33B5E5
#272734
================================================
FILE: demo-vue/app/App_Resources/Android/src/main/res/values/strings.xml
================================================
Local Notifications
Local Notifications
================================================
FILE: demo-vue/app/App_Resources/Android/src/main/res/values/styles.xml
================================================
================================================
FILE: demo-vue/app/App_Resources/Android/src/main/res/values-v21/colors.xml
================================================
#3d5afe
================================================
FILE: demo-vue/app/App_Resources/Android/src/main/res/values-v21/strings.xml
================================================
Local Notifications
Local Notifications
================================================
FILE: demo-vue/app/App_Resources/Android/src/main/res/values-v21/styles.xml
================================================
================================================
FILE: demo-vue/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/Contents.json
================================================
{
"images" : [
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "icon-29.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "icon-29@2x.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "icon-29@3x.png",
"scale" : "3x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "icon-40@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "icon-40@3x.png",
"scale" : "3x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "icon-60@2x.png",
"scale" : "2x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "icon-60@3x.png",
"scale" : "3x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "icon-29.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "icon-29@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "icon-40.png",
"scale" : "1x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "icon-40@2x.png",
"scale" : "2x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "icon-76.png",
"scale" : "1x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "icon-76@2x.png",
"scale" : "2x"
},
{
"size" : "83.5x83.5",
"idiom" : "ipad",
"filename" : "icon-83.5@2x.png",
"scale" : "2x"
},
{
"size" : "1024x1024",
"idiom" : "ios-marketing",
"filename" : "icon-1024.png",
"scale" : "1x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: demo-vue/app/App_Resources/iOS/Assets.xcassets/Contents.json
================================================
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: demo-vue/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Contents.json
================================================
{
"images" : [
{
"extent" : "full-screen",
"idiom" : "iphone",
"subtype" : "2436h",
"filename" : "Default-1125h.png",
"minimum-system-version" : "11.0",
"orientation" : "portrait",
"scale" : "3x"
},
{
"orientation" : "landscape",
"idiom" : "iphone",
"extent" : "full-screen",
"filename" : "Default-Landscape-X.png",
"minimum-system-version" : "11.0",
"subtype" : "2436h",
"scale" : "3x"
},
{
"extent" : "full-screen",
"idiom" : "iphone",
"subtype" : "736h",
"filename" : "Default-736h@3x.png",
"minimum-system-version" : "8.0",
"orientation" : "portrait",
"scale" : "3x"
},
{
"extent" : "full-screen",
"idiom" : "iphone",
"subtype" : "736h",
"filename" : "Default-Landscape@3x.png",
"minimum-system-version" : "8.0",
"orientation" : "landscape",
"scale" : "3x"
},
{
"extent" : "full-screen",
"idiom" : "iphone",
"subtype" : "667h",
"filename" : "Default-667h@2x.png",
"minimum-system-version" : "8.0",
"orientation" : "portrait",
"scale" : "2x"
},
{
"orientation" : "portrait",
"idiom" : "iphone",
"filename" : "Default@2x.png",
"extent" : "full-screen",
"minimum-system-version" : "7.0",
"scale" : "2x"
},
{
"extent" : "full-screen",
"idiom" : "iphone",
"subtype" : "retina4",
"filename" : "Default-568h@2x.png",
"minimum-system-version" : "7.0",
"orientation" : "portrait",
"scale" : "2x"
},
{
"orientation" : "portrait",
"idiom" : "ipad",
"filename" : "Default-Portrait.png",
"extent" : "full-screen",
"minimum-system-version" : "7.0",
"scale" : "1x"
},
{
"orientation" : "landscape",
"idiom" : "ipad",
"filename" : "Default-Landscape.png",
"extent" : "full-screen",
"minimum-system-version" : "7.0",
"scale" : "1x"
},
{
"orientation" : "portrait",
"idiom" : "ipad",
"filename" : "Default-Portrait@2x.png",
"extent" : "full-screen",
"minimum-system-version" : "7.0",
"scale" : "2x"
},
{
"orientation" : "landscape",
"idiom" : "ipad",
"filename" : "Default-Landscape@2x.png",
"extent" : "full-screen",
"minimum-system-version" : "7.0",
"scale" : "2x"
},
{
"orientation" : "portrait",
"idiom" : "iphone",
"filename" : "Default.png",
"extent" : "full-screen",
"scale" : "1x"
},
{
"orientation" : "portrait",
"idiom" : "iphone",
"filename" : "Default@2x.png",
"extent" : "full-screen",
"scale" : "2x"
},
{
"orientation" : "portrait",
"idiom" : "iphone",
"filename" : "Default-568h@2x.png",
"extent" : "full-screen",
"subtype" : "retina4",
"scale" : "2x"
},
{
"orientation" : "portrait",
"idiom" : "ipad",
"extent" : "to-status-bar",
"scale" : "1x"
},
{
"orientation" : "portrait",
"idiom" : "ipad",
"filename" : "Default-Portrait.png",
"extent" : "full-screen",
"scale" : "1x"
},
{
"orientation" : "landscape",
"idiom" : "ipad",
"extent" : "to-status-bar",
"scale" : "1x"
},
{
"orientation" : "landscape",
"idiom" : "ipad",
"filename" : "Default-Landscape.png",
"extent" : "full-screen",
"scale" : "1x"
},
{
"orientation" : "portrait",
"idiom" : "ipad",
"extent" : "to-status-bar",
"scale" : "2x"
},
{
"orientation" : "portrait",
"idiom" : "ipad",
"filename" : "Default-Portrait@2x.png",
"extent" : "full-screen",
"scale" : "2x"
},
{
"orientation" : "landscape",
"idiom" : "ipad",
"extent" : "to-status-bar",
"scale" : "2x"
},
{
"orientation" : "landscape",
"idiom" : "ipad",
"filename" : "Default-Landscape@2x.png",
"extent" : "full-screen",
"scale" : "2x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: demo-vue/app/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"filename" : "LaunchScreen-AspectFill.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "LaunchScreen-AspectFill@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: demo-vue/app/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"filename" : "LaunchScreen-Center.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "LaunchScreen-Center@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: demo-vue/app/App_Resources/iOS/Info.plist
================================================
CFBundleDevelopmentRegion
en
CFBundleDisplayName
Local Notifications
CFBundleExecutable
${EXECUTABLE_NAME}
CFBundleInfoDictionaryVersion
6.0
CFBundleName
${PRODUCT_NAME}
CFBundlePackageType
APPL
CFBundleShortVersionString
1.0.0
CFBundleSignature
????
CFBundleVersion
1.0.0
LSRequiresIPhoneOS
UILaunchStoryboardName
LaunchScreen
UIRequiresFullScreen
UIRequiredDeviceCapabilities
armv7
UISupportedInterfaceOrientations
UIInterfaceOrientationPortrait
UIInterfaceOrientationLandscapeLeft
UIInterfaceOrientationLandscapeRight
UISupportedInterfaceOrientations~ipad
UIInterfaceOrientationPortrait
UIInterfaceOrientationPortraitUpsideDown
UIInterfaceOrientationLandscapeLeft
UIInterfaceOrientationLandscapeRight
================================================
FILE: demo-vue/app/App_Resources/iOS/LaunchScreen.storyboard
================================================
================================================
FILE: demo-vue/app/App_Resources/iOS/build.xcconfig
================================================
// You can add custom settings here
// for example you can uncomment the following line to force distribution code signing
// CODE_SIGN_IDENTITY = iPhone Distribution
// To build for device with Xcode 8 you need to specify your development team. More info: https://developer.apple.com/library/prerelease/content/releasenotes/DeveloperTools/RN-Xcode/Introduction.html
// DEVELOPMENT_TEAM = YOUR_TEAM_ID;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
================================================
FILE: demo-vue/app/app.scss
================================================
// NativeScript core theme
// @see https://docs.nativescript.org/ui/theme
@import '~nativescript-theme-core/scss/dark';
// Override variables here
@import '~nativescript-theme-core/scss/index';
// Global SCSS styling
// @see https://docs.nativescript.org/ui/styling
================================================
FILE: demo-vue/app/components/App.vue
================================================
================================================
FILE: demo-vue/app/fonts/.gitkeep
================================================
================================================
FILE: demo-vue/app/main.js
================================================
import Vue from 'nativescript-vue'
import App from './components/App'
require ("nativescript-local-notifications");
// Prints Vue logs when --env.production is *NOT* set while building
Vue.config.silent = (TNS_ENV === 'production')
new Vue({
render: h => h('frame', [h(App)])
}).$start()
================================================
FILE: demo-vue/app/package.json
================================================
{
"android": {
"v8Flags": "--expose_gc"
},
"main": "main",
"name": "demo-vue",
"version": "1.0.0"
}
================================================
FILE: demo-vue/package.json
================================================
{
"name": "demo-vue",
"version": "1.0.0",
"description": "Vue demo app for the Local Notifications plugin",
"author": "EddyVerbruggen ",
"license": "MIT",
"nativescript": {
"id": "org.nativescript.plugindemo.vue.localnotifications",
"tns-ios": {
"version": "5.1.0"
},
"tns-android": {
"version": "5.1.0"
}
},
"dependencies": {
"nativescript-local-notifications": "file:../src",
"nativescript-theme-core": "^1.0.4",
"nativescript-vue": "^2.0.0",
"tns-core-modules": "~5.1.0"
},
"devDependencies": {
"@babel/core": "^7.0.0",
"@babel/preset-env": "^7.0.0",
"babel-loader": "^8.0.2",
"babel-traverse": "6.26.0",
"babel-types": "6.26.0",
"babylon": "6.18.0",
"clean-webpack-plugin": "^0.1.19",
"copy-webpack-plugin": "^4.5.2",
"css-loader": "^1.0.0",
"lazy": "1.0.11",
"nativescript-dev-webpack": "next",
"nativescript-vue-template-compiler": "^2.0.0",
"nativescript-worker-loader": "~0.9.0",
"node-sass": "^4.9.2",
"sass-loader": "^7.1.0",
"terser-webpack-plugin": "^1.1.0",
"typescript": "~3.1.6",
"vue-loader": "^15.2.6",
"webpack": "^4.16.4",
"webpack-bundle-analyzer": "~3.6.0",
"webpack-cli": "^3.1.0"
}
}
================================================
FILE: native-src/android/.gitattributes
================================================
* -crlf
================================================
FILE: native-src/android/.gitignore
================================================
out/
.idea/
.gradle/
local.properties
build/
================================================
FILE: native-src/android/README.md
================================================
# Local Notifications Plugin library for NativeScript Android apps
## Building the framework
- Open this folder as "an existing project" in Android Studio
- Change anything needed
- In the Gradle build window run `app > Tasks > build > clean` and `app > Tasks > build > build`
- Copy the release .aar: from the plugin project root, run: `cp native-src/android/app/build/outputs/aar/app-release.aar src/platforms/android/`
================================================
FILE: native-src/android/android.iml
================================================
================================================
FILE: native-src/android/app/.gitignore
================================================
/build
================================================
FILE: native-src/android/app/app.iml
================================================
generateDebugSources
================================================
FILE: native-src/android/app/build.gradle
================================================
apply plugin: 'com.android.library'
android {
compileSdkVersion 28
buildToolsVersion "28.0.3"
defaultConfig {
minSdkVersion 17
targetSdkVersion 28
versionCode 2
versionName "1.1.1"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
}
================================================
FILE: native-src/android/app/proguard-rules.pro
================================================
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in C:\Users\gprodano\AppData\Local\Android\android-sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
================================================
FILE: native-src/android/app/src/main/AndroidManifest.xml
================================================
================================================
FILE: native-src/android/app/src/main/java/com/telerik/localnotifications/Action.java
================================================
package com.telerik.localnotifications;
import android.content.Context;
import androidx.core.app.RemoteInput;
import android.util.Log;
import org.json.JSONArray;
import org.json.JSONObject;
import static com.telerik.localnotifications.LocalNotificationsPlugin.TAG;
/**
* Holds the icon and title components that would be used in a
* NotificationCompat.Action object. Does not include the PendingIntent so
* that it may be generated each time the notification is built. Necessary to
* compensate for missing functionality in the support library.
*/
public final class Action {
// The id for the click action
public static final String CLICK_ACTION_ID = "default_action";
// The application context
private final Context context;
// The action spec
private final JSONObject options;
/**
* Structure to encapsulate a named action that can be shown as part of
* this notification.
*
* @param context The application context.
* @param options The action options.
*/
Action(Context context, JSONObject options) {
this.context = context;
this.options = options;
}
/**
* Gets the ID for the action.
*/
public String getId() {
return options.optString("id", getTitle());
}
/**
* Gets the Title for the action.
*/
public String getTitle() {
return options.optString("title", "Tap here");
}
/**
* Gets the icon for the action.
*/
public int getIcon() {
// TODO
return android.R.drawable.screen_background_dark;
/*
AssetUtil assets = AssetUtil.getInstance(context);
String resPath = options.optString("icon");
int resId = assets.getResId(resPath);
if (resId == 0) {
resId = android.R.drawable.screen_background_dark;
}
return resId;
*/
}
/**
* Gets the value of the launch flag.
*/
public boolean isLaunchingApp() {
return options.optBoolean("launch", true);
}
/**
* Gets the type for the action.
*/
public boolean isWithInput() {
String type = options.optString("type");
return "input".equals(type);
}
/**
* Gets the input config in case of the action is of type input.
*/
public RemoteInput getInput() {
return new RemoteInput.Builder(getId())
.setLabel(options.optString("placeholder"))
.setAllowFreeFormInput(options.optBoolean("editable", true))
.setChoices(getChoices())
.build();
}
/**
* List of possible choices for input actions.
*/
private String[] getChoices() {
JSONArray opts = options.optJSONArray("choices");
Log.d(TAG, "getChoices, opts: " + opts);
if (opts == null) {
return null;
}
String[] choices = new String[opts.length()];
for (int i = 0; i < choices.length; i++) {
choices[i] = opts.optString(i);
}
Log.d(TAG, "getChoices, choices: " + choices);
Log.d(TAG, "getChoices, choices.length: " + choices.length);
return choices;
}
}
================================================
FILE: native-src/android/app/src/main/java/com/telerik/localnotifications/ActionGroup.java
================================================
package com.telerik.localnotifications;
import android.content.Context;
import android.util.Log;
import org.json.JSONArray;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static android.os.Build.VERSION.SDK_INT;
import static android.os.Build.VERSION_CODES.N;
public final class ActionGroup {
// Saves all groups for later lookup.
private static final Map groups = new HashMap();
// The ID of the action group.
private final String id;
// List of actions
private final Action[] actions;
/**
* Lookup the action groups with the specified group id.
*
* @param id The ID of the action group to find.
* @return Null if no group was found.
*/
public static ActionGroup lookup(String id) {
return groups.get(id);
}
/**
* Register the action group for later lookup.
*
* @param group The action group to register.
*/
public static void register(ActionGroup group) {
groups.put(group.getId(), group);
}
/**
* Unregister the action group.
*
* @param id The id of the action group to remove.
*/
public static void unregister(String id) {
groups.remove(id);
}
/**
* Check if a action group with that id is registered.
*
* @param id The id of the action group to check for.
*/
public static boolean isRegistered(String id) {
return groups.containsKey(id);
}
/**
* Creates an action group by parsing the specified action specs.
*
* @param list The list of actions.
* @return A new action group.
*/
public static ActionGroup parse(Context context, JSONArray list) {
return parse(context, null, list);
}
/**
* Creates an action group by parsing the specified action specs.
*
* @param id The id for the action group.
* @param list The list of actions.
* @return A new action group.
*/
public static ActionGroup parse(Context context, String id, JSONArray list) {
List actions = new ArrayList(list.length());
for (int i = 0; i < list.length(); i++) {
JSONObject opts = list.optJSONObject(i);
String type = opts.optString("type", "button");
if (type.equals("input") && SDK_INT < N) {
Log.w("Action", "Type input is not supported");
continue;
}
if (!(type.equals("button") || type.equals("input"))) {
Log.w("Action", "Unknown type: " + type);
continue;
}
actions.add(new Action(context, opts));
}
return new ActionGroup(id, actions.toArray(new Action[actions.size()]));
}
/**
* Creates an action group.
*
* @param id The ID of the group.
* @param actions The list of actions.
*/
private ActionGroup(String id, Action[] actions) {
this.id = id;
this.actions = actions;
}
/**
* Gets the action group id.
*/
public String getId() {
return id;
}
/**
* Gets the action list.
*/
public Action[] getActions() {
return actions;
}
}
================================================
FILE: native-src/android/app/src/main/java/com/telerik/localnotifications/Builder.java
================================================
package com.telerik.localnotifications;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Color;
import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat;
import android.util.Log;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.concurrent.ExecutionException;
import static android.app.PendingIntent.FLAG_UPDATE_CURRENT;
public final class Builder {
public static final String NOTIFICATION_ID = "NOTIFICATION_ID";
private static final String TAG = "Builder";
private static final String DEFAULT_CHANNEL = "Notifications";
private static final int DEFAULT_NOTIFICATION_COLOR = Color.parseColor("#ffffffff");
private static final int DEFAULT_NOTIFICATION_LED_ON = 500;
private static final int DEFAULT_NOTIFICATION_LED_OFF = 2000;
// Methods to build notifications:
static Notification build(JSONObject options, Context context, int notificationID) {
// We use options.channel as both channel id and name. If not set, both default to DEFAULT_CHANNEL:
return build(options, context, notificationID, options.optString("channel", DEFAULT_CHANNEL));
}
static Notification build(JSONObject options, Context context, int notificationID, String channelID) {
// Set channel for Android 8+:
if (android.os.Build.VERSION.SDK_INT >= 26) {
final NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
if (notificationManager != null && notificationManager.getNotificationChannel(channelID) == null) {
NotificationChannel channel = new NotificationChannel(channelID, channelID, NotificationManager.IMPORTANCE_HIGH);
if (shouldEnableNotificationLed(options)) {
channel.enableLights(true);
channel.setLightColor(getLedColor(options));
}
notificationManager.createNotificationChannel(channel);
}
}
// Create the builder:
NotificationCompat.Builder builder = android.os.Build.VERSION.SDK_INT >= 26 ? new NotificationCompat.Builder(context, channelID) : new NotificationCompat.Builder(context);
builder
.setDefaults(0)
.setContentTitle(options.optString("title", null))
.setSubText(options.optString("subtitle", null))
.setContentText(options.optString("body", null))
.setSmallIcon(options.optInt("icon"))
.setAutoCancel(true) // Remove the notification from the status bar once tapped.
.setNumber(options.optInt("badge"))
.setColor(options.optInt("color"))
.setOngoing(options.optBoolean("ongoing"))
.setPriority(options.optInt("priority", options.optBoolean("forceShowWhenInForeground") ? 1 : 0))
.setTicker(options.optString("ticker", null)); // Let the OS handle the default value for the ticker.
final Object thumbnail = options.opt("thumbnail");
if (thumbnail instanceof String) {
builder.setLargeIcon(getBitmap(context, (String) thumbnail));
}
// TODO sound preference is not doing anything
// builder.setSound(options.has("sound") ? Uri.parse("android.resource://" + context.getPackageName() + "/raw/" + options.getString("sound")) : Uri.parse("android.resource://" + context.getPackageName() + "/raw/notify"))
if (options.has("sound")) {
builder.setSound(android.media.RingtoneManager.getDefaultUri(android.media.RingtoneManager.TYPE_NOTIFICATION));
}
applyNotificationLed(options, builder);
applyStyle(options, builder, context);
applyTapReceiver(options, builder, context, notificationID);
applyClearReceiver(builder, context, notificationID);
applyActions(options, builder, context, notificationID);
return builder.build();
}
// Notification styles:
private static void applyNotificationLed(JSONObject options, NotificationCompat.Builder builder) {
if (shouldEnableNotificationLed(options)) {
builder.setLights(getLedColor(options), DEFAULT_NOTIFICATION_LED_ON, DEFAULT_NOTIFICATION_LED_OFF);
}
}
private static void applyStyle(JSONObject options, NotificationCompat.Builder builder, Context context) {
if (options.has("groupedMessages")) {
applyGroup(options, builder);
} else if (options.optBoolean("bigTextStyle")) {
applyBigTextStyle(options, builder);
} else if (options.has("image")) {
applyImage(options, builder, context);
}
}
private static void applyImage(JSONObject options, NotificationCompat.Builder builder, Context context) {
Bitmap bitmap = getBitmap(context, options.optString("image", ""));
if (bitmap == null) {
return;
}
final NotificationCompat.BigPictureStyle bigPictureStyle = new NotificationCompat.BigPictureStyle().bigPicture(bitmap);
builder.setStyle(bigPictureStyle);
final Object thumbnail = options.opt("thumbnail");
if (Boolean.TRUE.equals(thumbnail)) {
builder.setLargeIcon(bitmap); // Set the thumbnail...
bigPictureStyle.bigLargeIcon(null); // ...which goes away when expanded.
}
}
private static void applyBigTextStyle(JSONObject options, NotificationCompat.Builder builder) {
// set big text style (adds an 'expansion arrow' to the notification)
if (options.optBoolean("bigTextStyle")) {
final NotificationCompat.BigTextStyle bigTextStyle = new NotificationCompat.BigTextStyle();
bigTextStyle.setBigContentTitle(options.optString("title"));
bigTextStyle.bigText(options.optString("body"));
builder.setStyle(bigTextStyle);
}
}
private static void applyGroup(JSONObject options, NotificationCompat.Builder builder) {
JSONArray groupedMessages = options.optJSONArray("groupedMessages");
if (groupedMessages == null) {
return;
}
final NotificationCompat.InboxStyle inboxStyle = new NotificationCompat.InboxStyle();
// Sets a title for the Inbox in expanded layout
// TODO: Is this needed? Should we add a different option for it (bigTitle)?
inboxStyle.setBigContentTitle(options.optString("title", null));
inboxStyle.setSummaryText(options.optString("groupSummary", null));
int messagesToDisplay = Math.min(groupedMessages.length(), 5);
for (int i = 0; i < messagesToDisplay; ++i) {
try {
inboxStyle.addLine(groupedMessages.getString(i));
} catch (JSONException e) {
Log.e(TAG, "Error parsing message at index " + i, e);
}
}
builder
.setGroup("myGroup") // TODO not sure this needs to be configurable
.setStyle(inboxStyle);
}
// Notification click and cancel handlers:
/**
* Add the intent that handles the event when the notification is clicked (which should launch the app).
*/
private static void applyTapReceiver(JSONObject options, NotificationCompat.Builder builder, Context context, int notificationID) {
final Intent intent = new Intent(context, NotificationActionReceiver.class)
.putExtra(NOTIFICATION_ID, notificationID)
.putExtra("NOTIFICATION_LAUNCH", options.optBoolean("launch", true))
.setAction(Action.CLICK_ACTION_ID)
.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
builder.setContentIntent(PendingIntent.getService(
context,
notificationID,
intent,
FLAG_UPDATE_CURRENT
));
}
/**
* Add the intent that handles the delete event (which is fired when the X or 'clear all'
* was pressed in the notification center).
*/
private static void applyClearReceiver(NotificationCompat.Builder builder, Context context, int notificationID) {
final Intent intent = new Intent(context, NotificationClearedReceiver.class)
.putExtra(NOTIFICATION_ID, notificationID);
builder.setDeleteIntent(PendingIntent.getBroadcast(
context,
notificationID,
intent,
FLAG_UPDATE_CURRENT
));
}
private static void applyActions(JSONObject options, NotificationCompat.Builder builder, Context context, int notificationID) {
Action[] actions = getActions(options, context);
if (actions == null || actions.length == 0) {
return;
}
NotificationCompat.Action.Builder btn;
for (Action action : actions) {
btn = new NotificationCompat.Action.Builder(
action.getIcon(),
action.getTitle(),
getPendingIntentForAction(options, context, action, notificationID));
if (action.isWithInput()) {
Log.d(TAG, "applyActions, isWithInput");
btn.addRemoteInput(action.getInput());
} else {
Log.d(TAG, "applyActions, not isWithInput");
}
builder.addAction(btn.build());
}
}
private static Action[] getActions(JSONObject options, Context context) {
Object value = options.opt("actions");
String groupId = null;
JSONArray actions = null;
ActionGroup group = null;
if (value instanceof String) {
groupId = (String) value;
} else if (value instanceof JSONArray) {
actions = (JSONArray) value;
}
if (groupId != null) {
group = ActionGroup.lookup(groupId);
} else if (actions != null && actions.length() > 0) {
group = ActionGroup.parse(context, actions);
}
return (group != null) ? group.getActions() : null;
}
private static PendingIntent getPendingIntentForAction(JSONObject options, Context context, Action action, int notificationID) {
Log.d(TAG, "getPendingIntentForAction action.id " + action.getId() + ", action.isLaunchingApp(): " + action.isLaunchingApp());
Intent intent = new Intent(context, NotificationActionReceiver.class)
.putExtra(NOTIFICATION_ID, options.optInt("id", 0))
// TODO see https://github.com/katzer/cordova-plugin-local-notifications/blob/ca1374325bb27ec983332d55dcb6975d929bca4b/src/android/notification/Builder.java#L396
.putExtra("NOTIFICATION_LAUNCH", action.isLaunchingApp())
.setAction(action.getId())
.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
return PendingIntent.getService(context, notificationID, intent, FLAG_UPDATE_CURRENT);
}
// Utility methods:
private static @Nullable Bitmap getBitmap(Context context, String src) {
if (src.indexOf("res://") == 0) {
final int resourceId = context.getResources().getIdentifier(src.substring(6), "drawable", context.getApplicationInfo().packageName);
return resourceId == 0 ? null : android.graphics.BitmapFactory.decodeResource(context.getResources(), resourceId);
} else if (src.indexOf("http") == 0) {
try {
return new DownloadFileFromUrl(src).execute().get();
} catch (InterruptedException | ExecutionException e) {
return null;
}
}
return null;
}
private static boolean shouldEnableNotificationLed(JSONObject options) {
return options.has("notificationLed");
}
private static int getLedColor(JSONObject options) {
Object notificationLed = options.opt("notificationLed");
if (Boolean.TRUE.equals(notificationLed)) {
return DEFAULT_NOTIFICATION_COLOR;
} else if (notificationLed instanceof Integer) {
return (int) notificationLed;
} else {
Log.e(TAG, "Unable to parse option.notificationLed, using default notification color");
return DEFAULT_NOTIFICATION_COLOR;
}
}
}
================================================
FILE: native-src/android/app/src/main/java/com/telerik/localnotifications/DownloadFileFromUrl.java
================================================
package com.telerik.localnotifications;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.util.Log;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
class DownloadFileFromUrl extends AsyncTask {
private static final String TAG = "DownloadFileFromUrl";
private String imageUrl;
DownloadFileFromUrl(final String imageUrl) {
super();
this.imageUrl = imageUrl;
}
@Override
protected Bitmap doInBackground(String... strings) {
try {
HttpURLConnection connection = (HttpURLConnection) new URL(this.imageUrl).openConnection();
connection.setDoInput(true);
connection.connect();
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inJustDecodeBounds = false;
InputStream is = connection.getInputStream();
Bitmap bitmap = BitmapFactory.decodeStream(is, null, opts);
try {
is.close();
} catch (IOException e) {
Log.e(TAG, "Error closing image InputStream: " + e.getMessage(), e);
}
return bitmap;
} catch (IOException e) {
Log.d(TAG, "Error while loading image: " + e.getMessage(), e);
}
return null;
}
}
================================================
FILE: native-src/android/app/src/main/java/com/telerik/localnotifications/LifecycleCallbacks.java
================================================
package com.telerik.localnotifications;
import android.app.Activity;
import android.app.Application;
import android.os.Bundle;
import android.util.Log;
/**
* Subscribe to the Pause and Resume activity events in order to toggle the plugin's status.
*/
public class LifecycleCallbacks implements Application.ActivityLifecycleCallbacks {
private static LifecycleCallbacks callbacks = new LifecycleCallbacks();
/**
* Register for the application's events
* @param app
*/
public static void registerCallbacks(Application app) {
if (app == null) {
Log.d("LifecycleCallbacks", "The application is null, it's not passed correctly!");
throw new RuntimeException("The application is null, it's not passed correctly!");
}
// clean up, not to leak and register it N times...
Log.d("LifecycleCallbacks", "Unregistering the activity lifecycle callbacks...");
app.unregisterActivityLifecycleCallbacks(callbacks);
Log.d("LifecycleCallbacks", "Registering the activity lifecycle callbacks...");
app.registerActivityLifecycleCallbacks(callbacks);
}
public void onActivityPaused(Activity activity) {
Log.d(LocalNotificationsPlugin.TAG, "onActivityPaused: Application has been stopped.");
// the application is being stopped -> the push plugin is not in active/foreground state anymore
LocalNotificationsPlugin.isActive = false;
}
public void onActivityResumed(Activity activity) {
Log.d(LocalNotificationsPlugin.TAG, "onActivityPaused: Application has been started");
// the application has been resumed-> the push plugin is now in active/foreground state
LocalNotificationsPlugin.isActive = true;
}
public void onActivityCreated(Activity activity, Bundle bundle) {
}
public void onActivityDestroyed(Activity activity) {
}
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
public void onActivityStarted(Activity activity) {
}
public void onActivityStopped(Activity activity) {
}
}
================================================
FILE: native-src/android/app/src/main/java/com/telerik/localnotifications/LocalNotificationsPlugin.java
================================================
package com.telerik.localnotifications;
import android.content.Context;
import android.util.Log;
import org.json.JSONObject;
public class LocalNotificationsPlugin {
static final String TAG = "LocalNotifyPlugin";
static boolean isActive = false;
private static JSONObject cachedData;
private static LocalNotificationsPluginListener onMessageReceivedCallback;
private static LocalNotificationsPluginListener onMessageClearedCallback;
private static LocalNotificationsPluginListener onMessageClickedCallback;
/**
* Set the on message received callback
*
* @param callbacks
*/
public static void setOnMessageReceivedCallback(LocalNotificationsPluginListener callbacks) {
onMessageReceivedCallback = callbacks;
if (cachedData != null) {
executeOnMessageReceivedCallback(cachedData);
cachedData = null;
}
}
/**
* Execute the onMessageReceivedCallback with the data passed.
* In case the callback is not present, cache the data;
*
* @param data
*/
public static void executeOnMessageReceivedCallback(JSONObject data) {
if (onMessageReceivedCallback != null) {
Log.d(TAG, "Sending message to client");
onMessageReceivedCallback.success(data);
} else {
Log.d(TAG, "No callback function - caching the data for later retrieval.");
cachedData = data;
}
}
/**
* Set the on message clicked callback
*
* @param callbacks
*/
public static void setOnMessageClickedCallback(LocalNotificationsPluginListener callbacks) {
onMessageClickedCallback = callbacks;
}
/**
* Execute the onMessageClickedCallback with the click on notification Message.
* @param data
*/
public static void executeOnMessageClickedCallback(JSONObject data) {
if (onMessageClickedCallback != null) {
onMessageClickedCallback.success(data);
}
}
/**
* Set the on message cleared callback
*
* @param callbacks
*/
public static void setOnMessageClearedCallback(LocalNotificationsPluginListener callbacks) {
onMessageClearedCallback = callbacks;
}
/**
* Execute the onMessageClearedCallback with the data passed.
* In case the callback is not present, cache the data;
*
* @param data
*/
public static void executeOnMessageClearedCallback(JSONObject data) {
if (onMessageClearedCallback != null) {
onMessageClearedCallback.success(data);
}
}
public static void scheduleNotification(JSONObject options, Context context) throws Exception {
// Persist the options so that we can access them later to:
// - Restore a notification after reboot.
// - Create a notification after an alarm triggers (for recurrent or scheduled notifications).
// - Pass them back to the notification clicked or notification cleared callbacks.
//
// This way we don't need to pass them around as extras in the Intents.
Store.save(context, options);
// Display or schedule the notification, depending on the options:
// If there's already a notification with the same ID, the intent flags should take care of updating all the
// intents but the alarm one, which would be cancelled and rescheduled.
NotificationRestoreReceiver.scheduleNotification(options, context);
}
}
================================================
FILE: native-src/android/app/src/main/java/com/telerik/localnotifications/LocalNotificationsPluginListener.java
================================================
package com.telerik.localnotifications;
/**
* Defines methods for Success and Error callbacks
*/
public interface LocalNotificationsPluginListener {
/**
* Defines a success callback method, which is used to pass success function reference
* from the nativescript to the Java plugin
*
* @param data
*/
void success(Object data);
/**
* Defines a error callback method, which is used to pass error function reference
* from the nativescript to the Java plugin
*
* @param data
*/
void error(Object data);
}
================================================
FILE: native-src/android/app/src/main/java/com/telerik/localnotifications/NotificationActionReceiver.java
================================================
package com.telerik.localnotifications;
import android.app.IntentService;
import android.app.NotificationManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.util.Log;
import androidx.annotation.Nullable;
import androidx.core.app.RemoteInput;
import org.json.JSONException;
import org.json.JSONObject;
import static com.telerik.localnotifications.Action.CLICK_ACTION_ID;
/**
* IntentService which is an entry point, whenever a notification from the bar is tapped and executed.
* The activity fires, notifies the callback.
*/
public class NotificationActionReceiver extends IntentService {
private static String TAG = "NotificationActionReceiver";
// Hold a reference to the intent to handle.
private Intent intent;
public NotificationActionReceiver() {
super("NotificationActionReceiver");
}
@Override
protected void onHandleIntent(@Nullable Intent intent) {
this.intent = intent;
if (intent == null) {
return;
}
Bundle bundle = intent.getExtras();
if (bundle == null) {
return;
}
try {
final JSONObject jsonData = new JSONObject();
jsonData.put("event", Builder.NOTIFICATION_ID);
LocalNotificationsPlugin.executeOnMessageClickedCallback(jsonData);
onClick(intent.getAction(), bundle);
} catch (JSONException e) {
Log.e(TAG, e.getMessage(), e);
}
}
private void onClick(String action, Bundle bundle) throws JSONException {
final Context context = getApplicationContext();
// Note that for the non-default action this will be empty:
final JSONObject opts = Store.get(context, bundle.getInt(Builder.NOTIFICATION_ID), false);
boolean isAppActive = LocalNotificationsPlugin.isActive;
boolean doLaunch = intent.getBooleanExtra("NOTIFICATION_LAUNCH", true);
Log.d(TAG, "doLaunch = " + doLaunch);
if (!isAppActive && doLaunch) {
forceMainActivityReload();
}
if (setTextInput(action, opts)) {
opts.put("event", "input");
} else if (!CLICK_ACTION_ID.equals(action)) {
opts.put("event", "button");
opts.put("response", action);
} else {
opts.put("event", "default");
}
opts.put("foreground", isAppActive);
// opts.put("coldstart", !isPluginActive);
LocalNotificationsPlugin.executeOnMessageReceivedCallback(opts);
if (opts.has("id") && !opts.optBoolean("ongoing", false) && opts.optInt("repeatInterval", 0) == 0) {
int id = opts.getInt("id");
// Clear the notification from the tray, unless it's marker as ongoing/sticky:
((NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE)).cancel(id);
// And also unpersist it:
Store.remove(context, id);
}
}
private boolean setTextInput(String action, JSONObject data) throws JSONException {
Bundle input = RemoteInput.getResultsFromIntent(intent);
if (input != null) {
data.put("response", input.getCharSequence(action));
return true;
}
return false;
}
private void forceMainActivityReload() {
PackageManager pm = getPackageManager();
Intent launchIntent = pm.getLaunchIntentForPackage(getApplicationContext().getPackageName());
Log.d(TAG, "starting activity for package: " + getApplicationContext().getPackageName());
launchIntent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(launchIntent);
}
}
================================================
FILE: native-src/android/app/src/main/java/com/telerik/localnotifications/NotificationAlarmReceiver.java
================================================
package com.telerik.localnotifications;
import android.app.NotificationManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import org.json.JSONObject;
public class NotificationAlarmReceiver extends BroadcastReceiver {
private static final String TAG = "NotificationAlarmRcvr";
public void onReceive(Context context, Intent intent) {
final int id = intent.getIntExtra(Builder.NOTIFICATION_ID, 0);
final JSONObject opts = Store.get(context, id);
if (opts == null) {
Log.e(TAG, "Notification could not be restored, options are null");
return;
}
// Create the notification:
try {
((NotificationManager) context
.getSystemService(Context.NOTIFICATION_SERVICE))
.notify(id, Builder.build(opts, context, id));
} catch (Throwable t) {
Log.e(TAG, "Notification could not be restored!" + t.getMessage(), t);
}
// Note we don't unpersist this notification just yet, as it might still need to be restored
// after a reboot.
}
}
================================================
FILE: native-src/android/app/src/main/java/com/telerik/localnotifications/NotificationClearedReceiver.java
================================================
package com.telerik.localnotifications;
import android.content.Context;
import android.content.Intent;
import android.content.BroadcastReceiver;
import androidx.annotation.Nullable;
import org.json.JSONObject;
public class NotificationClearedReceiver extends BroadcastReceiver {
private static String TAG = "NotificationClearedReceiver";
/**
* Called when the notification is cleared from the notification center.
*
* @param context Application context
* @param intent Received intent with notification ID
*/
@Override
public void onReceive(Context context, @Nullable Intent intent) {
if (intent == null || !intent.hasExtra(Builder.NOTIFICATION_ID)) {
return;
}
// Default value not used as above check ensures we have an actual value:
final int id = intent.getIntExtra(Builder.NOTIFICATION_ID, 0);
final JSONObject opts = Store.get(context, id);
if (opts != null) {
if (opts.optInt("repeatInterval", 0) == 0) {
// Remove the persisted notification data if it's not repeating:
Store.remove(context, id);
}
LocalNotificationsPlugin.executeOnMessageClearedCallback(opts);
}
}
}
================================================
FILE: native-src/android/app/src/main/java/com/telerik/localnotifications/NotificationRestoreReceiver.java
================================================
package com.telerik.localnotifications;
import android.app.AlarmManager;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import java.util.Date;
import java.util.Map;
import org.json.JSONException;
import org.json.JSONObject;
/**
* Notifications need to be restored when the device is rebooted,
* that's what's this class is for.
*/
public class NotificationRestoreReceiver extends BroadcastReceiver {
private static final String TAG = "NotifyRestoreReceiver";
@Override
public void onReceive(Context context, Intent intent) {
if (context == null || !Intent.ACTION_BOOT_COMPLETED.equalsIgnoreCase(intent.getAction())) {
return;
}
try {
for (Map.Entry entry : Store.getAll(context).entrySet()) {
final String notificationString = entry.getValue();
Log.e(TAG, "Will restore previously scheduled notification: " + notificationString);
scheduleNotification(new JSONObject(notificationString), context);
}
} catch (IllegalStateException | JSONException e) {
Log.e(TAG, "Notification could not be scheduled! " + e.getMessage(), e);
}
}
static void scheduleNotification(JSONObject options, Context context) {
// We might create the notification IMMEDIATELY:
// If no ID is provided, we automatically assign different IDs so that all notifications are persisted:
final int notificationID = options.optInt("id", 0);
final long triggerTime = options.optLong("atTime", 0);
if (triggerTime == 0) {
// If we just want to show the notification immediately, there's no need to create an Intent,
// we just send the notification to the Notification Service:
((NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE)).notify(
notificationID, com.telerik.localnotifications.Builder.build(options, context, notificationID)
);
return;
}
// Check if the notification has EXPIRED:
final long interval = options.optLong("repeatInterval", 0); // in ms
final Date triggerDate = new Date(triggerTime);
if (interval == 0 && new Date().after(triggerDate)) {
Store.remove(context, notificationID);
return;
}
// Or SCHEDULE it for later:
final AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
try {
final Intent notificationIntent = new Intent(context, NotificationAlarmReceiver.class)
.setAction(options.getString("id"))
.putExtra(Builder.NOTIFICATION_ID, notificationID);
final PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, notificationIntent, PendingIntent.FLAG_CANCEL_CURRENT);
if (interval > 0) {
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, triggerTime, interval, pendingIntent);
} else {
alarmManager.set(AlarmManager.RTC_WAKEUP, triggerTime, pendingIntent);
}
} catch (Exception e) {
Log.e(TAG, "Notification could not be scheduled!" + e.getMessage(), e);
}
}
}
================================================
FILE: native-src/android/app/src/main/java/com/telerik/localnotifications/Store.java
================================================
package com.telerik.localnotifications;
import android.content.Context;
import androidx.annotation.Nullable;
import android.util.Log;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.Map;
public final class Store {
private static final String TAG = "Store";
private static final String SHARED_PREFERENCES_KEY = "LocalNotificationsPlugin";
public static @Nullable JSONObject get(Context context, int id) {
return get(context, id, true);
}
public static @Nullable JSONObject get(Context context, int id, boolean nullable) {
try {
return new JSONObject(context
.getSharedPreferences(SHARED_PREFERENCES_KEY, Context.MODE_PRIVATE)
.getString(String.valueOf(id), ""));
} catch (JSONException e) {
Log.e(TAG, "Error parsing options" + e.getMessage(), e);
}
return nullable ? null : new JSONObject();
}
public static Map getAll(Context context) {
return (Map) context.getSharedPreferences(SHARED_PREFERENCES_KEY, Context.MODE_PRIVATE).getAll();
}
public static String[] getKeys(Context context) {
return getAll(context).keySet().toArray(new String[0]);
}
public static void save(Context context, JSONObject opts) {
save(context, opts.optInt("id", 0), opts);
}
public static void save(Context context, int id, String opts) {
try {
save(context, id, new JSONObject(opts));
} catch (JSONException e) {
Log.e(TAG, "Error saving options" + e.getMessage(), e);
}
}
public static void save(Context context, int id, JSONObject opts) {
context.getSharedPreferences(SHARED_PREFERENCES_KEY, Context.MODE_PRIVATE).edit().putString(String.valueOf(id), opts.toString()).apply();
}
public static void remove(Context context, int id) {
context.getSharedPreferences(SHARED_PREFERENCES_KEY, Context.MODE_PRIVATE).edit().remove(String.valueOf(id)).apply();
}
}
================================================
FILE: native-src/android/app/src/main/res/values/strings.xml
================================================
locnotplugin
================================================
FILE: native-src/android/build.gradle
================================================
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.4.1'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
google()
jcenter()
maven { url "https://maven.google.com" }
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
================================================
FILE: native-src/android/gradle/wrapper/gradle-wrapper.properties
================================================
#Thu Jul 04 12:57:28 CEST 2019
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip
================================================
FILE: native-src/android/gradle.properties
================================================
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
# Default value: -Xmx10248m -XX:MaxPermSize=256m
# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
android.enableJetifier=true
android.useAndroidX=true
================================================
FILE: native-src/android/gradlew
================================================
#!/usr/bin/env bash
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn ( ) {
echo "$*"
}
die ( ) {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
esac
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
================================================
FILE: native-src/android/gradlew.bat
================================================
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windowz variants
if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
================================================
FILE: native-src/android/locnotplugin.iml
================================================
================================================
FILE: native-src/android/settings.gradle
================================================
include ':app'
================================================
FILE: native-src/ios/.gitattributes
================================================
* -crlf
================================================
FILE: native-src/ios/.gitignore
================================================
build/
xcuserdata/
================================================
FILE: native-src/ios/LocalNotificationsPlugin/Info.plist
================================================
CFBundleDevelopmentRegion
en
CFBundleExecutable
$(EXECUTABLE_NAME)
CFBundleIdentifier
$(PRODUCT_BUNDLE_IDENTIFIER)
CFBundleInfoDictionaryVersion
6.0
CFBundleName
$(PRODUCT_NAME)
CFBundlePackageType
FMWK
CFBundleShortVersionString
1.0
CFBundleSignature
????
CFBundleVersion
$(CURRENT_PROJECT_VERSION)
NSPrincipalClass
================================================
FILE: native-src/ios/LocalNotificationsPlugin/LocalNotificationsPlugin.h
================================================
#import
//! Project version number for LocalNotificationsPlugin.
FOUNDATION_EXPORT double LocalNotificationsVersionNumber;
//! Project version string for LocalNotificationsPlugin.
FOUNDATION_EXPORT const unsigned char LocalNotificationsPluginVersionString[];
// In this header, you should import all the public headers of your framework
#import
#import
================================================
FILE: native-src/ios/LocalNotificationsPlugin/Notification.h
================================================
#import
#import
@interface Notification : NSObject
{
UILocalNotification *notificationMessage;
BOOL isInline;
}
@property (nonatomic, strong) UILocalNotification *notificationMessage;
@property BOOL isInline;
@property (nonatomic, retain) UILocalNotification *launchNotification;
+ (instancetype)sharedInstance;
//-(void)register:(NSMutableDictionary *)options;
//-(void)registerUserNotificationSettings:(NSDictionary*)options;
-(void)setApplicationIconBadgeNumber:(NSMutableDictionary *)options;
-(void)didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings;
-(void)notificationReceived;
-(void)success:(NSString *)eventName WithMessage:(NSString *)message;
-(void)success:(NSString *)eventName WithDictionary:(NSMutableDictionary *)userInfo;
-(void)fail:(NSString *)eventName WithMessage:(NSString *)message withError:(NSError *)error;
@end
================================================
FILE: native-src/ios/LocalNotificationsPlugin/Notification.m
================================================
#import "Notification.h"
#import
#import
#import
const NSString * badgeKey = @"badge";
const NSString * soundKey = @"sound";
const NSString * alertKey = @"alert";
static NSString * didRegisterUserNotificationsEventName = @"didRegisterUserNotificationSettings";
const NSString * notificationReceivedEventName = @"notificationReceived";
const NSString * setBadgeNumberEventName = @"setApplicationIconBadgeNumber";
const NSString * didRegisterUserNotificationSettingsEventName = @"didRegisterUserNotificationSettings";
const NSString * failToRegisterUserNotificationSettingsEventName = @"failToRegisterUserNotificationSettings";
static char launchNotificationKey;
@implementation Notification
@synthesize notificationMessage;
@synthesize isInline;
+ (instancetype)sharedInstance
{
static Notification *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[Notification alloc] init];
});
return sharedInstance;
}
/*
-(void)register:(NSMutableDictionary *)options
{
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000
UIUserNotificationType UserNotificationTypes = UIUserNotificationTypeNone;
if([self isTrue: badgeKey fromOptions: options]) UserNotificationTypes |= UIUserNotificationTypeBadge;
if([self isTrue: soundKey fromOptions: options]) UserNotificationTypes |= UIUserNotificationTypeSound;
if([self isTrue: alertKey fromOptions: options]) UserNotificationTypes |= UIUserNotificationTypeAlert;
#endif
UIRemoteNotificationType notificationTypes = UIRemoteNotificationTypeNone;
notificationTypes |= UIRemoteNotificationTypeNewsstandContentAvailability;
if([self isTrue: badgeKey fromOptions: options]) notificationTypes |= UIRemoteNotificationTypeBadge;
if([self isTrue: soundKey fromOptions: options]) notificationTypes |= UIRemoteNotificationTypeSound;
if([self isTrue: alertKey fromOptions: options]) notificationTypes |= UIRemoteNotificationTypeAlert;
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000
UserNotificationTypes |= UIUserNotificationActivationModeBackground;
#endif
if (notificationTypes == UIRemoteNotificationTypeNone)
NSLog(@"LocalNotificationsPlugin.register: Notification type is set to none");
isInline = NO;
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000
if ([[UIApplication sharedApplication]respondsToSelector:@selector(registerUserNotificationSettings:)]) {
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UserNotificationTypes categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:settings];
[[UIApplication sharedApplication] registerForRemoteNotifications];
} else {
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:notificationTypes];
}
#else
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:notificationTypes];
#endif
[self notificationReceived];
}
*/
- (BOOL)isTrue:(NSString *)key fromOptions:(NSMutableDictionary *)options
{
id arg = [options objectForKey:key];
if([arg isKindOfClass:[NSString class]]) return [arg isEqualToString:@"true"];
if([arg boolValue]) return true;
return false;
}
- (void)didRegisterUserNotificationSettings:(UIUserNotificationSettings *)settings
{
UIUserNotificationType types = UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound;
bool ok = settings.types & types;
[self success:didRegisterUserNotificationsEventName WithMessage:[NSString stringWithFormat:@"%@", ok ? @"true" : @"false"]];
}
- (void)notificationReceived
{
if (self.notificationMessage)
{
NSMutableString *jsonStr = [NSMutableString stringWithString:@"{"];
if (self.notificationMessage.userInfo != nil) {
[self parseDictionary:self.notificationMessage.userInfo intoJSON:jsonStr];
}
if (isInline) {
[jsonStr appendFormat:@"\"foreground\":true"];
isInline = NO;
} else {
[jsonStr appendFormat:@"\"foreground\":false"];
}
[jsonStr appendString:@"}"];
[self success:notificationReceivedEventName WithMessage:jsonStr];
self.notificationMessage = nil;
}
}
-(void)parseDictionary:(NSDictionary *)inDictionary intoJSON:(NSMutableString *)jsonString
{
NSArray *keys = [inDictionary allKeys];
NSString *key;
for (key in keys)
{
id thisObject = [inDictionary objectForKey:key];
if ([thisObject isKindOfClass:[NSDictionary class]])
[self parseDictionary:thisObject intoJSON:jsonString];
else if ([thisObject isKindOfClass:[NSString class]])
[jsonString appendFormat:@"\"%@\":\"%@\",",
key,
[[[[inDictionary objectForKey:key]
stringByReplacingOccurrencesOfString:@"\\" withString:@"\\\\"]
stringByReplacingOccurrencesOfString:@"\"" withString:@"\\\""]
stringByReplacingOccurrencesOfString:@"\n" withString:@"\\n"]];
else {
[jsonString appendFormat:@"\"%@\":\"%@\",", key, [inDictionary objectForKey:key]];
}
}
}
- (void)setApplicationIconBadgeNumber:(NSMutableDictionary *)options
{
int badge = [[options objectForKey:badgeKey] intValue] ?: 0;
[[UIApplication sharedApplication] setApplicationIconBadgeNumber:badge];
[self success:setBadgeNumberEventName WithMessage:[NSString stringWithFormat:@"app badge count set to %d", badge]];
}
/*
- (void)registerUserNotificationSettings:(NSDictionary*)options
{
NSLog(@"--- in registerUserNotificationSettings");
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000
if (![[UIApplication sharedApplication]respondsToSelector:@selector(registerUserNotificationSettings:)]) {
[self success:didRegisterUserNotificationSettingsEventName WithMessage:[NSString stringWithFormat:@"%@", @"user notifications not supported for this ios version."]];
return;
}
NSArray *categories = [options objectForKey:@"categories"];
if (categories == nil) {
[self fail:failToRegisterUserNotificationSettingsEventName WithMessage:@"No categories specified" withError:nil];
return;
}
NSMutableArray *nsCategories = [[NSMutableArray alloc] initWithCapacity:[categories count]];
for (NSDictionary *category in categories) {
// ** 1. create the actions for this category
NSMutableArray *nsActionsForDefaultContext = [[NSMutableArray alloc] initWithCapacity:4];
NSArray *actionsForDefaultContext = [category objectForKey:@"actionsForDefaultContext"];
if (actionsForDefaultContext == nil) {
[self fail:failToRegisterUserNotificationSettingsEventName WithMessage:@"Category doesn't contain actionsForDefaultContext" withError:nil];
return;
}
if (![self createNotificationAction:category actions:actionsForDefaultContext nsActions:nsActionsForDefaultContext]) {
return;
}
NSMutableArray *nsActionsForMinimalContext = [[NSMutableArray alloc] initWithCapacity:2];
NSArray *actionsForMinimalContext = [category objectForKey:@"actionsForMinimalContext"];
if (actionsForMinimalContext == nil) {
[self fail:failToRegisterUserNotificationSettingsEventName WithMessage:@"Category doesn't contain actionsForMinimalContext" withError:nil];
return;
}
if (![self createNotificationAction:category actions:actionsForMinimalContext nsActions:nsActionsForMinimalContext]) {
return;
}
// ** 2. create the category
UIMutableUserNotificationCategory *nsCategory = [[UIMutableUserNotificationCategory alloc] init];
// Identifier to include in your push payload and local notification
NSString *identifier = [category objectForKey:@"identifier"];
if (identifier == nil) {
[self fail:failToRegisterUserNotificationSettingsEventName WithMessage:@"Category doesn't contain identifier" withError:nil];
return;
}
nsCategory.identifier = identifier;
// Add the actions to the category and set the action context
[nsCategory setActions:nsActionsForDefaultContext forContext:UIUserNotificationActionContextDefault];
// Set the actions to present in a minimal context
[nsCategory setActions:nsActionsForMinimalContext forContext:UIUserNotificationActionContextMinimal];
[nsCategories addObject:nsCategory];
}
// ** 3. Determine the notification types
NSArray *types = [options objectForKey:@"types"];
if (types == nil) {
[self fail:failToRegisterUserNotificationSettingsEventName WithMessage:@"No types specified" withError:nil];
return;
}
UIUserNotificationType nsTypes = UIUserNotificationTypeNone;
for (NSString *type in types) {
if ([type isEqualToString:badgeKey]) {
nsTypes |= UIUserNotificationTypeBadge;
} else if ([type isEqualToString:alertKey]) {
nsTypes |= UIUserNotificationTypeAlert;
} else if ([type isEqualToString:soundKey]) {
nsTypes |= UIUserNotificationTypeSound;
} else {
[self fail:failToRegisterUserNotificationSettingsEventName WithMessage:[NSString stringWithFormat:@"Unsupported type: %@, use one of badge, alert, sound", type] withError:nil];
}
}
// ** 4. Register the notification categories
NSSet *nsCategorySet = [NSSet setWithArray:nsCategories];
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:nsTypes categories:nsCategorySet];
[[UIApplication sharedApplication] registerUserNotificationSettings:settings];
UIUserNotificationSettings *settings = [[UIApplication sharedApplication] currentUserNotificationSettings];
UIUserNotificationType types = settings.types|UIUserNotificationTypeAlert|UIUserNotificationTypeBadge|UIUserNotificationTypeSound;
settings = [UIUserNotificationSettings settingsForTypes:types categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:settings];
#endif
[self success:didRegisterUserNotificationSettingsEventName
WithMessage:[NSString stringWithFormat:@"%@", @"user notifications registered!"]];
// [self checkPendingNotification];
}
*/
/*
-(void)checkPendingNotification {
if (notificationMessage) {
NSLog(@"--- in checkPendingNotification, notificationMessage");
[self notificationReceived];
} else if (self.launchNotification) {
NSLog(@"--- in checkPendingNotification, launchNotification");
notificationMessage = self.launchNotification;
[self notificationReceived];
} else {
NSLog(@"--- in checkPendingNotification, nothing");
}
}
*/
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000
- (BOOL)createNotificationAction:(NSDictionary *)category
actions:(NSArray *) actions
nsActions:(NSMutableArray *)nsActions
{
for (NSDictionary *action in actions) {
UIMutableUserNotificationAction *nsAction = [[UIMutableUserNotificationAction alloc] init];
// Define an ID string to be passed back to your app when you handle the action
NSString *identifier = [action objectForKey:@"identifier"];
if (identifier == nil) {
[self fail:failToRegisterUserNotificationSettingsEventName WithMessage:@"Action doesn't contain identifier" withError:nil];
return NO;
}
nsAction.identifier = identifier;
// Localized text displayed in the action button
NSString *title = [action objectForKey:@"title"];
if (title == nil) {
[self fail:failToRegisterUserNotificationSettingsEventName WithMessage:@"Action doesn't contain title" withError:nil];
return NO;
}
nsAction.title = title;
// If you need to show UI, choose foreground (background gives your app a few seconds to run)
BOOL isForeground = [@"foreground" isEqualToString:[action objectForKey:@"activationMode"]];
nsAction.activationMode = isForeground ? UIUserNotificationActivationModeForeground : UIUserNotificationActivationModeBackground;
// Destructive actions display in red
BOOL isDestructive = [[action objectForKey:@"destructive"] isEqual:[NSNumber numberWithBool:YES]];
nsAction.destructive = isDestructive;
// Set whether the action requires the user to authenticate
BOOL isAuthRequired = [[action objectForKey:@"authenticationRequired"] isEqual:[NSNumber numberWithBool:YES]];
nsAction.authenticationRequired = isAuthRequired;
[nsActions addObject:nsAction];
}
return YES;
}
#endif
-(void)success:(NSString *)eventName WithDictionary:(NSMutableDictionary *)userInfo
{
[[NSNotificationCenter defaultCenter]
postNotificationName:eventName
object:self userInfo:userInfo];
}
-(void)success:(NSString *)eventName WithMessage:(NSString *)message
{
NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
[userInfo setValue:message forKey:@"message"];
[[NSNotificationCenter defaultCenter] postNotificationName:eventName object:self userInfo:userInfo];
}
-(void)fail:(NSString *)eventName WithMessage:(NSString *)message withError:(NSError *)error
{
NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
NSString *errorMessage = (error) ? [NSString stringWithFormat:@"%@ - %@", message, [error localizedDescription]] : message;
[userInfo setValue:errorMessage forKey:@"message"];
[[NSNotificationCenter defaultCenter]
postNotificationName:eventName
object:self userInfo:userInfo];
}
- (NSMutableArray *)launchNotification
{
return objc_getAssociatedObject(self, &launchNotificationKey);
}
- (void)setLaunchNotification:(UILocalNotification *)notification
{
objc_setAssociatedObject(self, &launchNotificationKey, notification, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (void)dealloc
{
self.launchNotification = nil;
}
@end
================================================
FILE: native-src/ios/LocalNotificationsPlugin/NotificationManager.h
================================================
#import
#import "Notification.h"
@interface NotificationManager : NSObject
@end
================================================
FILE: native-src/ios/LocalNotificationsPlugin/NotificationManager.m
================================================
#import "NotificationManager.h"
#import
#import
#import
@implementation NotificationManager
static IMP didRegisterOriginalMethod = NULL;
static IMP didRegisterUserOriginalMethod = NULL;
static IMP didReceiveOriginalMethod = NULL;
static IMP didReceiveLocalOriginalMethod = NULL;
static IMP handleActionWithIdentifierLocalOriginalMethod = NULL;
+ (void)load {
[[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidBecomeActiveNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
[NotificationManager myApplicationDidBecomeActive:[UIApplication sharedApplication]];
}];
[[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidFinishLaunchingNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
UIApplication *app = [UIApplication sharedApplication];
id appDelegate = app.delegate;
// didRegisterUserNotificationSettings swizzle
Method didRegisterUserMethod = class_getInstanceMethod([NotificationManager class], @selector(my_application:didRegisterUserNotificationSettings:));
IMP didRegisterUserMethodImp = method_getImplementation(didRegisterUserMethod);
const char* didRegisterUserTypes = method_getTypeEncoding(didRegisterUserMethod);
Method didRegisterUserOriginal = class_getInstanceMethod(appDelegate.class, @selector(application:didRegisterUserNotificationSettings:));
if (didRegisterUserOriginal) {
didRegisterUserOriginalMethod = method_getImplementation(didRegisterUserOriginal);
method_exchangeImplementations(didRegisterUserOriginal, didRegisterUserMethod);
} else {
class_addMethod(appDelegate.class, @selector(application:didRegisterUserNotificationSettings:), didRegisterUserMethodImp, didRegisterUserTypes);
}
// didReceiveLocalNotification swizzle
Method didReceiveLocalMethod = class_getInstanceMethod([NotificationManager class], @selector(my_application:didReceiveLocalNotification:));
IMP didReceiveLocalMethodImp = method_getImplementation(didReceiveLocalMethod);
const char* didReceiveLocalTypes = method_getTypeEncoding(didReceiveLocalMethod);
Method didReceiveLocalOriginal = class_getInstanceMethod(appDelegate.class, @selector(application:didReceiveLocalNotification:));
if (didReceiveLocalOriginal) {
didReceiveLocalOriginalMethod = method_getImplementation(didReceiveLocalOriginal);
method_exchangeImplementations(didReceiveLocalOriginal, didReceiveLocalMethod);
} else {
class_addMethod(appDelegate.class, @selector(application:didReceiveLocalNotification:), didReceiveLocalMethodImp, didReceiveLocalTypes);
}
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000
// handleActionWithIdentifier local swizzle
Method handleActionWithIdentifierLocalMethod = class_getInstanceMethod([NotificationManager class], @selector(my_application:handleActionWithIdentifier:forLocalNotification:completionHandler:));
IMP handleActionWithIdentifierMethodLocalImp = method_getImplementation(handleActionWithIdentifierLocalMethod);
const char* handleActionWithIdentifierTypesLocal = method_getTypeEncoding(handleActionWithIdentifierLocalMethod);
Method handleActionWithIdentifierLocalOriginal = class_getInstanceMethod(appDelegate.class, @selector(application:handleActionWithIdentifier:forLocalNotification:completionHandler:));
if (handleActionWithIdentifierLocalOriginal) {
handleActionWithIdentifierLocalOriginalMethod = method_getImplementation(handleActionWithIdentifierLocalOriginal);
method_exchangeImplementations(handleActionWithIdentifierLocalOriginal, handleActionWithIdentifierLocalMethod);
} else {
class_addMethod(appDelegate.class, @selector(application:handleActionWithIdentifier:forLocalNotification:completionHandler:), handleActionWithIdentifierMethodLocalImp, handleActionWithIdentifierTypesLocal);
}
#endif
}];
}
-(id)init
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(createNotificationChecker:)
name:@"UIApplicationDidFinishLaunchingNotification" object:nil];
return self;
}
- (void)createNotificationChecker:(NSNotification *)notification
{
if (notification)
{
NSDictionary *launchOptions = [notification userInfo];
if (launchOptions)
[Notification sharedInstance].launchNotification = [launchOptions objectForKey: @"UIApplicationLaunchOptionsRemoteNotificationKey"];
}
}
+ (void)myApplicationDidBecomeActive:(UIApplication *)application
{
application.applicationIconBadgeNumber = 0;
if ([Notification sharedInstance].launchNotification) {
[Notification sharedInstance].launchNotification = nil;
[[Notification sharedInstance] performSelectorOnMainThread:@selector(notificationReceived) withObject:[Notification sharedInstance] waitUntilDone:NO];
}
}
- (void)my_application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings {
if (didRegisterOriginalMethod) {
void (*originalImp)(id, SEL, UIApplication *, NSData *) = didRegisterOriginalMethod;
originalImp(self, @selector(application:didRegisterUserNotificationSettings:), application, notificationSettings);
}
NSLog(@"%@", notificationSettings);
[[Notification sharedInstance] didRegisterUserNotificationSettings:notificationSettings];
}
- (void)my_application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification {
if (didReceiveLocalOriginalMethod) {
void (*originalImp)(id, SEL, UIApplication *, UILocalNotification *) = didReceiveOriginalMethod;
originalImp(self, @selector(application:didReceiveLocalNotification:), application, notification);
}
UIApplicationState appState = UIApplicationStateActive;
if ([application respondsToSelector:@selector(applicationState)]) {
appState = application.applicationState;
}
if (appState == UIApplicationStateActive) {
[Notification sharedInstance].notificationMessage = notification;
[Notification sharedInstance].isInline = YES;
[[Notification sharedInstance] notificationReceived];
} else {
[Notification sharedInstance].launchNotification = notification;
[Notification sharedInstance].notificationMessage = notification;
[Notification sharedInstance].isInline = NO;
}
}
- (void)my_application:(UIApplication *) application handleActionWithIdentifier: (NSString *) identifier forLocalNotification: (UILocalNotification *) notification completionHandler: (void (^)()) completionHandler {
if (application.applicationState == UIApplicationStateActive) {
[Notification sharedInstance].notificationMessage = notification;
[Notification sharedInstance].isInline = YES;
[[Notification sharedInstance] notificationReceived];
} else {
[Notification sharedInstance].notificationMessage = notification;
[[Notification sharedInstance] performSelectorOnMainThread:@selector(notificationReceived) withObject:[Notification sharedInstance] waitUntilDone:NO];
}
if (handleActionWithIdentifierLocalOriginalMethod) {
void (*originalImp)(id, SEL, UIApplication *, NSString *, UILocalNotification *, void(^)()) = handleActionWithIdentifierLocalOriginalMethod;
originalImp(self, @selector(application:handleActionWithIdentifier:forLocalNotification:completionHandler:), application, identifier, notification, completionHandler);
} else {
completionHandler();
}
}
@end
================================================
FILE: native-src/ios/LocalNotificationsPlugin.xcodeproj/project.pbxproj
================================================
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXAggregateTarget section */
2B6E19381B454A67006A7B46 /* LocalNotificationsPluginLibrary */ = {
isa = PBXAggregateTarget;
buildConfigurationList = 2B6E19391B454A68006A7B46 /* Build configuration list for PBXAggregateTarget "LocalNotificationsPluginLibrary" */;
buildPhases = (
2B1764CF1B454AF200936DC0 /* ShellScript */,
);
dependencies = (
);
name = LocalNotificationsPluginLibrary;
productName = PushPluginLibrary;
};
/* End PBXAggregateTarget section */
/* Begin PBXBuildFile section */
2B1764D41B4567E500936DC0 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2B1764D31B4567E500936DC0 /* UIKit.framework */; };
2B6E19231B454838006A7B46 /* LocalNotificationsPlugin.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2B6E19171B454838006A7B46 /* LocalNotificationsPlugin.framework */; };
A325E9481C45871900C9F16B /* LocalNotificationsPlugin.h in Headers */ = {isa = PBXBuildFile; fileRef = A325E9421C45871900C9F16B /* LocalNotificationsPlugin.h */; settings = {ATTRIBUTES = (Public, ); }; };
A325E9491C45871900C9F16B /* Notification.h in Headers */ = {isa = PBXBuildFile; fileRef = A325E9431C45871900C9F16B /* Notification.h */; settings = {ATTRIBUTES = (Public, ); }; };
A325E94A1C45871900C9F16B /* Notification.m in Sources */ = {isa = PBXBuildFile; fileRef = A325E9441C45871900C9F16B /* Notification.m */; };
A325E94B1C45871900C9F16B /* NotificationManager.h in Headers */ = {isa = PBXBuildFile; fileRef = A325E9451C45871900C9F16B /* NotificationManager.h */; settings = {ATTRIBUTES = (Public, ); }; };
A325E94C1C45871900C9F16B /* NotificationManager.m in Sources */ = {isa = PBXBuildFile; fileRef = A325E9461C45871900C9F16B /* NotificationManager.m */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
2B6E19241B454838006A7B46 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 2B6E190E1B454838006A7B46 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 2B6E19161B454838006A7B46;
remoteInfo = PushPlugin;
};
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
2B1764D31B4567E500936DC0 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
2B6E19171B454838006A7B46 /* LocalNotificationsPlugin.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = LocalNotificationsPlugin.framework; sourceTree = BUILT_PRODUCTS_DIR; };
2B6E19221B454838006A7B46 /* LocalNotificationsPlugin.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = LocalNotificationsPlugin.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
A325E9411C45871900C9F16B /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
A325E9421C45871900C9F16B /* LocalNotificationsPlugin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LocalNotificationsPlugin.h; sourceTree = ""; };
A325E9431C45871900C9F16B /* Notification.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Notification.h; sourceTree = ""; };
A325E9441C45871900C9F16B /* Notification.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Notification.m; sourceTree = ""; };
A325E9451C45871900C9F16B /* NotificationManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NotificationManager.h; sourceTree = ""; };
A325E9461C45871900C9F16B /* NotificationManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NotificationManager.m; sourceTree = ""; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
2B6E19131B454838006A7B46 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
2B1764D41B4567E500936DC0 /* UIKit.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
2B6E191F1B454838006A7B46 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
2B6E19231B454838006A7B46 /* LocalNotificationsPlugin.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
2B6E190D1B454838006A7B46 = {
isa = PBXGroup;
children = (
A325E9401C45871900C9F16B /* LocalNotificationsPlugin */,
2B1764D31B4567E500936DC0 /* UIKit.framework */,
2B6E19181B454838006A7B46 /* Products */,
);
sourceTree = "";
};
2B6E19181B454838006A7B46 /* Products */ = {
isa = PBXGroup;
children = (
2B6E19171B454838006A7B46 /* LocalNotificationsPlugin.framework */,
2B6E19221B454838006A7B46 /* LocalNotificationsPlugin.xctest */,
);
name = Products;
sourceTree = "";
};
A325E9401C45871900C9F16B /* LocalNotificationsPlugin */ = {
isa = PBXGroup;
children = (
A325E9411C45871900C9F16B /* Info.plist */,
A325E9421C45871900C9F16B /* LocalNotificationsPlugin.h */,
A325E9431C45871900C9F16B /* Notification.h */,
A325E9441C45871900C9F16B /* Notification.m */,
A325E9451C45871900C9F16B /* NotificationManager.h */,
A325E9461C45871900C9F16B /* NotificationManager.m */,
);
path = LocalNotificationsPlugin;
sourceTree = "";
};
/* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */
2B6E19141B454838006A7B46 /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
A325E94B1C45871900C9F16B /* NotificationManager.h in Headers */,
A325E9481C45871900C9F16B /* LocalNotificationsPlugin.h in Headers */,
A325E9491C45871900C9F16B /* Notification.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */
2B6E19161B454838006A7B46 /* LocalNotificationsPlugin */ = {
isa = PBXNativeTarget;
buildConfigurationList = 2B6E192D1B454838006A7B46 /* Build configuration list for PBXNativeTarget "LocalNotificationsPlugin" */;
buildPhases = (
2B6E19121B454838006A7B46 /* Sources */,
2B6E19131B454838006A7B46 /* Frameworks */,
2B6E19141B454838006A7B46 /* Headers */,
2B6E19151B454838006A7B46 /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = LocalNotificationsPlugin;
productName = PushPlugin;
productReference = 2B6E19171B454838006A7B46 /* LocalNotificationsPlugin.framework */;
productType = "com.apple.product-type.framework";
};
2B6E19211B454838006A7B46 /* LocalNotificationsPluginTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 2B6E19301B454838006A7B46 /* Build configuration list for PBXNativeTarget "LocalNotificationsPluginTests" */;
buildPhases = (
2B6E191E1B454838006A7B46 /* Sources */,
2B6E191F1B454838006A7B46 /* Frameworks */,
2B6E19201B454838006A7B46 /* Resources */,
);
buildRules = (
);
dependencies = (
2B6E19251B454838006A7B46 /* PBXTargetDependency */,
);
name = LocalNotificationsPluginTests;
productName = PushPluginTests;
productReference = 2B6E19221B454838006A7B46 /* LocalNotificationsPlugin.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
2B6E190E1B454838006A7B46 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0720;
ORGANIZATIONNAME = Telerik;
TargetAttributes = {
2B6E19161B454838006A7B46 = {
CreatedOnToolsVersion = 6.2;
};
2B6E19211B454838006A7B46 = {
CreatedOnToolsVersion = 6.2;
};
2B6E19381B454A67006A7B46 = {
CreatedOnToolsVersion = 6.2;
};
};
};
buildConfigurationList = 2B6E19111B454838006A7B46 /* Build configuration list for PBXProject "LocalNotificationsPlugin" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
);
mainGroup = 2B6E190D1B454838006A7B46;
productRefGroup = 2B6E19181B454838006A7B46 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
2B6E19161B454838006A7B46 /* LocalNotificationsPlugin */,
2B6E19211B454838006A7B46 /* LocalNotificationsPluginTests */,
2B6E19381B454A67006A7B46 /* LocalNotificationsPluginLibrary */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
2B6E19151B454838006A7B46 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
2B6E19201B454838006A7B46 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
2B1764CF1B454AF200936DC0 /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "UNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-universal\n\n# make sure the output directory exists\nmkdir -p \"${UNIVERSAL_OUTPUTFOLDER}\"\n\n# Step 1. Build Device and Simulator versions\nxcodebuild -target \"${PROJECT_NAME}\" ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphoneos BUILD_DIR=\"${BUILD_DIR}\" BUILD_ROOT=\"${BUILD_ROOT}\" clean build\nxcodebuild -target \"${PROJECT_NAME}\" -configuration ${CONFIGURATION} -sdk iphonesimulator BUILD_DIR=\"${BUILD_DIR}\" BUILD_ROOT=\"${BUILD_ROOT}\" clean build\n\n# Step 2. Copy the framework structure to the universal folder\ncp -R \"${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework\" \"${UNIVERSAL_OUTPUTFOLDER}/\"\n\n# Step 3. Create universal binary file using lipo and place the combined executable in the copied framework directory\nlipo -create -output \"${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/${PROJECT_NAME}\" \"${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework/${PROJECT_NAME}\" \"${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework/${PROJECT_NAME}\"";
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
2B6E19121B454838006A7B46 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
A325E94C1C45871900C9F16B /* NotificationManager.m in Sources */,
A325E94A1C45871900C9F16B /* Notification.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
2B6E191E1B454838006A7B46 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
2B6E19251B454838006A7B46 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 2B6E19161B454838006A7B46 /* LocalNotificationsPlugin */;
targetProxy = 2B6E19241B454838006A7B46 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin XCBuildConfiguration section */
2B6E192B1B454838006A7B46 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Debug;
};
2B6E192C1B454838006A7B46 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1;
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Release;
};
2B6E192E1B454838006A7B46 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
INFOPLIST_FILE = LocalNotificationsPlugin/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
ONLY_ACTIVE_ARCH = NO;
PRODUCT_BUNDLE_IDENTIFIER = "com.telerik.localnotifications.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = LocalNotificationsPlugin;
SKIP_INSTALL = YES;
};
name = Debug;
};
2B6E192F1B454838006A7B46 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
INFOPLIST_FILE = LocalNotificationsPlugin/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
ONLY_ACTIVE_ARCH = NO;
PRODUCT_BUNDLE_IDENTIFIER = "com.telerik.localnotifications.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = LocalNotificationsPlugin;
SKIP_INSTALL = YES;
};
name = Release;
};
2B6E19311B454838006A7B46 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
FRAMEWORK_SEARCH_PATHS = (
"$(SDKROOT)/Developer/Library/Frameworks",
"$(inherited)",
);
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
INFOPLIST_FILE = LocalNotificationsPlugin/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "com.telerik.localnotifications.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = LocalNotificationsPlugin;
};
name = Debug;
};
2B6E19321B454838006A7B46 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
FRAMEWORK_SEARCH_PATHS = (
"$(SDKROOT)/Developer/Library/Frameworks",
"$(inherited)",
);
INFOPLIST_FILE = LocalNotificationsPlugin/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "com.telerik.localnotifications.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = LocalNotificationsPlugin;
};
name = Release;
};
2B6E193A1B454A68006A7B46 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
PRODUCT_NAME = LocalNotificationsPlugin;
};
name = Debug;
};
2B6E193B1B454A68006A7B46 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
PRODUCT_NAME = LocalNotificationsPlugin;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
2B6E19111B454838006A7B46 /* Build configuration list for PBXProject "LocalNotificationsPlugin" */ = {
isa = XCConfigurationList;
buildConfigurations = (
2B6E192B1B454838006A7B46 /* Debug */,
2B6E192C1B454838006A7B46 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
2B6E192D1B454838006A7B46 /* Build configuration list for PBXNativeTarget "LocalNotificationsPlugin" */ = {
isa = XCConfigurationList;
buildConfigurations = (
2B6E192E1B454838006A7B46 /* Debug */,
2B6E192F1B454838006A7B46 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
2B6E19301B454838006A7B46 /* Build configuration list for PBXNativeTarget "LocalNotificationsPluginTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
2B6E19311B454838006A7B46 /* Debug */,
2B6E19321B454838006A7B46 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
2B6E19391B454A68006A7B46 /* Build configuration list for PBXAggregateTarget "LocalNotificationsPluginLibrary" */ = {
isa = XCConfigurationList;
buildConfigurations = (
2B6E193A1B454A68006A7B46 /* Debug */,
2B6E193B1B454A68006A7B46 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 2B6E190E1B454838006A7B46 /* Project object */;
}
================================================
FILE: native-src/ios/LocalNotificationsPlugin.xcodeproj/project.xcworkspace/contents.xcworkspacedata
================================================
================================================
FILE: native-src/ios/LocalNotificationsPlugin.xcodeproj/project.xcworkspace/xcshareddata/PushPlugin.xccheckout
================================================
IDESourceControlProjectFavoriteDictionaryKey
IDESourceControlProjectIdentifier
BC8B754B-9C8D-47D0-ABA9-1598CAAC06C3
IDESourceControlProjectName
PushPlugin
IDESourceControlProjectOriginsDictionary
E8C553F8FBDE6C62B10352AA36517C14BC12A66F
https://github.com/telerik/push-plugin-ios.git
IDESourceControlProjectPath
PushPlugin.xcodeproj
IDESourceControlProjectRelativeInstallPathDictionary
E8C553F8FBDE6C62B10352AA36517C14BC12A66F
../..
IDESourceControlProjectURL
https://github.com/telerik/push-plugin-ios.git
IDESourceControlProjectVersion
111
IDESourceControlProjectWCCIdentifier
E8C553F8FBDE6C62B10352AA36517C14BC12A66F
IDESourceControlProjectWCConfigurations
IDESourceControlRepositoryExtensionIdentifierKey
public.vcs.git
IDESourceControlWCCIdentifierKey
E8C553F8FBDE6C62B10352AA36517C14BC12A66F
IDESourceControlWCCName
push-plugin-ios
================================================
FILE: native-src/ios/README.md
================================================
# Local Notifications Plugin library for NativeScript iOS apps
This is the native iOS for the Telerik NativeScript Local Notifications plugin.
Not really useful for usage outside this plugin.
## Building the framework
- Run the target for simulator and device, make sure to not only build for the active architecture
- Right-click the file in the Products folder and open in Finder
- In a Terminal `cd` to that folder, move up to the `Products` folder
- Run `lipo -create -output "LocalNotificationsPlugin" "Debug-iphonesimulator/LocalNotificationsPlugin.framework/LocalNotificationsPlugin" "Debug-iphoneos/LocalNotificationsPlugin.framework/LocalNotificationsPlugin"`
- Use the resulting `LocalNotificationsPlugin` file instead of the one generated inside any of the target
================================================
FILE: publish/pack.sh
================================================
#!/bin/bash
SOURCE_DIR=../src;
TO_SOURCE_DIR=src;
PACK_DIR=package;
ROOT_DIR=..;
PUBLISH=--publish
install(){
npm i
}
pack() {
echo 'Clearing /src and /package...'
node_modules/.bin/rimraf "$TO_SOURCE_DIR"
node_modules/.bin/rimraf "$PACK_DIR"
# copy src
echo 'Copying src...'
node_modules/.bin/ncp "$SOURCE_DIR" "$TO_SOURCE_DIR"
# copy README & LICENSE to src
echo 'Copying README and LICENSE to /src...'
node_modules/.bin/ncp "$ROOT_DIR"/LICENSE "$TO_SOURCE_DIR"/LICENSE
node_modules/.bin/ncp "$ROOT_DIR"/README.md "$TO_SOURCE_DIR"/README.md
# compile package and copy files required by npm
echo 'Building /src...'
cd "$TO_SOURCE_DIR"
node_modules/.bin/tsc
cd ..
echo 'Creating package...'
# create package dir
mkdir "$PACK_DIR"
# create the package
cd "$PACK_DIR"
npm pack ../"$TO_SOURCE_DIR"
# delete source directory used to create the package
cd ..
node_modules/.bin/rimraf "$TO_SOURCE_DIR"
}
install && pack
================================================
FILE: publish/package.json
================================================
{
"name": "nativescript-publish",
"version": "1.0.0",
"description": "Publish helper",
"devDependencies": {
"ncp": "^2.0.0",
"rimraf": "^2.5.0"
}
}
================================================
FILE: publish/publish.sh
================================================
#!/bin/bash
PACK_DIR=package;
publish() {
cd $PACK_DIR
echo 'Publishing to npm...'
npm publish *.tgz
}
./pack.sh && publish
================================================
FILE: src/.npmignore
================================================
.idea/
.vscode/
native-src/
*.ts
!*.d.ts
tsconfig.json
references.d.ts
================================================
FILE: src/index.d.ts
================================================
/**
* iOS and Android apis should match.
* It doesn't matter if you export `.ios` or `.android`, either one but only one.
*/
export * from "./local-notifications.ios";
// Export any shared classes, constants, etc.
export * from "./local-notifications-common";
================================================
FILE: src/local-notifications-common.ts
================================================
import { Color } from "tns-core-modules/color/color";
export type ScheduleInterval = "second" | "minute" | "hour" | "day" | "week" | "month" | "quarter" | "year";
export interface NotificationAction {
id: string;
type: "button" | "input";
title?: string;
/**
* Launch the app when the action is triggered.
* Default false.
*/
launch?: boolean;
submitLabel?: string;
placeholder?: string;
/**
* For type = "input".
* Default true.
* Android only.
*/
editable?: boolean;
/**
* For type = "input".
* Android only.
*/
choices?: Array;
}
/**
* The options object passed into the schedule function.
*/
export interface ScheduleOptions {
/**
* A number so you can easily distinguish your notifications.
* Default .
*/
id?: number;
/**
* The title which is shown in the statusbar.
* Default not set.
*/
title?: string;
/**
* Shown below the title on iOS >= 10, and next to the App name on Android.
* Default not set.
* All android and iOS >= 10 only.
*/
subtitle?: string;
/**
* The text below the title.
* Default not set on Android. On iOS, the subtitle, title (in this order or priority) will be swapped for it on iOS,
* as iOS won't display notifications without a body. If none of them are set, `' '` will be used.
*/
body?: string;
/**
* On Android you can show a different text in the statusbar, instead of the 'body'.
* Default not set, so `body` is used.
*/
ticker?: string;
/**
* A JavaScript Date object indicating when the notification should be shown.
* Default 'now'.
*/
at?: Date;
// TODO
trigger?: "timeInterval";
/**
* On iOS (and some Android devices) you see a number on top of the app icon. On most Android devices you'll see this number in the notification center.
* Default not set (0).
*/
badge?: number;
/**
* Currently this is only used on Android where you can set this to 'null' to suppress the sound.
* Default 'the default notification sound'.
*/
sound?: string;
/**
* Custom color for the notification icon and title that will be applied when the notification center is expanded.
* Android >= Lollipop (21) only.
*/
color?: Color;
interval?: ScheduleInterval;
/**
* On Android you can set a custom icon in the system tray.
* Pass in `res://filename` (without the extension) which lives in `App_Resouces/Android/drawable` folders.
* If not passed, we'll look there for a file named `ic_stat_notify.png`.
* By default the app icon is used.
* Android < Lollipop (21) only (also see 'silhouetteIcon').
*/
icon?: string;
/**
* Same as `icon`, but for Android >= Lollipop (21) (also see 'icon').
* Should be an alpha-only image.
* Defaults to `res://ic_stat_notify_silhouette`, or the app icon if not present.
*/
silhouetteIcon?: string;
/**
* Custom thumbnail/icon to show in the notification center on Android, this can be:
* - true if you want to use the image as the thumbnail as well.
* - A resource url that lives in App_Resouces/Android/drawable folders. E.g.: 'res://filename.png'.
* - A http url from anywhere on the web.
*
* Android only.
* Default not set.
*/
thumbnail?: boolean | string;
/**
* Set whether this is an "ongoing" notification.
* Ongoing notifications cannot be dismissed by the user,
* so your application or must take care of canceling them.
*
* Android only.
* Default false.
*/
ongoing?: boolean;
/**
* An array of messages to be displayed as a single notification using the inbox style
* Note: the length of the array cannot be greater than five, in a situation where it
* is, the array would be trimmed from the top
*
* Android only.
*/
groupedMessages?: Array;
/**
* The summary of the grouped message (see #groupedMessage) when using the inbox style
*
* Android only.
*/
groupSummary?: string;
/**
* URL (http) of the image to use as an expandable notification image.
*/
image?: string;
/**
* Using the big text style
*
* Android only.
* Default false.
*/
bigTextStyle?: boolean;
/**
* Enable the notification LED light with optional LED light style settings
* - true if you want to use default color
* - Custom color if you would like to use custom color for the notification LED light.
*
* Android only.
* Default not set.
*/
notificationLed?: boolean | Color;
/**
* When longpressing a notification on Android (API >= 26), this 'channel' name is revealed.
* Default 'Channel'.
*/
channel?: string;
/**
* Default false.
*/
forceShowWhenInForeground?: boolean;
priority?: number;
/**
* Buttons or text input.
*/
actions?: Array;
}
export interface ReceivedNotification {
id: number;
foreground: boolean;
title?: string;
body?: string;
event?: string;
response?: string;
}
export interface LocalNotificationsApi {
/**
* On iOS you need to ask permission to schedule a notification.
* You can have the `schedule` funtion do that for you automatically
* (the notification will be scheduled in case the user granted permission),
* or you can manually invoke `requestPermission` if that's your thing.
*/
schedule(options: ScheduleOptions[]): Promise>;
/**
* Tapping a notification in the notification center will launch your app.
* But what if you scheduled two notifications and you want to know which one the user tapped?
*
* Use this function to have a callback invoked when a notification was used to launch your app.
* Note that on iOS it will even be triggered when your app is in the foreground and a notification is received.
*/
addOnMessageReceivedCallback(onReceived: (data: ReceivedNotification) => void): Promise;
/**
* Use when you want to know the id's of all notifications which have been scheduled.
*/
getScheduledIds(): Promise;
/**
* Cancels the 'id' passed in.
* On iOS returns whether or not it was found (and cancelled).
* On Android we always return true currently.
*/
cancel(id: number): Promise;
/**
* Use when you just want to cancel all previously scheduled notifications.
*/
cancelAll(): Promise;
/**
* On Android you don't need permission, but on iOS you do.
* Android will simply return true.
*
* If the 'requestPermission' or 'schedule' functions previously ran
* you may want to check whether or not the user granted permission.
*/
hasPermission(): Promise;
/**
* On Android you don't need permission, but on iOS you do.
* Android will simply return true.
*
* If the 'requestPermission' or 'schedule' function previously ran
* the user has already been prompted to grant permission.
*
* If the user granted permission this function returns true,
* but if he denied permission this function will return false
* since an iOS can only request permission once. In which case the user needs
* to go to the iOS settings app and manually enable permissions for your app.
*/
requestPermission(): Promise;
}
// TODO: This could be just an utils file!
export abstract class LocalNotificationsCommon {
protected static defaults = {
badge: 0,
interval: undefined,
ongoing: false,
groupSummary: null,
bigTextStyle: false,
channel: "Channel",
forceShowWhenInForeground: false
};
protected static merge(obj1: {}, obj2: {}): any {
let result = {};
for (let i in obj1) {
if ((i in obj2) && (typeof obj1[i] === "object") && (i !== null)) {
result[i] = this.merge(obj1[i], obj2[i]);
} else {
result[i] = obj1[i];
}
}
for (let i in obj2) {
if (i in result) {
continue;
}
result[i] = obj2[i];
}
return result;
}
protected static generateUUID(): string {
// Not the best, but it will work. See https://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript
const s4 = () => Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1);
return `${s4()}${s4()}-${s4()}-${s4()}-${s4()}-${s4()}${s4()}${s4()}`;
}
protected static generateNotificationID(): number {
return Math.round((Date.now() + Math.round((100000 * Math.random()))) / 1000);
}
protected static ensureID(opts: ScheduleOptions): number {
const id = opts.id;
if (typeof id === "number") {
return id;
} else {
// We need unique IDs in all notifications to be able to persist them without overwriting one another:
return opts.id = LocalNotificationsCommon.generateNotificationID();
}
}
}
================================================
FILE: src/local-notifications.android.ts
================================================
import * as app from "tns-core-modules/application";
import * as utils from "tns-core-modules/utils/utils";
import {
LocalNotificationsApi,
LocalNotificationsCommon,
ReceivedNotification,
ScheduleInterval,
ScheduleOptions
} from "./local-notifications-common";
declare const android, com, global: any;
const NotificationManagerCompatPackageName = useAndroidX() ? global.androidx.core.app : android.support.v4.app;
function useAndroidX () {
return global.androidx && global.androidx.appcompat;
}
(() => {
const registerLifecycleEvents = () => {
com.telerik.localnotifications.LifecycleCallbacks.registerCallbacks(app.android.nativeApp);
};
// Hook on the application events
if (app.android.nativeApp) {
registerLifecycleEvents();
} else {
app.on(app.launchEvent, registerLifecycleEvents);
}
})();
export class LocalNotificationsImpl extends LocalNotificationsCommon implements LocalNotificationsApi {
private static IS_GTE_LOLLIPOP: boolean = android.os.Build.VERSION.SDK_INT >= 21;
private static getInterval(interval: ScheduleInterval): number {
if (interval === "second") {
return 1000; // it's in ms
} else if (interval === "minute") {
return android.app.AlarmManager.INTERVAL_FIFTEEN_MINUTES / 15;
} else if (interval === "hour") {
return android.app.AlarmManager.INTERVAL_HOUR;
} else if (interval === "day") {
return android.app.AlarmManager.INTERVAL_DAY;
} else if (interval === "week") {
return android.app.AlarmManager.INTERVAL_DAY * 7;
} else if (interval === "month") {
return android.app.AlarmManager.INTERVAL_DAY * 31; // well that's almost accurate
} else if (interval === "year") {
return android.app.AlarmManager.INTERVAL_DAY * 365; // same here
} else {
return undefined;
}
}
private static getIcon(context: any /* android.content.Context */, resources: any, iconLocation?: string): string {
const packageName: string = context.getApplicationInfo().packageName;
return iconLocation
&& iconLocation.indexOf(utils.RESOURCE_PREFIX) === 0
&& resources.getIdentifier(iconLocation.substr(utils.RESOURCE_PREFIX.length), "drawable", packageName)
|| (LocalNotificationsImpl.IS_GTE_LOLLIPOP && resources.getIdentifier("ic_stat_notify_silhouette", "drawable", packageName))
|| resources.getIdentifier("ic_stat_notify", "drawable", packageName)
|| context.getApplicationInfo().icon;
}
private static cancelById(id: number): void {
const context = utils.ad.getApplicationContext();
const notificationIntent = new android.content.Intent(context, com.telerik.localnotifications.NotificationAlarmReceiver.class).setAction("" + id);
const pendingIntent = android.app.PendingIntent.getBroadcast(context, 0, notificationIntent, 0);
const alarmManager = context.getSystemService(android.content.Context.ALARM_SERVICE);
alarmManager.cancel(pendingIntent);
const notificationManager = context.getSystemService(android.content.Context.NOTIFICATION_SERVICE);
notificationManager.cancel(id);
com.telerik.localnotifications.Store.remove(context, id);
}
hasPermission(): Promise {
return new Promise((resolve, reject) => {
try {
resolve(LocalNotificationsImpl.hasPermission());
} catch (ex) {
console.log("Error in LocalNotifications.hasPermission: " + ex);
reject(ex);
}
});
}
requestPermission(): Promise {
return new Promise((resolve, reject) => {
try {
// AFAIK can't do it on this platform.. when 'false' is returned, the app could prompt the user to manually enable them in the Device Settings
resolve(LocalNotificationsImpl.hasPermission());
} catch (ex) {
console.log("Error in LocalNotifications.requestPermission: " + ex);
reject(ex);
}
});
}
addOnMessageReceivedCallback(onReceived: (data: ReceivedNotification) => void): Promise {
return new Promise((resolve, reject) => {
try {
// note that this is ONLY triggered when the user clicked the notification in the statusbar
com.telerik.localnotifications.LocalNotificationsPlugin.setOnMessageReceivedCallback(
new com.telerik.localnotifications.LocalNotificationsPluginListener({
success: notification => {
onReceived(JSON.parse(notification));
}
})
);
resolve();
} catch (ex) {
console.log("Error in LocalNotifications.addOnMessageReceivedCallback: " + ex);
reject(ex);
}
});
}
addOnMessageClearedCallback(onReceived: (data: ReceivedNotification) => void): Promise {
return new Promise((resolve, reject) => {
try {
// note that this is ONLY triggered when the user clicked the notification in the statusbar
com.telerik.localnotifications.LocalNotificationsPlugin.setOnMessageClearedCallback(
new com.telerik.localnotifications.LocalNotificationsPluginListener({
success: notification => {
onReceived(JSON.parse(notification));
}
})
);
resolve();
} catch (ex) {
console.log("Error in LocalNotifications.addOnMessageClearedCallback: " + ex);
reject(ex);
}
});
}
cancel(id: number): Promise {
return new Promise((resolve, reject) => {
try {
LocalNotificationsImpl.cancelById(id);
resolve(true);
} catch (ex) {
console.log("Error in LocalNotifications.cancel: " + ex);
reject(ex);
}
});
}
cancelAll(): Promise {
return new Promise((resolve, reject) => {
try {
const context = utils.ad.getApplicationContext();
// if (android.os.Build.VERSION.SDK_INT >= 26) {
// const notificationManager = context.getSystemService(android.content.Context.NOTIFICATION_SERVICE);
// console.log(">> >= 26, getActiveNotifications: " + notificationManager.getActiveNotifications());
// } else {
// console.log(">> < 26, StatusBarNotification[0]: " + new android.service.notification.StatusBarNotification[0]);
// }
const keys: Array = com.telerik.localnotifications.Store.getKeys(utils.ad.getApplicationContext());
for (let i = 0; i < keys.length; i++) {
LocalNotificationsImpl.cancelById(parseInt(keys[i]));
}
NotificationManagerCompatPackageName.NotificationManagerCompat.from(context).cancelAll();
resolve();
} catch (ex) {
console.log("Error in LocalNotifications.cancelAll: " + ex);
reject(ex);
}
});
}
getScheduledIds(): Promise {
return new Promise((resolve, reject) => {
try {
const keys: Array = com.telerik.localnotifications.Store.getKeys(utils.ad.getApplicationContext());
const ids: number[] = [];
for (let i = 0; i < keys.length; i++) {
ids.push(parseInt(keys[i]));
}
resolve(ids);
} catch (ex) {
console.log("Error in LocalNotifications.getScheduledIds: " + ex);
reject(ex);
}
});
}
schedule(scheduleOptions: ScheduleOptions[]): Promise> {
return new Promise((resolve, reject) => {
try {
if (!LocalNotificationsImpl.hasPermission()) {
reject("Permission not granted");
return;
}
const context = utils.ad.getApplicationContext();
const resources = context.getResources();
const scheduledIds: Array = [];
// TODO: All these changes in the options (other than setting the ID) should rather be done in Java so that
// the persisted options are exactly like the original ones.
for (let n in scheduleOptions) {
const options = LocalNotificationsImpl.merge(scheduleOptions[n], LocalNotificationsImpl.defaults);
options.icon = LocalNotificationsImpl.getIcon(
context,
resources,
LocalNotificationsImpl.IS_GTE_LOLLIPOP && options.silhouetteIcon || options.icon
);
options.atTime = options.at ? options.at.getTime() : 0;
// Used when restoring the notification after a reboot:
options.repeatInterval = LocalNotificationsImpl.getInterval(options.interval);
if (options.color) {
options.color = options.color.android;
}
if (options.notificationLed && options.notificationLed !== true) {
options.notificationLed = options.notificationLed.android;
}
LocalNotificationsImpl.ensureID(options);
com.telerik.localnotifications.LocalNotificationsPlugin.scheduleNotification(
new org.json.JSONObject(JSON.stringify(options)),
context);
scheduledIds.push(options.id);
}
resolve(scheduledIds);
} catch (ex) {
console.log("Error in LocalNotifications.schedule: " + ex);
reject(ex);
}
});
}
private static hasPermission(): boolean {
const context = utils.ad.getApplicationContext();
return !context || NotificationManagerCompatPackageName.NotificationManagerCompat.from(context).areNotificationsEnabled();
}
}
export const LocalNotifications = new LocalNotificationsImpl();
================================================
FILE: src/local-notifications.ios.ts
================================================
import { DelegateObserver, SharedNotificationDelegate } from "nativescript-shared-notification-delegate";
import * as fileSystemModule from "tns-core-modules/file-system";
import { fromUrl } from "tns-core-modules/image-source";
import { LocalNotificationsApi, LocalNotificationsCommon, ReceivedNotification, ScheduleInterval, ScheduleOptions } from "./local-notifications-common";
declare const Notification: any;
export class LocalNotificationsImpl extends LocalNotificationsCommon implements LocalNotificationsApi {
private static didRegisterUserNotificationSettingsObserver: any;
private notificationReceivedObserver: any;
private pendingReceivedNotifications: Array = [];
private receivedNotificationCallback: (data: ReceivedNotification) => void;
private notificationHandler: Notification;
private notificationManager: NotificationManager;
private observer: LocalNotificationsDelegateObserverImpl;
constructor() {
super();
if (LocalNotificationsImpl.isUNUserNotificationCenterAvailable()) {
this.observer = new LocalNotificationsDelegateObserverImpl(new WeakRef(this));
SharedNotificationDelegate.addObserver(this.observer);
} else {
// grab 'em here, store 'em in JS, and give them to the callback when addOnMessageReceivedCallback is wired
this.notificationReceivedObserver = LocalNotificationsImpl.addObserver("notificationReceived", result => {
const notificationDetails = JSON.parse(result.userInfo.objectForKey("message"));
this.addOrProcessNotification(notificationDetails);
});
this.notificationHandler = Notification.new();
this.notificationManager = NotificationManager.new();
}
}
static isUNUserNotificationCenterAvailable(): boolean {
try {
// available since iOS 10
return !!UNUserNotificationCenter;
} catch (ignore) {
return false;
}
}
private static hasPermission(): boolean {
const settings = UIApplication.sharedApplication.currentUserNotificationSettings;
const types = UIUserNotificationType.Alert | UIUserNotificationType.Badge | UIUserNotificationType.Sound;
return (settings.types & types) > 0;
}
private static getImageName(imageURL: string = "", extension: "png" | "jpeg" | "jpg" = "png"): [string, string] {
const name: string = imageURL.split(/[\/\.]/).slice(-2, -1)[0] || LocalNotificationsImpl.generateUUID();
return [name, `${name}.${extension}`];
}
private static addObserver(eventName, callback): any {
return NSNotificationCenter.defaultCenter.addObserverForNameObjectQueueUsingBlock(eventName, null, NSOperationQueue.mainQueue, callback);
}
private static getInterval(interval: ScheduleInterval): NSCalendarUnit {
if (interval === "minute") {
return NSCalendarUnit.CalendarUnitSecond;
} else if (interval === "hour") {
return NSCalendarUnit.CalendarUnitMinute | NSCalendarUnit.CalendarUnitSecond;
} else if (interval === "day") {
return NSCalendarUnit.CalendarUnitHour | NSCalendarUnit.CalendarUnitMinute | NSCalendarUnit.CalendarUnitSecond;
} else if (interval === "week") {
return NSCalendarUnit.CalendarUnitWeekday | NSCalendarUnit.CalendarUnitHour | NSCalendarUnit.CalendarUnitMinute | NSCalendarUnit.CalendarUnitSecond;
} else if (interval === "month") {
return NSCalendarUnit.CalendarUnitDay | NSCalendarUnit.CalendarUnitHour | NSCalendarUnit.CalendarUnitMinute | NSCalendarUnit.CalendarUnitSecond;
} else if (interval === "year") {
return NSCalendarUnit.CalendarUnitMonth | NSCalendarUnit.CalendarUnitDay | NSCalendarUnit.CalendarUnitHour | NSCalendarUnit.CalendarUnitMinute | NSCalendarUnit.CalendarUnitSecond;
} else {
return NSCalendarUnit.CalendarUnitYear | NSCalendarUnit.CalendarUnitMonth | NSCalendarUnit.CalendarUnitDay | NSCalendarUnit.CalendarUnitHour | NSCalendarUnit.CalendarUnitMinute | NSCalendarUnit.CalendarUnitSecond;
}
}
private static getIntervalSeconds(interval: ScheduleInterval, ticks: number): number {
if (!interval) {
return ticks;
} else if (interval === "second") {
return ticks;
} else if (interval === "minute") {
return ticks * 60;
} else if (interval === "hour") {
return ticks * 60 * 60;
} else if (interval === "day") {
return ticks * 60 * 60 * 24;
} else if (interval === "week") {
return ticks * 60 * 60 * 24 * 7;
} else if (interval === "month") {
return ticks * 60 * 60 * 24 * 30.438;
} else if (interval === "quarter") {
return ticks * 60 * 60 * 24 * 91.313;
} else if (interval === "year") {
return ticks * 60 * 60 * 24 * 365;
} else {
return ticks;
}
}
private static schedulePendingNotifications(pending: ScheduleOptions[]): Array {
if (LocalNotificationsImpl.isUNUserNotificationCenterAvailable()) {
return LocalNotificationsImpl.schedulePendingNotificationsNew(pending);
} else {
return LocalNotificationsImpl.schedulePendingNotificationsLegacy(pending);
}
}
private static schedulePendingNotificationsNew(pending: ScheduleOptions[]): Array {
const scheduledIds: Array = [];
for (const n in pending) {
const options: ScheduleOptions = LocalNotificationsImpl.merge(pending[n], LocalNotificationsImpl.defaults);
LocalNotificationsImpl.ensureID(options);
scheduledIds.push(options.id);
// Notification content
const content = UNMutableNotificationContent.new();
const {title, subtitle, body} = options;
content.title = body || subtitle ? title : undefined;
content.subtitle = body ? subtitle : undefined;
// On iOS, a notification with no body won't show up, so the subtitle or title will be used in this case as body
// instead. If none of them is set, we set it to ' ' and will show up as an empty line in the notification:
content.body = body || subtitle || title || " ";
content.badge = options.badge;
if (options.sound === undefined || options.sound === "default") {
content.sound = UNNotificationSound.defaultSound;
}
const userInfoDict = new NSMutableDictionary({capacity: 3});
userInfoDict.setObjectForKey("nativescript-local-notifications", "__NotificationType");
userInfoDict.setObjectForKey(options.forceShowWhenInForeground, "forceShowWhenInForeground");
userInfoDict.setObjectForKey(options.priority || 0, "priority");
content.userInfo = userInfoDict;
// Notification trigger and repeat
let trigger: UNNotificationTrigger;
if (options.at) {
const cal = LocalNotificationsImpl.calendarWithMondayAsFirstDay();
const date = cal.componentsFromDate(LocalNotificationsImpl.getInterval(options.interval), options.at);
date.timeZone = NSTimeZone.defaultTimeZone;
trigger = UNCalendarNotificationTrigger.triggerWithDateMatchingComponentsRepeats(date, options.interval !== undefined);
} else {
trigger = UNTimeIntervalNotificationTrigger.triggerWithTimeIntervalRepeats(2, false);
}
// actions
if (options.actions) {
let categoryIdentifier = "CATEGORY";
const actions: Array = [];
options.actions.forEach(action => {
categoryIdentifier += ("_" + action.id);
let notificationActionOptions: UNNotificationActionOptions = UNNotificationActionOptionNone;
if (action.launch) {
notificationActionOptions = UNNotificationActionOptions.Foreground;
}
if (action.type === "input") {
actions.push(UNTextInputNotificationAction.actionWithIdentifierTitleOptionsTextInputButtonTitleTextInputPlaceholder(
"" + action.id,
action.title,
notificationActionOptions,
action.submitLabel || "Submit",
action.placeholder));
} else if (action.type === "button") {
actions.push(UNNotificationAction.actionWithIdentifierTitleOptions(
"" + action.id,
action.title,
notificationActionOptions));
} else {
console.log("Unsupported action type: " + action.type);
}
});
const notificationCategory = UNNotificationCategory.categoryWithIdentifierActionsIntentIdentifiersOptions(
categoryIdentifier,
actions,
[],
UNNotificationCategoryOptions.CustomDismissAction);
content.categoryIdentifier = categoryIdentifier;
UNUserNotificationCenter.currentNotificationCenter().getNotificationCategoriesWithCompletionHandler((categories: NSSet) => {
if (categories) {
UNUserNotificationCenter.currentNotificationCenter().setNotificationCategories(categories.setByAddingObject(notificationCategory));
} else {
UNUserNotificationCenter.currentNotificationCenter().setNotificationCategories(NSSet.setWithObject(notificationCategory));
}
});
}
if (!options.image) {
UNUserNotificationCenter.currentNotificationCenter().addNotificationRequestWithCompletionHandler(
UNNotificationRequest.requestWithIdentifierContentTrigger("" + options.id, content, trigger),
(error: NSError) => error ? console.log(`Error scheduling notification (id ${options.id}): ${error.localizedDescription}`) : null);
} else {
fromUrl(options.image).then(image => {
const [imageName, imageNameWithExtension] = LocalNotificationsImpl.getImageName(options.image, "png");
const path: string = fileSystemModule.path.join(
fileSystemModule.knownFolders.temp().path,
imageNameWithExtension,
);
const saved = image.saveToFile(path, "png");
if (saved || fileSystemModule.File.exists(path)) {
try {
content.attachments = NSArray.arrayWithObject(
UNNotificationAttachment.attachmentWithIdentifierURLOptionsError(
imageName,
NSURL.fileURLWithPath(path),
null
));
} catch (err) {
console.log("Error adding image attachment - ignoring the image. Error: " + err);
// Just fall back to a normal notification...
}
}
UNUserNotificationCenter.currentNotificationCenter().addNotificationRequestWithCompletionHandler(
UNNotificationRequest.requestWithIdentifierContentTrigger("" + options.id, content, trigger),
(error: NSError) => error ? console.log(`Error scheduling notification (id ${options.id}): ${error.localizedDescription}`) : null);
});
}
}
return scheduledIds;
}
private static calendarWithMondayAsFirstDay(): NSCalendar {
const cal = NSCalendar.alloc().initWithCalendarIdentifier(NSCalendarIdentifierISO8601);
cal.firstWeekday = 2;
cal.minimumDaysInFirstWeek = 1;
return cal;
}
private static schedulePendingNotificationsLegacy(pending: ScheduleOptions[]): Array {
const scheduledIds: Array = [];
for (const n in pending) {
const options = LocalNotificationsImpl.merge(pending[n], LocalNotificationsImpl.defaults);
LocalNotificationsImpl.ensureID(options);
scheduledIds.push(options.id);
const notification = UILocalNotification.new();
notification.fireDate = options.at ? options.at : new Date();
notification.alertTitle = options.title;
notification.alertBody = options.body;
notification.timeZone = NSTimeZone.defaultTimeZone;
notification.applicationIconBadgeNumber = options.badge;
// these are sent back to the plugin when a notification is received
const userInfoDict = NSMutableDictionary.alloc().initWithCapacity(4);
userInfoDict.setObjectForKey(options.id, "id");
userInfoDict.setObjectForKey(options.title, "title");
userInfoDict.setObjectForKey(options.body, "body");
userInfoDict.setObjectForKey(options.interval, "interval");
notification.userInfo = userInfoDict;
switch (options.sound) {
case null:
case false:
break;
case undefined:
case "default":
notification.soundName = UILocalNotificationDefaultSoundName;
break;
default:
notification.soundName = options.sound;
break;
}
// Used when restoring the notification after a reboot:
options.repeatInterval = LocalNotificationsImpl.getInterval(options.interval);
// notification.soundName = custom..;
// notification.resumeApplicationInBackground = true;
UIApplication.sharedApplication.scheduleLocalNotification(notification);
}
return scheduledIds;
}
addOrProcessNotification(notificationDetails: ReceivedNotification): void {
if (this.receivedNotificationCallback) {
this.receivedNotificationCallback(notificationDetails);
} else {
this.pendingReceivedNotifications.push(notificationDetails);
}
}
hasPermission(): Promise {
return new Promise((resolve, reject) => {
try {
resolve(LocalNotificationsImpl.hasPermission());
} catch (ex) {
console.log("Error in LocalNotifications.hasPermission: " + ex);
reject(ex);
}
});
}
requestPermission(): Promise {
return new Promise((resolve, reject) => {
if (LocalNotificationsImpl.isUNUserNotificationCenterAvailable()) {
// iOS >= 10
const center = UNUserNotificationCenter.currentNotificationCenter();
center.requestAuthorizationWithOptionsCompletionHandler(
UNAuthorizationOptions.Alert | UNAuthorizationOptions.Badge | UNAuthorizationOptions.Sound,
(granted: boolean, error: NSError) => resolve(granted));
} else {
// iOS < 10
LocalNotificationsImpl.didRegisterUserNotificationSettingsObserver = LocalNotificationsImpl.addObserver("didRegisterUserNotificationSettings", result => {
NSNotificationCenter.defaultCenter.removeObserver(LocalNotificationsImpl.didRegisterUserNotificationSettingsObserver);
LocalNotificationsImpl.didRegisterUserNotificationSettingsObserver = undefined;
const granted = result.userInfo.objectForKey("message");
resolve(granted !== "false" && granted !== false);
});
const types = UIApplication.sharedApplication.currentUserNotificationSettings.types | UIUserNotificationType.Alert | UIUserNotificationType.Badge | UIUserNotificationType.Sound;
const settings = UIUserNotificationSettings.settingsForTypesCategories(types, null);
UIApplication.sharedApplication.registerUserNotificationSettings(settings);
}
});
}
addOnMessageReceivedCallback(onReceived: (data: ReceivedNotification) => void): Promise {
return new Promise((resolve, reject) => {
try {
this.receivedNotificationCallback = onReceived;
for (const pendingReceivedNotification of this.pendingReceivedNotifications) {
onReceived(pendingReceivedNotification);
}
this.pendingReceivedNotifications = [];
resolve(true);
} catch (ex) {
console.log("Error in LocalNotifications.addOnMessageReceivedCallback: " + ex);
reject(ex);
}
});
}
addOnMessageClearedCallback(onReceived: (data: ReceivedNotification) => void): Promise {
// Not possible on iOS. It looks like this would only work if the notification has categories set, which might not
// be the case. Therefore, this method is just a placeholder in case users use it without checking the platform
// they are in. See:
// - https://stackoverflow.com/questions/44009707/customdismissaction-not-working-for-remote-notifications
// - https://stackoverflow.com/questions/31929274/know-if-ios-notification-was-dismiss.
return Promise.resolve(false);
}
cancel(id: number): Promise {
return new Promise((resolve, reject) => {
try {
if (LocalNotificationsImpl.isUNUserNotificationCenterAvailable()) {
UNUserNotificationCenter.currentNotificationCenter().removePendingNotificationRequestsWithIdentifiers(["" + id]);
resolve(true);
} else {
const scheduled = UIApplication.sharedApplication.scheduledLocalNotifications;
for (let i = 0, l = scheduled.count; i < l; i++) {
const noti = scheduled.objectAtIndex(i);
if (id === +noti.userInfo.valueForKey("id")) {
UIApplication.sharedApplication.cancelLocalNotification(noti);
resolve(true);
return;
}
}
resolve(false);
}
} catch (ex) {
console.log("Error in LocalNotifications.cancel: " + ex);
reject(ex);
}
});
}
cancelAll(): Promise {
return new Promise((resolve, reject) => {
try {
if (LocalNotificationsImpl.isUNUserNotificationCenterAvailable()) {
UNUserNotificationCenter.currentNotificationCenter().removeAllPendingNotificationRequests();
} else {
UIApplication.sharedApplication.cancelAllLocalNotifications();
}
UIApplication.sharedApplication.applicationIconBadgeNumber = 0;
resolve();
} catch (ex) {
console.log("Error in LocalNotifications.cancelAll: " + ex);
reject(ex);
}
});
}
getScheduledIds(): Promise {
return new Promise((resolve, reject) => {
try {
const scheduledIds = [];
if (LocalNotificationsImpl.isUNUserNotificationCenterAvailable()) {
UNUserNotificationCenter.currentNotificationCenter().getPendingNotificationRequestsWithCompletionHandler((notRequests: NSArray) => {
if (notRequests) {
for (let i = 0; i < notRequests.count; i++) {
scheduledIds.push(notRequests[i].identifier);
}
}
resolve(scheduledIds.map(Number));
});
} else {
const scheduled = UIApplication.sharedApplication.scheduledLocalNotifications;
for (let i = 0, l = scheduled.count; i < l; i++) {
scheduledIds.push(scheduled.objectAtIndex(i).userInfo.valueForKey("id"));
}
resolve(scheduledIds.map(Number));
}
} catch (ex) {
console.log("Error in LocalNotifications.getScheduledIds: " + ex);
reject(ex);
}
});
}
schedule(options: ScheduleOptions[]): Promise> {
return new Promise((resolve, reject) => {
try {
if (!LocalNotificationsImpl.hasPermission()) {
this.requestPermission().then(granted => {
if (granted) {
resolve(LocalNotificationsImpl.schedulePendingNotifications(options));
} else {
reject("Permission not granted");
}
});
} else {
resolve(LocalNotificationsImpl.schedulePendingNotifications(options));
}
} catch (ex) {
console.log("Error in LocalNotifications.schedule: " + ex);
reject(ex);
}
});
}
}
class LocalNotificationsDelegateObserverImpl implements DelegateObserver {
private _owner: WeakRef;
private receivedInForeground = false;
observerUniqueKey = "nativescript-local-notifications";
constructor(owner: WeakRef) {
this._owner = owner;
}
/**
* Called when the app was opened by a notification.
*/
userNotificationCenterDidReceiveNotificationResponseWithCompletionHandler(center: UNUserNotificationCenter, notificationResponse: UNNotificationResponse, completionHandler: () => void, next: () => void): void {
if (notificationResponse.notification.request.content.userInfo.valueForKey("__NotificationType") !== "nativescript-local-notifications") {
next();
return;
}
const request = notificationResponse.notification.request,
notificationContent = request.content,
action = notificationResponse.actionIdentifier;
// let's ignore dismiss actions
if (action === UNNotificationDismissActionIdentifier) {
completionHandler();
return;
}
let event = "default";
if (action !== UNNotificationDefaultActionIdentifier) {
event = notificationResponse instanceof UNTextInputNotificationResponse ? "input" : "button";
}
let response = notificationResponse.actionIdentifier;
if (response === UNNotificationDefaultActionIdentifier) {
response = undefined;
} else if (notificationResponse instanceof UNTextInputNotificationResponse) {
response = (notificationResponse).userText;
}
this._owner.get().addOrProcessNotification({
id: +request.identifier,
title: notificationContent.title,
body: notificationContent.body,
foreground: this.receivedInForeground || UIApplication.sharedApplication.applicationState === UIApplicationState.Active,
event,
response
});
this.receivedInForeground = false;
completionHandler();
}
/**
* Called when the app is in the foreground.
*/
userNotificationCenterWillPresentNotificationWithCompletionHandler(center: UNUserNotificationCenter, notification: UNNotification, completionHandler: (presentationOptions: UNNotificationPresentationOptions) => void, next: () => void): void {
if (notification.request.content.userInfo.valueForKey("__NotificationType") !== "nativescript-local-notifications"
|| notification.request.trigger instanceof UNPushNotificationTrigger) {
next();
return;
}
this.receivedInForeground = true;
if (notification.request.content.userInfo.valueForKey("forceShowWhenInForeground") || notification.request.content.userInfo.valueForKey("priority")) {
completionHandler(UNNotificationPresentationOptions.Badge | UNNotificationPresentationOptions.Sound | UNNotificationPresentationOptions.Alert);
} else {
completionHandler(UNNotificationPresentationOptions.Badge | UNNotificationPresentationOptions.Sound);
}
}
}
const instance = new LocalNotificationsImpl();
export const LocalNotifications = instance;
================================================
FILE: src/package.json
================================================
{
"name": "nativescript-local-notifications",
"version": "4.2.1",
"description": "The Local Notifications plugin allows your app to show notifications when the app is not running. Just like remote push notifications, but a few orders of magnitude easier to set up.",
"main": "local-notifications",
"typings": "index.d.ts",
"nativescript": {
"platforms": {
"android": "6.0.0",
"ios": "6.0.0"
}
},
"scripts": {
"build": "npm i && tsc --skipLibCheck",
"demo.ios": "npm run build && cd ../demo && tns run ios",
"demo.android": "npm run build && cd ../demo && tns run android",
"demo-ng.ios": "npm run build && cd ../demo-ng && tns run ios",
"demo-ng.android": "npm run build && cd ../demo-ng && tns run android",
"demo-vue.ios": "npm run build && cd ../demo-vue && tns run ios --bundle",
"demo-vue.android": "npm run build && cd ../demo-vue && tns run android --bundle",
"test": "npm run tslint && npm run tslint.demo && cd ../demo && tns build ios && tns build android",
"test.ios": "cd ../demo && tns test ios --emulator",
"test.ios.device": "cd ../demo && tns test ios",
"test.android": "cd ../demo && tns test android --justlaunch",
"plugin.link": "npm link && cd ../demo && npm link nativescript-mapbox && cd ../src",
"preparedemo": "npm run build && cd ../demo && tns plugin remove nativescript-mapbox && tns plugin add ../src && tns install",
"setup": "npm run build && cd ../demo && npm i",
"setupandinstall": "npm i && cd ../demo && npm i && cd ../src && npm run build && cd ../demo && tns plugin add ../src && cd ../src",
"tslint": "tslint --config '../tslint.json' '*.ts' --exclude '**/node_modules/**'",
"tslint.demo": "tslint --config '../tslint.json' '../demo/app/*.ts' --exclude '**/node_modules/**'",
"ci.tslint": "npm i && tslint '**/*.ts' --config '../tslint.json' --exclude '**/node_modules/**' --exclude '**/platforms/**'",
"prepublishOnly": "npm run build",
"development.setup": "npm run setup && npm link && cd ../demo && npm link nativescript-mapbox && cd ../src",
"generate.typings.ios": "cd ../demo && TNS_DEBUG_METADATA_PATH=\"$(pwd)/metadata\" tns build ios && TNS_TYPESCRIPT_DECLARATIONS_PATH=\"$(pwd)/typings\" tns build ios && echo 'Now look for your library typings in demo/typings!'"
},
"repository": {
"type": "git",
"url": "https://github.com/eddyverbruggen/nativescript-local-notifications.git"
},
"keywords": [
"ecosystem:NativeScript",
"NativeScript",
"Alarm",
"Notification",
"Local Notification"
],
"author": {
"name": "Eddy Verbruggen",
"url": "https://github.com/EddyVerbruggen/"
},
"contributors": [
{
"name": "Dani Gámez Franco",
"url": "https://github.com/Danziger"
}
],
"license": "MIT",
"bugs": {
"url": "https://github.com/eddyverbruggen/nativescript-local-notifications/issues"
},
"homepage": "https://github.com/eddyverbruggen/nativescript-local-notifications",
"devDependencies": {
"nativescript-dev-typescript": "~0.10.0",
"tns-core-modules": "~6.1.2",
"tns-platform-declarations": "~6.1.2",
"tslint": "^5.10.0",
"typescript": "~3.4.5"
},
"dependencies": {
"nativescript-shared-notification-delegate": "~1.0.0"
}
}
================================================
FILE: src/platforms/ios/LocalNotificationsPlugin.framework/Headers/LocalNotificationsPlugin.h
================================================
#import
//! Project version number for LocalNotificationsPlugin.
FOUNDATION_EXPORT double LocalNotificationsVersionNumber;
//! Project version string for LocalNotificationsPlugin.
FOUNDATION_EXPORT const unsigned char LocalNotificationsPluginVersionString[];
// In this header, you should import all the public headers of your framework
#import
#import
================================================
FILE: src/platforms/ios/LocalNotificationsPlugin.framework/Headers/Notification.h
================================================
#import
#import
@interface Notification : NSObject
{
UILocalNotification *notificationMessage;
BOOL isInline;
}
@property (nonatomic, strong) UILocalNotification *notificationMessage;
@property BOOL isInline;
@property (nonatomic, retain) UILocalNotification *launchNotification;
+ (instancetype)sharedInstance;
//-(void)register:(NSMutableDictionary *)options;
//-(void)registerUserNotificationSettings:(NSDictionary*)options;
-(void)setApplicationIconBadgeNumber:(NSMutableDictionary *)options;
-(void)didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings;
-(void)notificationReceived;
-(void)success:(NSString *)eventName WithMessage:(NSString *)message;
-(void)success:(NSString *)eventName WithDictionary:(NSMutableDictionary *)userInfo;
-(void)fail:(NSString *)eventName WithMessage:(NSString *)message withError:(NSError *)error;
@end
================================================
FILE: src/platforms/ios/LocalNotificationsPlugin.framework/Headers/NotificationManager.h
================================================
#import
#import "Notification.h"
@interface NotificationManager : NSObject
@end
================================================
FILE: src/platforms/ios/LocalNotificationsPlugin.framework/Modules/module.modulemap
================================================
framework module LocalNotificationsPlugin {
umbrella header "LocalNotificationsPlugin.h"
export *
module * { export * }
}
================================================
FILE: src/platforms/ios/typings/objc!LocalNotificationsPlugin.d.ts
================================================
declare var LocalNotificationsPluginVersionString: interop.Reference;
declare var LocalNotificationsVersionNumber: number;
// @ts-ignore
declare class Notification extends NSObject implements UIApplicationDelegate {
static alloc(): Notification; // inherited from NSObject
static new(): Notification; // inherited from NSObject
static sharedInstance(): Notification;
isInline: boolean;
launchNotification: UILocalNotification;
notificationMessage: UILocalNotification;
readonly debugDescription: string; // inherited from NSObjectProtocol
readonly description: string; // inherited from NSObjectProtocol
readonly hash: number; // inherited from NSObjectProtocol
readonly isProxy: boolean; // inherited from NSObjectProtocol
readonly superclass: typeof NSObject; // inherited from NSObjectProtocol
window: UIWindow; // inherited from UIApplicationDelegate
readonly // inherited from NSObjectProtocol
applicationContinueUserActivityRestorationHandler(application: UIApplication, userActivity: NSUserActivity, restorationHandler: (p1: NSArray) => void): boolean;
applicationDidBecomeActive(application: UIApplication): void;
applicationDidChangeStatusBarFrame(application: UIApplication, oldStatusBarFrame: CGRect): void;
applicationDidChangeStatusBarOrientation(application: UIApplication, oldStatusBarOrientation: UIInterfaceOrientation): void;
applicationDidDecodeRestorableStateWithCoder(application: UIApplication, coder: NSCoder): void;
applicationDidEnterBackground(application: UIApplication): void;
applicationDidFailToContinueUserActivityWithTypeError(application: UIApplication, userActivityType: string, error: NSError): void;
applicationDidFailToRegisterForRemoteNotificationsWithError(application: UIApplication, error: NSError): void;
applicationDidFinishLaunching(application: UIApplication): void;
applicationDidFinishLaunchingWithOptions(application: UIApplication, launchOptions: NSDictionary): boolean;
applicationDidReceiveLocalNotification(application: UIApplication, notification: UILocalNotification): void;
applicationDidReceiveMemoryWarning(application: UIApplication): void;
applicationDidReceiveRemoteNotification(application: UIApplication, userInfo: NSDictionary): void;
applicationDidReceiveRemoteNotificationFetchCompletionHandler(application: UIApplication, userInfo: NSDictionary, completionHandler: (p1: UIBackgroundFetchResult) => void): void;
applicationDidRegisterForRemoteNotificationsWithDeviceToken(application: UIApplication, deviceToken: NSData): void;
applicationDidRegisterUserNotificationSettings(application: UIApplication, notificationSettings: UIUserNotificationSettings): void;
applicationDidUpdateUserActivity(application: UIApplication, userActivity: NSUserActivity): void;
applicationHandleActionWithIdentifierForLocalNotificationCompletionHandler(application: UIApplication, identifier: string, notification: UILocalNotification, completionHandler: () => void): void;
applicationHandleActionWithIdentifierForLocalNotificationWithResponseInfoCompletionHandler(application: UIApplication, identifier: string, notification: UILocalNotification, responseInfo: NSDictionary, completionHandler: () => void): void;
applicationHandleActionWithIdentifierForRemoteNotificationCompletionHandler(application: UIApplication, identifier: string, userInfo: NSDictionary, completionHandler: () => void): void;
applicationHandleActionWithIdentifierForRemoteNotificationWithResponseInfoCompletionHandler(application: UIApplication, identifier: string, userInfo: NSDictionary, responseInfo: NSDictionary, completionHandler: () => void): void;
applicationHandleEventsForBackgroundURLSessionCompletionHandler(application: UIApplication, identifier: string, completionHandler: () => void): void;
applicationHandleIntentCompletionHandler(application: UIApplication, intent: INIntent, completionHandler: (p1: INIntentResponse) => void): void;
applicationHandleOpenURL(application: UIApplication, url: NSURL): boolean;
applicationHandleWatchKitExtensionRequestReply(application: UIApplication, userInfo: NSDictionary, reply: (p1: NSDictionary) => void): void;
applicationOpenURLOptions(app: UIApplication, url: NSURL, options: NSDictionary): boolean;
applicationOpenURLSourceApplicationAnnotation(application: UIApplication, url: NSURL, sourceApplication: string, annotation: any): boolean;
applicationPerformActionForShortcutItemCompletionHandler(application: UIApplication, shortcutItem: UIApplicationShortcutItem, completionHandler: (p1: boolean) => void): void;
applicationPerformFetchWithCompletionHandler(application: UIApplication, completionHandler: (p1: UIBackgroundFetchResult) => void): void;
applicationProtectedDataDidBecomeAvailable(application: UIApplication): void;
applicationProtectedDataWillBecomeUnavailable(application: UIApplication): void;
applicationShouldAllowExtensionPointIdentifier(application: UIApplication, extensionPointIdentifier: string): boolean;
applicationShouldRequestHealthAuthorization(application: UIApplication): void;
applicationShouldRestoreApplicationState(application: UIApplication, coder: NSCoder): boolean;
applicationShouldSaveApplicationState(application: UIApplication, coder: NSCoder): boolean;
applicationSignificantTimeChange(application: UIApplication): void;
applicationSupportedInterfaceOrientationsForWindow(application: UIApplication, window: UIWindow): UIInterfaceOrientationMask;
applicationUserDidAcceptCloudKitShareWithMetadata(application: UIApplication, cloudKitShareMetadata: CKShareMetadata): void;
applicationViewControllerWithRestorationIdentifierPathCoder(application: UIApplication, identifierComponents: NSArray | string[], coder: NSCoder): UIViewController;
applicationWillChangeStatusBarFrame(application: UIApplication, newStatusBarFrame: CGRect): void;
applicationWillChangeStatusBarOrientationDuration(application: UIApplication, newStatusBarOrientation: UIInterfaceOrientation, duration: number): void;
applicationWillContinueUserActivityWithType(application: UIApplication, userActivityType: string): boolean;
applicationWillEncodeRestorableStateWithCoder(application: UIApplication, coder: NSCoder): void;
applicationWillEnterForeground(application: UIApplication): void;
applicationWillFinishLaunchingWithOptions(application: UIApplication, launchOptions: NSDictionary): boolean;
applicationWillResignActive(application: UIApplication): void;
applicationWillTerminate(application: UIApplication): void;
class(): typeof NSObject;
conformsToProtocol(aProtocol: any /* Protocol */): boolean;
didRegisterUserNotificationSettings(notificationSettings: UIUserNotificationSettings): void;
failWithMessageWithError(eventName: string, message: string, error: NSError): void;
isEqual(object: any): boolean;
isKindOfClass(aClass: typeof NSObject): boolean;
isMemberOfClass(aClass: typeof NSObject): boolean;
notificationReceived(): void;
performSelector(aSelector: string): any;
performSelectorWithObject(aSelector: string, object: any): any;
performSelectorWithObjectWithObject(aSelector: string, object1: any, object2: any): any;
respondsToSelector(aSelector: string): boolean;
retainCount(): number;
self(): this;
setApplicationIconBadgeNumber(options: NSMutableDictionary): void;
successWithDictionary(eventName: string, userInfo: NSMutableDictionary): void;
successWithMessage(eventName: string, message: string): void;
}
declare class NotificationManager extends NSObject {
static alloc(): NotificationManager; // inherited from NSObject
static new(): NotificationManager; // inherited from NSObject
}
================================================
FILE: src/references.d.ts
================================================
///
///
///
================================================
FILE: src/tsconfig.json
================================================
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"declaration": true,
"removeComments": true,
"noLib": false,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"lib": [
"es6",
"dom"
],
"sourceMap": false,
"pretty": true,
"allowUnreachableCode": false,
"allowUnusedLabels": false,
"noEmitHelpers": true,
"noEmitOnError": false,
"noImplicitAny": false,
"noImplicitReturns": true,
"noImplicitUseStrict": false,
"noFallthroughCasesInSwitch": true
},
"exclude": [
"node_modules",
"typings"
],
"compileOnSave": false
}
================================================
FILE: tslint.json
================================================
{
"rules": {
"class-name": true,
"comment-format": [
true,
"check-space"
],
"indent": [
true,
"spaces"
],
"no-duplicate-variable": true,
"no-eval": true,
"no-internal-module": true,
"no-trailing-whitespace": true,
"no-var-keyword": true,
"one-line": [
true,
"check-open-brace",
"check-whitespace"
],
"quotemark": [
true,
"double"
],
"semicolon": [
true,
"always"
],
"triple-equals": [
true,
"allow-null-check"
],
"typedef-whitespace": [
true,
{
"call-signature": "nospace",
"index-signature": "nospace",
"parameter": "nospace",
"property-declaration": "nospace",
"variable-declaration": "nospace"
}
],
"variable-name": [
true,
"ban-keywords"
],
"whitespace": [
true,
"check-branch",
"check-decl",
"check-operator",
"check-separator",
"check-type"
]
}
}