ionic-team / capacitor-plugins Goto Github PK
View Code? Open in Web Editor NEWOfficial plugins for Capacitor ⚡️
Official plugins for Capacitor ⚡️
In xcode you can now target your app for desktop by using catalyst. Device.getInfo currently returns the model info but that is currently set to "iPad" for catalyst, and no other way of detecting if the app is being run on desktop.
I suggest adding a "desktop" field or similar.
It is easy to do following this article (I've tried and verified it): https://www.hackingwithswift.com/example-code/catalyst/how-to-detect-your-ios-app-is-running-on-macos-catalyst
There are no other good ways of doing this that I know of.
Because of the rescheduling mechanism on the Android platform at device reboot or startup, it will be usefull expose a property for LocalNotifications that allows to delete (without showing) notifications older than a certain amount of time instead of presenting or rescheduling them at startup. For example, LocalNotifications generated by some sort of calendar app for an event on a certain date should not be presented if the date (at reboot/startup time) is in the past.
Android
Expose some property in the LocalNotification object named "ignoreIfOlderThan", it will be an object containing a numeric value and a time unit type:
const localNotification: LocalNotification = {
id: ID,
title: SOME_TITLE,
body: SOME_BODY,
sound: 'default',
schedule: {
at: SOME_DATE,
},
ignoreIfOlderThan: {
value: 1,
unit: "day" // or "month", "hour", "second"...
}
}
In this case the BroadcastReceiver
for startup event will check if notifications saved in LocalNotificationStorage are scheduled for the previous day and it will remove every metch.
Latest Dependencies:
@capacitor/cli: 1.4.0
@capacitor/core: 1.4.0
@capacitor/android: 1.4.0
@capacitor/ios: 1.4.0
I tested it on Android and web also
when showing notification no image is shown in the notification
when adding url and id to attachments it should show image in notification
LocalNotifications.schedule({
notifications: [
{
title: "aaaa",
body: "Body",
id: 1,
actionTypeId: 'OPEN_PRODUCT',
attachments: [
{ id: 'face', url: 'https://khanoo.com/wp-content/uploads/estate_images/house/77-1576179614/230174.jpg' }
],
schedule: {
every: "minute"
},
extra: null
}
]
});
Just test my code which i provided to see if you can see image or not
npm --version
output: 6.13.4
node --version
output: v12.13.1
pod --version
output (iOS issues only): 1.9.0.beta.2
While developing extensions in iOS, you may find a need to share application or user data between the host app and the extension.
To do so, we need to pass a "suite name" at the initialization of the userDefaults
init?(suiteName suitename: String?)
Possibility to initialize the store with a suite name.
An old cordova plugin is doing the job : https://github.com/apla/me.apla.cordova.app-preferences
May concerns Android as well.
I have used Camera
plugin to get photos from the user's media gallery (on Android), and it worked very well - however, I would also like for users to be able to import & capture videos.
Camera.getMedia({
mediaTypes: [CameraMediaType.Photo, CameraMediaType.Video],
videoQuality: CameraVideoQuality.Medium,
...
})
When CameraMediaType.Video
and CameraSource.Photos
(or should it be CameraSource.Library
?) is specified, list videos in the gallery feed alongside photos (like they appear when you use the Samsung Gallery app or similar). Accept video quality parameters similar to UIImagePickerController.QualityType
.
Currently I am using <input capture>
(see spec) but this is painfully inefficient as the media's binary data must cross the bridge as Base64 (which can take tens of seconds on slower devices). It is also unstable on iOS leading to termination of the webview.
2.3.0
android
calling Geolocation.getCurrentPosition() uses the hardware gps to get the position even if inside the cache time frame
return cached value to the promise if inside the defined cache time, right now the function is really slow since it always fetch the position from scrach
async () => {
//using ms library to compose timestamps
let options = { maximumAge: ms('5m'), timeout: ms('45s'), enableHighAccuracy: true };
let pos = await Geolocation.getCurrentPosition(options);
let pos2 = await Geolocation.getCurrentPosition(options);
}
npm --version
output: 6.14.4
node --version
output: v12.16.3
pod --version
output (iOS issues only):
You cannot read huge files as they won't fit into the RAM of your system... For writing files you can just use the append-function, but for reading files there sadly is no real solution.
All available ones
File-Streams
Create from- and to-parameter for "FileReadOptions" to define an area of the file to read.
Description of the problem:
Currently we are able to use hardware back button to exit app by listening to backButton
event and then calling App.exitApp();
:
App.addListener('backButton', (data: AppUrlOpen) => {
if (!(this.routerOutlet && this.routerOutlet.canGoBack())) {
App.exitApp();
}
});
It would be great, that if an option to Minimize App could also be added to the capacitor and we could use something like App.minimizeApp();
There's a cordova plugin https://github.com/tomloprod/cordova-plugin-appminimize for this purpose, but I believe since its a common use case, it should be added to the Capacitor.
Affected platform
OS of the development machine
I want to be able to select multiple photos from the gallery
create method getPhotos same as getPhoto just return an array
Hi,
I would like to request, if it would be possible to change the background color of the Toast plugin (Capacitor) analogous to the "normal" Ionic Framework Toast via the settings?
Some improvements:
Thanks, and great work, Im really liking capacitor 🙂
npx cap doctor
output:
@capacitor/cli 2.0.1 @capacitor/core 2.0.1 @capacitor/android 2.0.1
const data = await Filesystem.readFile({
path,
})
const { size } = await Filesystem.stat({
path,
})
No issues with Filesystem.readFile
With Filesystem.stat
the app crashed and I got the following error in the Android Studio console
2020-04-29 17:06:28.150 6188-6388/com.boomerang.app V/Capacitor/Plugin: To native (Capacitor plugin): callbackId: 77806689, pluginId: Filesystem, methodName: stat
2020-04-29 17:06:28.150 6188-6388/com.boomerang.app V/Capacitor: callback: 77806689, pluginId: Filesystem, methodName: stat, methodData: {"path":"content:\/\/com.android.providers.media.documents\/document\/image%3A24"}
2020-04-29 17:06:28.152 6188-6340/com.boomerang.app E/Capacitor: Serious error executing plugin
java.lang.reflect.InvocationTargetException
at java.lang.reflect.Method.invoke(Native Method)
at com.getcapacitor.PluginHandle.invoke(PluginHandle.java:99)
at com.getcapacitor.Bridge$1.run(Bridge.java:520)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:214)
at android.os.HandlerThread.run(HandlerThread.java:67)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'int java.lang.String.hashCode()' on a null object reference
at com.getcapacitor.plugin.Filesystem.getDirectory(Filesystem.java:67)
at com.getcapacitor.plugin.Filesystem.getFileObject(Filesystem.java:90)
at com.getcapacitor.plugin.Filesystem.stat(Filesystem.java:440)
at java.lang.reflect.Method.invoke(Native Method)
at com.getcapacitor.PluginHandle.invoke(PluginHandle.java:99)
at com.getcapacitor.Bridge$1.run(Bridge.java:520)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:214)
at android.os.HandlerThread.run(HandlerThread.java:67)
2020-04-29 17:06:28.153 6188-6340/com.boomerang.app E/AndroidRuntime: FATAL EXCEPTION: CapacitorPlugins
Process: com.boomerang.app, PID: 6188
java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
at com.getcapacitor.Bridge$1.run(Bridge.java:529)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:214)
at android.os.HandlerThread.run(HandlerThread.java:67)
Caused by: java.lang.reflect.InvocationTargetException
at java.lang.reflect.Method.invoke(Native Method)
at com.getcapacitor.PluginHandle.invoke(PluginHandle.java:99)
at com.getcapacitor.Bridge$1.run(Bridge.java:520)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:214)
at android.os.HandlerThread.run(HandlerThread.java:67)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'int java.lang.String.hashCode()' on a null object reference
at com.getcapacitor.plugin.Filesystem.getDirectory(Filesystem.java:67)
at com.getcapacitor.plugin.Filesystem.getFileObject(Filesystem.java:90)
at com.getcapacitor.plugin.Filesystem.stat(Filesystem.java:440)
at java.lang.reflect.Method.invoke(Native Method)
at com.getcapacitor.PluginHandle.invoke(PluginHandle.java:99)
at com.getcapacitor.Bridge$1.run(Bridge.java:520)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:214)
at android.os.HandlerThread.run(HandlerThread.java:67)
npx cap doctor
output:
💊 Capacitor Doctor 💊
Latest Dependencies:
@capacitor/cli: 1.2.1
@capacitor/core: 1.2.1
@capacitor/android: 1.2.1
@capacitor/ios: 1.2.1
Installed Dependencies:
@capacitor/android 1.2.1
@capacitor/ios 1.2.1
@capacitor/core 1.2.1
@capacitor/cli 1.2.1
[success] Android looking great! 👌
Found 1 Capacitor plugin for ios:
cordova-plugin-ble-central (1.2.2)
[success] iOS looking great! 👌
No output from the eventlisteners shown in the example, no error message whatsoever
output from the eventlisteners
https://github.com/kxc0re/testmotion
iOS version 13.1.2
yarn --version
output: 1.12.3
node --version
output: v11.6.0
pod --version
output (iOS issues only): 1.8.3
npx cap doctor
output:
💊 Capacitor Doctor 💊
Latest Dependencies:
@capacitor/cli: 2.1.2
@capacitor/core: 2.1.2
@capacitor/android: 2.1.2
@capacitor/electron: 2.1.2
@capacitor/ios: 2.1.2
Installed Dependencies:
@capacitor/ios not installed
@capacitor/electron not installed
@capacitor/cli 2.1.2
@capacitor/android 2.1.2
@capacitor/core 2.1.2
[success] Android looking great! 👌
If multiple parallel calls to Geolocation.getCurrentPosition()
are made, only last one returns any result, success or error.
Every call to Geolocation.getCurrentPosition()
should have it's promise fullfilled or rejected.
This shoud be the way, besides what the plugin does internally (which native API uses, cached position, ...)
const params = {
enableHighAccuracy: true,
maximumAge: 20000,
timeout: 50,
};
console.log('position 1 start')
Capacitor.Plugins.Geolocation.getCurrentPosition(params).then(
position => console.log('position 1', position),
error => console.error('position 1 error', error)
);
console.log('position 2 start')
Capacitor.Plugins.Geolocation.getCurrentPosition(params).then(
position => console.log('position 2', position),
error => console.error('position 2 error', error)
);
console.log('position 3 start')
Capacitor.Plugins.Geolocation.getCurrentPosition(params).then(
position => console.log('position 3', position),
error => console.error('position 3 error', error)
);
console.log('position 4 start')
Capacitor.Plugins.Geolocation.getCurrentPosition(params).then(
position => console.log('position 4', position),
error => console.error('position 4 error', error)
);
npx @capacitor/cli create
js/capacitor-welcome.js
file)npm --version
output: 6.14.4
node --version
output: v12.17.0
Set StatusBar style back to default on iOS if it was set manually.
Let https://github.com/ionic-team/capacitor/blob/ab1ffd576d541c2423adf422b54d0b1b0483d00e/ios/Capacitor/Capacitor/Plugins/StatusBar.swift#L16 take default
as an option, in addition to light
and dark
This would allow the framework to match iOS 13 card style modals, which automatically set the statusbar style for you (h/t @liamdebeasi)
Local notifications
It will be nice to be able to retrieve the content of a notification by its ID. We can retrieve all the pending notifications IDs via getPending(): Promise<LocalNotificationPendingList>
but then we are not able to see the content of these notifications.
Camera
Originally requested by @zyniq82 (ionic-team/capacitor#1952) with an unfinished implementation by @sandstrom (ionic-team/capacitor#2050).
The Camera plugin has strange default behavior when using width
and height
:
- if I specify both
width
andheight
, I'm sure no side is too long, but then the aspect ratio of the resulting image is changed.- if I specify only
width
orheight
, the aspect ratio is retained, but then I don't know if my prescribed value is applied to the longer or shorter side of the image, since I don't know beforehand if the image is in portrait or landscape format.-- @zyniq82
The default behavior should be to preserve the aspect ratio, even if both width
and height
are given (this is a breaking change from the core plugin). There can be an option to disable the default behavior, for example preserveAspectRatio
(which would default to true
).
iOS, Android
Description of the problem:
Affected platform
OS of the development machine
Other information:
Might be only on iPhone X and newer devices that have the bottom swipe gestures and the white bar at the bottom of the screen.
Capacitor version:1.1
node version: 9.4
npm version: 6.10.1
CocoaPods version: 1.7.4
Steps to reproduce:
If you switch from your Capacitor app to an app that has the keyboard open (such as Messages), when you switch back (specifically by swiping the bottom bar on iPhone X), the Capacitor app will be shrunk for a second as if it had the keyboard open, but with black at the bottom where the keyboard was, then it will resize itself.
Link to sample project:
Let me know if you cannot reproduce
Clipboard.write allows to pass a label.
I think it should be explained what is it for as it's Android only and it's not another type of copy, but a label to identify it.
And I'm not really sure how to use it, you add it to the write, but the read doesn't provide it back, so what is it for?
Currently, the Splash Screen plugin uses it's own ViewController that only shows the background image. A developer may have other items like logos or text on their LaunchScreen, so it should use the LaunchScreen Storyboard instead of making its own.
Secondly, since it is difficult for javascript to intercept the app state changes fast enough to display the splash screen (without creating a background task), it would be helpful if the Splash plugin could handle showing itself when the app becomes inactive. This is for apps where you don't want to show the app when it's in the background or immediately after it becomes active in case you have some authentication code you want to run first.
Here's the updated code to accomplish both of the above, on iOS at least:
SplashScreen.swift
import Foundation
import AudioToolbox
@objc(CAPSplashScreenPlugin)
public class CAPSplashScreenPlugin: CAPPlugin {
var viewController = UIViewController();
var spinner = UIActivityIndicatorView()
var showSpinner: Bool = false
var call: CAPPluginCall?
var hideTask: Any?
var isVisible: Bool = false
let launchShowDuration = 3000
let launchAutoHide = true
var pauseAutoShow = false
var resumeAutoHide = false
var resumeShowDuration = 3000
let defaultFadeInDuration = 200
let defaultFadeOutDuration = 200
let defaultShowDuration = 3000
let defaultAutoHide = true
public override func load() {
buildViews()
showOnLaunch()
NotificationCenter.default.addObserver(self, selector: #selector(pause), name: UIApplication.willResignActiveNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(resume), name: UIApplication.didBecomeActiveNotification, object: nil)
}
// Handle pause notification
@objc func pause(_ notification: Notification) {
let showOnPause = getConfigValue("pauseAutoShow") as? Bool ?? pauseAutoShow
if showOnPause {
showSplash(showDuration: defaultShowDuration, fadeInDuration: 0, fadeOutDuration: 0, autoHide: false, backgroundColor: nil, spinnerStyle: nil, spinnerColor: nil, completion: { }, isLaunchSplash: false)
}
}
// Handle resume notification
@objc func resume(_ notification: Notification) {
let hideOnResume = getConfigValue("resumeAutoHide") as? Bool ?? resumeAutoHide
if hideOnResume {
let showDuration = getConfigValue("resumeShowDuration") as? Int ?? resumeShowDuration
self.hideTask = DispatchQueue.main.asyncAfter(
deadline: DispatchTime.now() + (Double(showDuration) / 1000)
) {
self.hideSplash(fadeOutDuration: self.defaultFadeOutDuration, isLaunchSplash: false)
}
}
}
// Set the pause options
@objc public func setPauseScreen(_ call: CAPPluginCall) {
self.call = call
pauseAutoShow = call.get("pauseAutoShow", Bool.self, pauseAutoShow)!
resumeAutoHide = call.get("resumeAutoHide", Bool.self, resumeAutoHide)!
resumeShowDuration = call.get("resumeShowDuration", Int.self, resumeShowDuration)!
call.success()
}
// Show the splash screen
@objc public func show(_ call: CAPPluginCall) {
self.call = call
let showDuration = call.get("showDuration", Int.self, defaultShowDuration)!
let fadeInDuration = call.get("fadeInDuration", Int.self, defaultFadeInDuration)!
let fadeOutDuration = call.get("fadeOutDuration", Int.self, defaultFadeOutDuration)!
let autoHide = call.get("autoHide", Bool.self, defaultAutoHide)!
let backgroundColor = getConfigValue("backgroundColor") as? String ?? nil
let spinnerStyle = getConfigValue("iosSpinnerStyle") as? String ?? nil
let spinnerColor = getConfigValue("spinnerColor") as? String ?? nil
showSpinner = getConfigValue("showSpinner") as? Bool ?? false
showSplash(showDuration: showDuration, fadeInDuration: fadeInDuration, fadeOutDuration: fadeOutDuration, autoHide: autoHide, backgroundColor: backgroundColor, spinnerStyle: spinnerStyle, spinnerColor: spinnerColor, completion: {
call.success()
}, isLaunchSplash: false)
}
// Hide the splash screen
@objc public func hide(_ call: CAPPluginCall) {
self.call = call
let fadeDuration = call.get("fadeOutDuration", Int.self, defaultFadeOutDuration)!
hideSplash(fadeOutDuration: fadeDuration)
call.success()
}
func buildViews() {
viewController = UIStoryboard(name: "LaunchScreen", bundle: nil).instantiateInitialViewController()!
// Observe for changes on frame and bounds to handle rotation resizing
let parentView = bridge.viewController.view
parentView?.addObserver(self, forKeyPath: "frame", options: .new, context: nil)
parentView?.addObserver(self, forKeyPath: "bounds", options: .new, context: nil)
updateSplashImageBounds()
showSpinner = getConfigValue("showSpinner") as? Bool ?? false
if showSpinner {
spinner.translatesAutoresizingMaskIntoConstraints = false
spinner.startAnimating()
}
}
func tearDown() {
isVisible = false
bridge.viewController.view.isUserInteractionEnabled = true
viewController.view.removeFromSuperview()
if showSpinner {
spinner.removeFromSuperview()
}
}
// Update the bounds for the splash image. This will also be called when
// the parent view observers fire
func updateSplashImageBounds() {
guard let delegate = UIApplication.shared.delegate else {
bridge.modulePrint(self, "Unable to find root window object for SplashScreen bounds. Please file an issue")
return
}
guard let window = delegate.window as? UIWindow else {
bridge.modulePrint(self, "Unable to find root window object for SplashScreen bounds. Please file an issue")
return
}
viewController.view.frame = CGRect(origin: CGPoint(x: 0, y: 0), size: window.bounds.size)
}
public override func observeValue(forKeyPath keyPath: String?, of object: Any?, change _: [NSKeyValueChangeKey: Any]?, context: UnsafeMutableRawPointer?) {
updateSplashImageBounds()
}
func showOnLaunch() {
let launchShowDurationConfig = getConfigValue("launchShowDuration") as? Int ?? launchShowDuration
let launchAutoHideConfig = getConfigValue("launchAutoHide") as? Bool ?? launchAutoHide
let launchBackgroundColorConfig = getConfigValue("backgroundColor") as? String ?? nil
let launchSpinnerStyleConfig = getConfigValue("iosSpinnerStyle") as? String ?? nil
let launchSpinnerColorConfig = getConfigValue("spinnerColor") as? String ?? nil
let view = bridge.viewController.view
view?.addSubview(viewController.view)
if showSpinner {
view?.addSubview(spinner)
spinner.centerXAnchor.constraint(equalTo: view!.centerXAnchor).isActive = true
spinner.centerYAnchor.constraint(equalTo: view!.centerYAnchor).isActive = true
}
showSplash(showDuration: launchShowDurationConfig, fadeInDuration: 0, fadeOutDuration: defaultFadeOutDuration, autoHide: launchAutoHideConfig, backgroundColor: launchBackgroundColorConfig, spinnerStyle: launchSpinnerStyleConfig, spinnerColor: launchSpinnerColorConfig, completion: {
}, isLaunchSplash: true)
}
func showSplash(showDuration: Int, fadeInDuration: Int, fadeOutDuration: Int, autoHide: Bool, backgroundColor: String?, spinnerStyle: String?, spinnerColor: String?, completion: @escaping () -> Void, isLaunchSplash: Bool) {
DispatchQueue.main.async {
if backgroundColor != nil {
self.viewController.view.backgroundColor = UIColor(fromHex: backgroundColor!)
}
let view = self.bridge.viewController.view
if self.showSpinner {
if spinnerStyle != nil {
switch spinnerStyle!.lowercased() {
case "small":
self.spinner.style = .white
default:
self.spinner.style = .whiteLarge
}
}
if spinnerColor != nil {
self.spinner.color = UIColor(fromHex: spinnerColor!)
}
}
if !isLaunchSplash {
view?.addSubview(self.viewController.view)
if self.showSpinner {
view?.addSubview(self.spinner)
self.spinner.centerXAnchor.constraint(equalTo: view!.centerXAnchor).isActive = true
self.spinner.centerYAnchor.constraint(equalTo: view!.centerYAnchor).isActive = true
}
}
view?.isUserInteractionEnabled = false
UIView.transition(with: self.viewController.view, duration: TimeInterval(Double(fadeInDuration) / 1000), options: .curveLinear, animations: {
self.viewController.view.alpha = 1
if self.showSpinner {
self.spinner.alpha = 1
}
}) { (finished: Bool) in
self.isVisible = true
if autoHide {
self.hideTask = DispatchQueue.main.asyncAfter(
deadline: DispatchTime.now() + (Double(showDuration) / 1000)
) {
self.hideSplash(fadeOutDuration: fadeOutDuration, isLaunchSplash: isLaunchSplash)
completion()
}
}
}
}
}
func hideSplash(fadeOutDuration: Int) {
hideSplash(fadeOutDuration: fadeOutDuration, isLaunchSplash: false)
}
func hideSplash(fadeOutDuration: Int, isLaunchSplash: Bool) {
if isLaunchSplash, isVisible {
CAPLog.print("SplashScreen.hideSplash: SplashScreen was automatically hidden after default timeout. " +
"You should call `SplashScreen.hide()` as soon as your web app is loaded (or increase the timeout). " +
"Read more at https://capacitor.ionicframework.com/docs/apis/splash-screen/#hiding-the-splash-screen")
}
if !isVisible { return }
DispatchQueue.main.async {
UIView.transition(with: self.viewController.view, duration: TimeInterval(Double(fadeOutDuration) / 1000), options: .curveLinear, animations: {
self.viewController.view.alpha = 0
if self.showSpinner {
self.spinner.alpha = 0
}
}) { (finished: Bool) in
self.tearDown()
}
}
}
}
When using LocalNotifications plugin on iOS (web), you'll get that error when trying to request permissions. Should be handled to return a proper error.
preserveAspectRatio
is deprecated and not really used, remove before @capacitor/camera 2.0.0 is released
I'd like to schedule recurring local notifications on Tuesdays and Thursdays at a given hour.
I'd like to schedule it using the on
keyword together with a (new) weekday
(0-6) keyword.
I don't see a way around this, as day
is only 0-30. I could use every
— but that doesn't let me set the hour of delivery. ionic-team/capacitor#2752 goes into further detail.
schedule: {
on: {
hour: 20,
weekday: 2
}
},
...
schedule: {
on: {
hour: 20,
weekday: 4
}
},
weekday
, support so it could easily be added in LocalNotifications.swift
from what I gather.LocalNotificationsSchedule.java
we are using SimpleDateFormat
which has a u
— day number of week (1-7) support.Filesystem
Since the target of cordova-plugin-file
's dataDirectory
used to be the library folder on iOS, it would great to also have the library directory as option to read from with the filesystem plugin.
iOS
For implementation, one would have to add the new directory to the definitions file and add a case to the switch statement within the native swift code. For android, a fall-back to the files folder would do the trick.
x
x
Description of the problem:
When the user tries to access the Filesystem without having the permission, the user gets prompted to grant such permission. If in the meantime another request is made, after the user grants the permission the result of the first call is returned to the second request.
More in detail there’s no way to have two calls in progress at the same time,
so mkdir
will call requestPermissions()
and set savedLastCall
stat
will also call requestPermissions()
and overwrite savedLastCall
Affected platform
OS of the development machine
Capacitor version:
Master at sha
https://github.com/ionic-team/capacitor/tree/519b9b3d5abacaa232af810fa9dbc952cdec693b
Steps to reproduce:
In the browser console for the example app type:
Capacitor.Plugins.Filesystem.mkdir({path: 'foooooooo', directory: 'DOCUMENTS'}).then(console.log, console.error)
Then, without granting the permission on the app, type:
Capacitor.Plugins.Filesystem.stat({path: 'foooooooo', directory: 'DOCUMENTS'}).then(console.log, console.error)
Then grant the filesystem permission on the app and you will get the result of the first call mkdir
to the stat
call.
A push notification send through firebase isn't triggering the code located within the addEventListener
for pushNotificationReceived
.
Installed Dependencies:
@capacitor/cli 1.4.0
@capacitor/core 1.4.0
@capacitor/android 1.4.0
@capacitor/ios 1.4.0
Currently when a data notification is pushed through Firebase, to a device which is no longer in the foreground ( has been (non forcefully) killed by swiping it away in the recent application viewer):
The notification is handled by CapacitorFirebaseMessagingService#onMessageReceived yet it is never handled by the pushNotificationReceived
within the application code (like it should according to the documentation).
The reason for this is the fact that PushNotifications#sendRemoteMessage expects the bridge
to be set within: PushNotifications#getPushNotificationsInstance. This is however never the case as the plugin load
method is not called as such the static staticBridge
is never assigned. And the call is never relayed down to the application Typescript code.
I would expect the getPushNotificationsInstance
method to initialize the application / load it so the staticBridge
property is set. Otherwise the documentation will have to be updated to reflect the fact that listening for pushNotificationReceived
only works when the application is active and the user hasn't (none forcefully) killed the app by swiping it away within the recent application viewer.
{
"to": "<<address>>",
"data" : {
"body" : "Body of Your Notification in data"
},
"priority": "high"
}
Code within the AppComponent
...
async initializePushNotificationListener() {
console.debug("AppComponent#initializePushNotificationListener initializing notification listeners");
await PushNotifications.register();
console.debug("AppComponent#initializePushNotificationListener notification listeners registered");
// On success, we should be able to receive notifications
PushNotifications.addListener("registration", (token: PushNotificationToken) => {
// tslint:disable-next-line:max-line-length
console.debug(`AppComponent#initializePushNotificationListener Push registration success, token: ${token.value}`);
});
PushNotifications.addListener("registrationError",
(error: any) => {
alert("Error on registration: " + JSON.stringify(error));
}
);
// Show us the notification payload if the app is open on our device
PushNotifications.addListener("pushNotificationReceived",
(notification: PushNotification) => {
console.info("AppComponent#initializePushNotificationListener notification received", notification);
LocalNotifications.schedule({
notifications: [
{
title: "Title",
body: "Body",
id: 1,
schedule: {at: new Date(Date.now() + 1000 * 20)},
sound: null,
attachments: null,
actionTypeId: "",
extra: null
}
]
}).catch(error => {
console.debug("AppComponent#initializePushNotificationListener notifications denied", error);
});
}
);
// Method called when tapping on a notification
PushNotifications.addListener("pushNotificationActionPerformed",
(notification: PushNotificationActionPerformed) => {
alert("Push action performed: " + JSON.stringify(notification));
}
);
}
...
npm --version
output: 6.11.3
node --version
output: 10.17.0
Tested on two different devices:
Might relate to: ionic-team/capacitor#1928 (comment)
The problem I am having is that when I schedule a local notification for a future date, the notification will be displayed with the time the local notification was created as the timestamp, not the time the notification was scheduled.
A few months ago, Apple announced that Safari will expire localStorage entries for domains that are inactive for 7 days.
Maybe device.ts should store the uid in a cookie instead of localStorage?
💊 Capacitor Doctor 💊
Latest Dependencies:
@capacitor/cli: 2.2.0
@capacitor/core: 2.2.0
@capacitor/android: 2.2.0
@capacitor/electron: 2.2.0
@capacitor/ios: 2.2.0
Installed Dependencies:
@capacitor/ios not installed
@capacitor/electron not installed
@capacitor/cli 2.1.2
@capacitor/core 2.1.2
@capacitor/android 2.2.0
[success] Android looking great! 👌
The android keyboard overlay the input on the screen when the StatusBar.overlay is set to true
The screen should scroll to the focused input.
This has been resolved in the ionic cordova keyboard plugin by adding a resizeOnFullscreen preference. Do we have anything like this in capacitor keyboard.
When using the camera plugin on both Android and iOS most or all EXIF data is stripped from the image. On Android all attributes are stripped, and on iOS only Orientation
, ExifIFDPointer
, ColorSpace
, PixelXDimension
and PixelYDimension
are returned.
I could see this being handled in the following ways:
A) Return an EXIF dictionary with the image path
B) Retain the original EXIF data on the image itself
I think providing both is ideal, as A) would allow the client to use the EXIF data without needing to use a third-party library for using the EXIF data within the app. Additionally, B) allows for a direct upload for server-side parsing without needing to write the EXIF data back to the image client-side.
I am using the following code to test this:
import { Plugins, CameraResultType, CameraSource } from '@capacitor/core'
const { Camera } = Plugins
import { EXIF } from 'exif-js'
async getPhoto() {
const image = await Camera.getPhoto({
quality: 100,
correctOrientation: true,
resultType: CameraResultType.Uri,
source: CameraSource.Prompt
})
EXIF.getData({ src: image.webPath }, function(error) {
if (error) {
console.log(error)
}
var allMetaData = EXIF.getAllTags(this);
console.log('ALL TAGS - ', allMetaData)
let lng = EXIF.getTag(this, 'GPSLongitude') || null
let lat = EXIF.getTag(this, 'GPSLatitude') || null
console.log('LNG - ', lng)
console.log('LAT - ', lat)
})
}
I don't have experience writing Swift or Java, but if there is anything I can do to help implement this please let me know!
Handle Android InboxStyle and BigTextStyle of NotificationCompat
.
Android
Explicit properties from JS for advanced styling of notifications.
Description of the problem:
The docs say I should get a jpg back from capacitor:
https://capacitor.ionicframework.com/docs/apis/camera/
// The url starting with 'data:image/jpeg;base64,' and the base64 encoded string representation of the image, if using CameraResultType.DataUrl.
dataUrl ?: string;
When testing in the browser, I'm getting a png (e.g. data:image/png;base64,iVBO...). I need consistent or controllable behaviour of the image format.
Affected platform
OS of the development machine
Other information:
Capacitor version: 1.1.0
node version: 10.16.0
npm version: 6.9.0
Steps to reproduce:
Take a picture:
const { Camera } = Plugins;
const image = await Camera.getPhoto({
quality: 90,
allowEditing: false,
resultType: CameraResultType.DataUrl,
source: CameraSource.Prompt
});
Put a breakpoint on the result, you'll see the data url is png.
npx cap doctor
output:
Latest Dependencies:
@capacitor/cli: 1.3.0
@capacitor/core: 1.3.0
@capacitor/android: 1.3.0
@capacitor/ios: 1.3.0
Installed Dependencies:
@capacitor/android not installed
@capacitor/cli 1.3.0
@capacitor/core 1.3.0
@capacitor/ios 1.3.0
The plugin doesn't detect the network state changes (see steps to reproduce)
The plugin should detect the network state changes correctly
initializeApp
function in app.component.ts
as followsimport {Plugins} from '@capacitor/core';
initializeApp() {
this.platform.ready().then(() => {
Plugins.Network.addListener('networkStatusChange', (status) => console.log('network', status));
setInterval(() => Plugins.Network.getStatus().then((status) => console.log('status interval', status)), 10000);
this.statusBar.styleDefault();
this.splashScreen.hide();
});
}
Make more Browser Options
I use Capacitor Brower to make a Authentication Service, it's work fine, but without a clearCache, when an user logged is opening the auth link, the user is connected directly without the possibility to connect with another account
Could be nice to have
Android
iOS
FileSystem
The FileSystem plugin should support binary data when using appendFile
, readFile
, and writeFile
. An encoding
key could be provided when working with utf8 encoded data.
To represent binary data in JS, Blobs (part of the File API spec) should be used because they best represent file contents: immutable, potentially (but not necessarily) encoded, potentially (but not necessarily) with an associated mime type. Blobs can be converted to ArrayBuffers or streams for alternative use cases.
the event "keyboardWillShow" on Keyboard plugin triggered after keyboard is show on android
npx cap doctor
output:
💊 Capacitor Doctor 💊
Latest Dependencies:
@capacitor/cli: 1.4.0
@capacitor/core: 1.4.0
@capacitor/android: 1.4.0
@capacitor/ios: 1.4.0
Installed Dependencies:
@capacitor/cli 1.4.0
@capacitor/core 1.4.0
@capacitor/ios 1.4.0
@capacitor/android 1.4.0
[success] Android looking great! 👌
Found 5 Capacitor plugins for ios:
cordova-plugin-badge (0.8.8)
cordova-plugin-camera (4.1.0)
cordova-plugin-email (1.2.7)
cordova-plugin-mediapicker-dmcsdk (2.4.7)
cordova-plugin-simple-image-resizer (0.2.0)
[success] iOS looking great! 👌
On android 8 with Samsung A8, the event keyboardWillShow triggered after the keyboard show.
the event should be triggered before the keyboard show
// same effect on all listeners
Keyboard.addListener("keyboardWillShow", () => alert('keyboardWillShow'));
window.addEventListener("keyboardWillShow", () => alert('keyboardWillShow'));
Focus to input text
npm --version
output: 6.11.2
node --version
output: v11.2.0
pod --version
output (iOS issues only):
This is a list of all published files from the TextZoom plugin, but we should ignore the same patterns in all plugins (files
? .npmignore
?):
CHANGELOG.md
CapacitorTextZoom.podspec
android/.gradle/6.1.1/executionHistory/executionHistory.bin
android/.gradle/6.1.1/executionHistory/executionHistory.lock
android/.gradle/6.1.1/fileChanges/last-build.bin
android/.gradle/6.1.1/fileContent/fileContent.lock
android/.gradle/6.1.1/fileHashes/fileHashes.bin
android/.gradle/6.1.1/fileHashes/fileHashes.lock
android/.gradle/6.1.1/fileHashes/resourceHashesCache.bin
android/.gradle/6.1.1/gc.properties
android/.gradle/6.1.1/javaCompile/classAnalysis.bin
android/.gradle/6.1.1/javaCompile/jarAnalysis.bin
android/.gradle/6.1.1/javaCompile/javaCompile.lock
android/.gradle/6.1.1/javaCompile/taskHistory.bin
android/.gradle/buildOutputCleanup/buildOutputCleanup.lock
android/.gradle/buildOutputCleanup/cache.properties
android/.gradle/buildOutputCleanup/outputFiles.bin
android/.gradle/checksums/checksums.lock
android/.gradle/vcs-1/gc.properties
android/build.gradle
android/gradle.properties
android/gradle/wrapper/gradle-wrapper.jar
android/gradle/wrapper/gradle-wrapper.properties
android/gradlew
android/gradlew.bat
android/proguard-rules.pro
android/settings.gradle
android/src/androidTest/java/com/getcapacitor/android/ExampleInstrumentedTest.java
android/src/main/AndroidManifest.xml
android/src/main/java/com/capacitorjs/plugins/textzoom/TextZoom.java
android/src/main/java/com/capacitorjs/plugins/textzoom/TextZoomPlugin.java
android/src/main/res/layout/bridge_layout_main.xml
android/src/test/java/com/getcapacitor/ExampleUnitTest.java
dist/esm/definitions.d.ts
dist/esm/definitions.js
dist/esm/definitions.js.map
dist/esm/index.d.ts
dist/esm/index.js
dist/esm/index.js.map
dist/esm/ios.d.ts
dist/esm/ios.js
dist/esm/ios.js.map
dist/plugin.js
dist/plugin.js.map
ios/Plugin.xcodeproj/project.pbxproj
ios/Plugin.xcodeproj/project.xcworkspace/contents.xcworkspacedata
ios/Plugin.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
ios/Plugin.xcodeproj/xcshareddata/xcschemes/Plugin.xcscheme
ios/Plugin.xcodeproj/xcshareddata/xcschemes/PluginTests.xcscheme
ios/Plugin.xcworkspace/contents.xcworkspacedata
ios/Plugin.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
ios/Plugin/Info.plist
ios/Plugin/TextZoom.swift
ios/Plugin/TextZoomPlugin.h
ios/Plugin/TextZoomPlugin.m
ios/Plugin/TextZoomPlugin.swift
ios/PluginTests/Info.plist
ios/PluginTests/PluginTests.swift
ios/Podfile
ios/Podfile.lock
ios/Pods/Local Podspecs/Capacitor.podspec.json
ios/Pods/Local Podspecs/CapacitorCordova.podspec.json
ios/Pods/Manifest.lock
ios/Pods/Pods.xcodeproj/project.pbxproj
ios/Pods/Pods.xcodeproj/xcuserdata/dan.xcuserdatad/xcschemes/Capacitor.xcscheme
ios/Pods/Pods.xcodeproj/xcuserdata/dan.xcuserdatad/xcschemes/CapacitorCordova.xcscheme
ios/Pods/Pods.xcodeproj/xcuserdata/dan.xcuserdatad/xcschemes/Pods-Plugin.xcscheme
ios/Pods/Pods.xcodeproj/xcuserdata/dan.xcuserdatad/xcschemes/Pods-PluginTests.xcscheme
ios/Pods/Pods.xcodeproj/xcuserdata/dan.xcuserdatad/xcschemes/xcschememanagement.plist
ios/Pods/Target Support Files/Capacitor/Capacitor-Info.plist
ios/Pods/Target Support Files/Capacitor/Capacitor-dummy.m
ios/Pods/Target Support Files/Capacitor/Capacitor-prefix.pch
ios/Pods/Target Support Files/Capacitor/Capacitor-umbrella.h
ios/Pods/Target Support Files/Capacitor/Capacitor.debug.xcconfig
ios/Pods/Target Support Files/Capacitor/Capacitor.modulemap
ios/Pods/Target Support Files/Capacitor/Capacitor.release.xcconfig
ios/Pods/Target Support Files/CapacitorCordova/CapacitorCordova-Info.plist
ios/Pods/Target Support Files/CapacitorCordova/CapacitorCordova-dummy.m
ios/Pods/Target Support Files/CapacitorCordova/CapacitorCordova-prefix.pch
ios/Pods/Target Support Files/CapacitorCordova/CapacitorCordova-umbrella.h
ios/Pods/Target Support Files/CapacitorCordova/CapacitorCordova.debug.xcconfig
ios/Pods/Target Support Files/CapacitorCordova/CapacitorCordova.modulemap
ios/Pods/Target Support Files/CapacitorCordova/CapacitorCordova.release.xcconfig
ios/Pods/Target Support Files/Pods-Plugin/Pods-Plugin-Info.plist
ios/Pods/Target Support Files/Pods-Plugin/Pods-Plugin-acknowledgements.markdown
ios/Pods/Target Support Files/Pods-Plugin/Pods-Plugin-acknowledgements.plist
ios/Pods/Target Support Files/Pods-Plugin/Pods-Plugin-dummy.m
ios/Pods/Target Support Files/Pods-Plugin/Pods-Plugin-umbrella.h
ios/Pods/Target Support Files/Pods-Plugin/Pods-Plugin.debug.xcconfig
ios/Pods/Target Support Files/Pods-Plugin/Pods-Plugin.modulemap
ios/Pods/Target Support Files/Pods-Plugin/Pods-Plugin.release.xcconfig
ios/Pods/Target Support Files/Pods-PluginTests/Pods-PluginTests-Info.plist
ios/Pods/Target Support Files/Pods-PluginTests/Pods-PluginTests-acknowledgements.markdown
ios/Pods/Target Support Files/Pods-PluginTests/Pods-PluginTests-acknowledgements.plist
ios/Pods/Target Support Files/Pods-PluginTests/Pods-PluginTests-dummy.m
ios/Pods/Target Support Files/Pods-PluginTests/Pods-PluginTests-frameworks.sh
ios/Pods/Target Support Files/Pods-PluginTests/Pods-PluginTests-umbrella.h
ios/Pods/Target Support Files/Pods-PluginTests/Pods-PluginTests.debug.xcconfig
ios/Pods/Target Support Files/Pods-PluginTests/Pods-PluginTests.modulemap
ios/Pods/Target Support Files/Pods-PluginTests/Pods-PluginTests.release.xcconfig
package.json
npx cap doctor
output:
Capacitor Doctor
Latest Dependencies:
@capacitor/cli: 2.0.0
@capacitor/core: 2.0.0
@capacitor/android: 2.0.0
@capacitor/electron: 2.0.0
@capacitor/ios: 2.0.0
Installed Dependencies:
@capacitor/ios not installed
@capacitor/electron not installed
@capacitor/cli 2.0.0
@capacitor/core 2.0.0
@capacitor/android 2.0.0
[success] Android looking great! �👌
it seems when I use the getPhoto
API with it's options quality, width and height those get ignored by the android camera. I recieve a big size image and the dimensions are not what I used regarding I expect a small image.
I was testing with my laptop camera and it was work Ok ( iI think is beacause is a VGA), and when I started to test on my phone (a huawei mate 10) I realized.
It would be great that the camera method returns a image with the correct properties predifined.
I need this to get an image with at least 500kb size.
image = await Camera.getPhoto({
quality: 10,
height: 1280,
width: 960,
allowEditing: false,
saveToGallery: true,
direction: CameraDirection.Rear,
source: CameraSource.Camera,
resultType: CameraResultType.DataUrl
});
but when I want to upload mi image to internet its weight is to big
npm --version
output: 6.13.4
node --version
output:v 12.14.1
It would be nice to know the current WebView version on a device.
The device plugin already returns several information about the device - like OS version etc.
This feature request is about extending the device information with the current WebView version.
Android pseudo code
PackageInfo pInfo = WebView.getCurrentWebViewPackage();
r.put("webViewVersion", pInfo.versionName); // e.g. 69.0.3497.100
Android
iOS
https://www.npmjs.com/package/@capacitor/text-zoom
"Unable to find a readme for @capacitor/[email protected]"
ScreenReader (or a new plugin?)
While working with a member of the Capacitor community, there was a strong desire for the ability to have Capacitor expose functionality related to device zoom size.
Exposing this functionality would enable this member to implement accessibility best practices into their design for users with visual impairments.
It would be ideal to have a Capacitor plugin expose the following functionality:
getTextZoom(): Promise<number>
setTextZoom(number): Promise<void>
updateTextZoom(): Promise<number>
usePreferredTextZoom(boolean): Promise<void>
false
, set the WebView zoom percentage to 100. If true
, retrieve the device's preferred text zoom from settings and apply it to the WebViewiOS WebKit provides a mechanism to obtain the system font in CSS, but it appears this is not the case with Android.
phonegap-mobile-accessibility
is a Cordova plugin that provides this functionality last updated 4 years ago. The lack of maintenance is a concern of the community member.
source: CameraSource.Prompt and CameraSource.Photos have no effect on browser. It always opens my webcam instead of poping up the actionsheet or image picker. I tried the example https://github.com/ionic-team/capacitor/tree/master/example/src/pages/camera. All buttons opened my webcam directly. The plugin worked on ios&android simulator as expected.
$ ionic info
cli packages: (/usr/local/lib/node_modules)
@ionic/cli-utils : 1.19.2
ionic (Ionic CLI) : 3.20.0
global packages:
cordova (Cordova CLI) : 7.1.0
local packages:
@ionic/app-scripts : 3.1.2
Cordova Platforms : none
Ionic Framework : ionic-angular 3.9.2
System:
ios-deploy : 1.9.1
ios-sim : 5.0.6
Node : v8.9.1
npm : 5.5.1
OS : macOS Sierra
Xcode : Xcode 9.2 Build version 9C40b
Environment Variables:
ANDROID_HOME : not set
Misc:
backend : pro
iOS (and some Android) notification payloads often contain the number of unread notifications, however currently this value can't be used. Support setting and getting the notification badge count by implementing getBadgeCount
and setBadgeCount
methods.
I notice this feature has been mentioned in other issues too (#1301 ionic-team/capacitor#837 etc). It is also currently a supported feature of the phonegap push plugin. See push.setApplicationIconBadgeNumber
and push.getApplicationIconBadgeNumber
at https://github.com/phonegap/phonegap-plugin-push/blob/master/docs/API.md
Add getBadgeCount
and setBadgeCount
methods
npx cap doctor
output:
Latest Dependencies:
@capacitor/cli: 1.4.0
@capacitor/core: 1.4.0
@capacitor/android: 1.4.0
@capacitor/ios: 1.4.0
Installed Dependencies:
@capacitor/cli 1.3.0
@capacitor/core 1.3.0
@capacitor/ios 1.3.0
@capacitor/android 1.3.0
The LocalNotification addListener function for eventName: "localNotificationReceived" does not appear to fire.
For example, when
LocalNotifications.addListener('localNotificationReceived', (notification) => {
console.log('local notification received');
});
is used in the code, the console log is never logged for android when the notification is fired.
The console.log (in the example above) or the desired behaviour would be triggered when the notification is fired/received.
LocalNotifications.addListener('localNotificationReceived', (notification) => {
console.log('local notification received');
});
npm --version
output: 6.10.3
node --version
output: v12.9.1
pod --version
output (iOS issues only):
Capacitor 3 Splash Screen
Splash screen typically have a logo or other feature in the center of the screen. Currently the spinner on the Splash Screen plugin is fixed to the center horizontally and vertically. Being able to configure the spinner to appear elsewhere on the screen would be useful.
iOS
Android
Add an option to capacitor.config.json to determine the position of the spinner, ie TOP CENTER, MIDDLE CENTER, BOTTOM CENTER, TOP LEFT, etc.
i've achieved this on iOS by changing Pods > Development Pods > Capacitor > Plugins > SplashScreen.swift lines 128 and 164 from
self.spinner.centerYAnchor.constraint(equalTo: view!.centerYAnchor).isActive = true
to
self.spinner.bottomAnchor.constraint(equalTo: view!.safeAreaLayoutGuide.bottomAnchor).isActive = true
This moves it to the bottom center - the addition of the .safeAreaLayoutGuide ensures it doesn't cover the gesture bar on iPhone 10+
I don't have a solution for Android yet, but Google searching suggests that can be changed in the .java file also.
Based on a post here ionic-team/capacitor#3508 and the suggestion to post this as a feature request.
HapticsWeb (extends WebPlugin implements HapticsPlugin)
Haptics has native implementations, but no web implementation. The web plugin will make use of the web Vibration API to deliver functionality on vibration enabled devices (i.e. mobile). Note that some browsers implement permissions i.e. prompting the user to allow vibration when first run.
Web
A Capacitor plugin which exposes the following functionality:
Vibration | Example Code | Behaviour |
---|---|---|
Once | navigator.vibrate(1000) or navigator.vibrate([1000]) |
Vibrate for 1000ms |
Sequence | navigator.vibrate([50, 100, 150]) |
Vibrate for 50ms, still for 100ms, vibrate for 150ms |
Cancel | navigator.vibrate(0) or navigator.vibrate([]) |
Cancels any existing vibrations |
export declare type HapticsWebVibratePattern = number | number[]
export declare class HapticsWeb extends WebPlugin implements HapticsPlugin {
constructor()
impact(): void;
notification(): void;
vibrate(options: HapticsWebVibratePattern): Promise<any>
selectionStart(): void;
selectionChanged(): void;
selectionEnd(): void;
}
HapticsWeb.prototype.vibrate = function (options) {
if (!navigator.vibrate) {
return Promise.reject('Web Haptics API not available');
}
return navigator.vibrate(options);
};
W3C Vibration API: https://www.w3.org/TR/vibration/
Google Chrome Samples: https://googlechrome.github.io/samples/vibration/
MDN Web Docs: https://developer.mozilla.org/en-US/docs/Web/API/Vibration_API/
Hello,
I'm talking about this file line 9 and 58
https://github.com/ionic-team/capacitor/blob/master/core/src/web/storage.ts
We already have an existing application and the current Web version of Storage will not read the existing values from local storage due to this KEY_PREFIX.
I can see this is being used for clear()
and keys()
etc but right now it's breaking existing applications. I guess we can force KEY_PREFIX to an empty string for now but this should be improved in my opinion.
Thank you!
Is this supposed to work/be implemented or just not possible in android? Or is there a workaround? I need the keyboard to cover the webview like it does in iOS.
It would be nice if one could schedule an interval notification (e.g. every day) but with a custom startTime.
Consider the following example:
notifications: [{
// ....
schedule: {
every: 'day'
}
// ....
}]
This schedules a notification that triggers every day from NOW on. So if one would schedule a notification at 11:00 am, it would trigger the next day at 11:00 am, and so on...
What I'm looking for is something like "remind every day on 08:00 am", so for example:
notifications: [{
// ....
schedule: {
every: 'day',
startDate: aSpecificStartDate
}
// ....
}]
This should be fairly easy to implement. Looking at the Android source, startTime
needs to be configurable. (For the swift sources is's almost the same)
I would suggest to introduce a new property startTime
for the schedule
object. For me, this seems to be the most straightforward way, plus is stays backwards compatible.
Any thoughts on this? If you guys are okay with that solution I would give it a try and submit a pull request.
Or maybe am I missing something and there is a workaround for my problem?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.