I am using Xam.Plugins.Notifier package to implement Local Notification in Xamarin.Forms project.
Here is the code what I wrote in PCL project.
CrossLocalNotifications.Current.Show("Title", "Description");
It works good on Android but It doesn't work on IOS.
I am not sure if it works on lower IOS sdk.
Anyway it doesn't work on IOS 11.
Here is the code that I added in AppDelegate.cs
if (UIDevice.CurrentDevice.CheckSystemVersion(10, 0))
{
// Ask the user for permission to get notifications on iOS 10.0+
UNUserNotificationCenter.Current.RequestAuthorization(
UNAuthorizationOptions.Alert | UNAuthorizationOptions.Badge | UNAuthorizationOptions.Sound,
(approved, error) => { });
}
else if (UIDevice.CurrentDevice.CheckSystemVersion(8, 0))
{
// Ask the user for permission to get notifications on iOS 8.0+
var settings = UIUserNotificationSettings.GetSettingsForTypes(
UIUserNotificationType.Alert | UIUserNotificationType.Badge | UIUserNotificationType.Sound,
new NSSet());
UIApplication.SharedApplication.RegisterUserNotificationSettings(settings);
}
Can anybody help me to fix it?
I want to have this package working on IOS.
Thanks.
Which scenario does it not work ? Active or in background?
If it doesn't work when it is active , you may forget to handle the delegate (subclasses UNUserNotificationCenterDelegate)
Modify your code as below:
if (UIDevice.CurrentDevice.CheckSystemVersion(10, 0))
{
// Ask the user for permission to get notifications on iOS 10.0+
UNUserNotificationCenter.Current.RequestAuthorization(
UNAuthorizationOptions.Alert | UNAuthorizationOptions.Badge | UNAuthorizationOptions.Sound,
(approved, error) => { });
// Watch for notifications while app is active
UNUserNotificationCenter.Current.Delegate = new UserNotificationCenterDelegate();
}
Create a subclass UserNotificationCenterDelegate
public class UserNotificationCenterDelegate : UNUserNotificationCenterDelegate
{
public override void WillPresentNotification(UNUserNotificationCenter center, UNNotification notification, Action<UNNotificationPresentationOptions> completionHandler)
{
// Tell system to display the notification anyway or use
// `None` to say we have handled the display locally.
completionHandler(UNNotificationPresentationOptions.Alert);
}
}
Related
ORIGINAL QUESTION:
My apps statusbar does not seem to react to android system theme changes while the app is loaded.
The statusbar only updates after a restart. Please see videos below:
This video shows the light theme correctly applied to the app's statusbar when loaded. But after loading the app, if the user changes the system theme to dark, the statusbar of the app does not update until the app is restarted.
Light to dark theme example video.
This video shows the dark theme correctly applied to the app's statusbar when loaded. But after loading the app, if the users changes the system theme to light, the statusbar of the app does not update until the app is restarted.
Dark to light theme example video.
Anyone know how to get the statusbar to react to system theme changes while having the app loaded?
UPDATE 1:
The following returns the value of the selected theme in the console, but as soon as I uncomment Application.Current.UserAppTheme = AppTheme.Dark; no values are returned in the console when I change the system theme.
private void ChangeTheme()
{
Application.Current.RequestedThemeChanged += (s, a) =>
{
AppTheme currentTheme = Application.Current.RequestedTheme;
if (currentTheme is AppTheme.Dark)
{
Console.WriteLine(currentTheme.ToString());
//Application.Current.UserAppTheme = AppTheme.Dark;
}
else if (currentTheme is AppTheme.Light)
{
Console.WriteLine(currentTheme.ToString());
}
};
}
UPDATE 2:
I am using 2 different styles.xml files in Platforms > Android > Resources > values and values-night to set the statusbarcolor.
In your MainActivity.cs you can override the OnConfigurationChanged() method and listen to UI configuration changes:
public override void OnConfigurationChanged(Configuration newConfig)
{
base.OnConfigurationChanged(newConfig);
if (Build.VERSION.SdkInt < BuildVersionCodes.R)
{
return;
}
if (newConfig.IsNightModeActive)
{
Window?.SetStatusBarColor(Colors.Black.ToAndroid());
Window?.InsetsController?.SetSystemBarsAppearance(0, (int)WindowInsetsControllerAppearance.LightStatusBars);
}
else
{
Window?.SetStatusBarColor(Colors.White.ToAndroid());
Window?.InsetsController?.SetSystemBarsAppearance((int)WindowInsetsControllerAppearance.LightStatusBars, (int)WindowInsetsControllerAppearance.LightStatusBars);
}
}
You also need to include the ConfigChanges.UiMode flag in the ConfigurationChanges attribute (included by default in new MAUI projects):
[Activity(Theme = "#style/MyAppTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize | ConfigChanges.Density)]
public class MainActivity : MauiAppCompatActivity
UPDATE
About the RequestedThemeChanged event and the RequestedTheme property in your case: When you are setting Application.Current.UserAppTheme = AppTheme.Dark; you are effectively saying that you want the theme to be set to Dark permanently, so the event doesn't get raised anymore after that, since UserAppTheme is not set to Unspecified anymore. See more: https://learn.microsoft.com/en-us/dotnet/maui/user-interface/system-theme-changes#set-the-current-user-theme
I have spent about one day (maybe a little more) on trying to add my application to Login Item in the order it starts up at macOS launch (user login).
The first approach was the newest one; I check this tutorial on youtube:
https://www.youtube.com/watch?v=2mmWEHUgEBo&t=660s
So following this steps, I have done:
Add new project inside my main project that I have named Launcher
I am using Automatic Signing (as version of my Xcode) is different
In Project Settings > Capabilities I toggled App Sandbox to ON.
In Build Phases I have added this:
My Launcher has Skip Install = YES
Code in my Launcher app looks like this (I have even previously use Swift to do the same)
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
// Insert code here to initialize your application
NSArray *pathComponents = [[[NSBundle mainBundle] bundlePath] pathComponents];
pathComponents = [pathComponents subarrayWithRange:NSMakeRange(0, [pathComponents count] - 4)];
NSString *path = [NSString pathWithComponents:pathComponents];
[[NSWorkspace sharedWorkspace] launchApplication:path];
[NSApp terminate:nil];
}
Finally, I have magic code in Main App to enable app as Login Item
if(!SMLoginItemSetEnabled("click.remotely.Remotely-Click-Server-Launcher"
as CFString, Bool(checkboxButton.state as NSNumber) ) ) {
let alert: NSAlert = NSAlert()
alert.messageText = "Remotely.Click Server - Error";
alert.informativeText = "Application couldn't be added as
Login Item to macOS System Preferences > Users & Groups.";
alert.alertStyle = NSAlertStyle.warning;
alert.addButton(withTitle:"OK");
alert.runModal();
}
I have made Archive, and then have different options to Export:
I couldn't decide which one to choose, so I tried all of them.
"Save for Mac App Store Deployment" - made Installation package that has installed in /Applications/ directory but the app never runs.
"Developer-Id signed," "Development-signed" , "macOS App" all makes file in a directory that I exported to Applications directory, but no one works.
When I click the checkbox button, I could see some window blinking for a while on the screen (Launcher program). When I log out and log in the same window blinking effect appears but Launcher didn't start the Main application. When I click checkbox button again (and turn off Login Item) this blinking effect on user login (system startup) doesn't happen again. So it seems that this addition of Launcher program as Login Item works, but this Launcher couldn't start the Main app. Moreover when I go to /Applications/Main.app/Contents/Library/LoginItems/Launcher.app and click it manually then Launcher app launch Main application correctly (so the path was correct).
So what's going wrong?
Then I consider implementation of deprecated approach using
kLSSharedFileListSessionLoginItems
I have thought it must work it just add something in System Preferences this
window below.
But it also could go wrong!
I have chosen implementation in Swift (all examples/tutorials I have found was in Objective-C) So I have written something like this:
class LoginItemsList : NSObject {
let loginItemsList : LSSharedFileList = LSSharedFileListCreate(nil, kLSSharedFileListSessionLoginItems.takeRetainedValue(), nil).takeRetainedValue();
func addLoginItem(_ path: CFURL) -> Bool {
if(getLoginItem(path) != nil) {
print("Login Item has already been added to the list.");
return true;
}
var path : CFURL = CFURLCreateWithString(nil, "file:///Applications/Safari.app" as CFString, nil);
print("Path adding to Login Item list is: ", path);
// add new Login Item at the end of Login Items list
if let loginItem = LSSharedFileListInsertItemURL(loginItemsList,
getLastLoginItemInList(),
nil, nil,
path,
nil, nil) {
print("Added login item is: ", loginItem);
return true;
}
return false;
}
func removeLoginItem(_ path: CFURL) -> Bool {
// remove Login Item from the Login Items list
if let oldLoginItem = getLoginItem(path) {
print("Old login item is: ", oldLoginItem);
if(LSSharedFileListItemRemove(loginItemsList, oldLoginItem) == noErr) {
return true;
}
return false;
}
print("Login Item for given path not found in the list.");
return true;
}
func getLoginItem(_ path : CFURL) -> LSSharedFileListItem! {
var path : CFURL = CFURLCreateWithString(nil, "file:///Applications/Safari.app" as CFString, nil);
// Copy all login items in the list
let loginItems : NSArray = LSSharedFileListCopySnapshot(loginItemsList, nil).takeRetainedValue();
var foundLoginItem : LSSharedFileListItem?;
var nextItemUrl : Unmanaged<CFURL>?;
// Iterate through login items to find one for given path
print("App URL: ", path);
for var i in (0..<loginItems.count) // CFArrayGetCount(loginItems)
{
var nextLoginItem : LSSharedFileListItem = loginItems.object(at: i) as! LSSharedFileListItem; // CFArrayGetValueAtIndex(loginItems, i).;
if(LSSharedFileListItemResolve(nextLoginItem, 0, &nextItemUrl, nil) == noErr) {
print("Next login item URL: ", nextItemUrl!.takeUnretainedValue());
// compare searched item URL passed in argument with next item URL
if(nextItemUrl!.takeRetainedValue() == path) {
foundLoginItem = nextLoginItem;
}
}
}
return foundLoginItem;
}
func getLastLoginItemInList() -> LSSharedFileListItem! {
// Copy all login items in the list
let loginItems : NSArray = LSSharedFileListCopySnapshot(loginItemsList, nil).takeRetainedValue() as NSArray;
if(loginItems.count > 0) {
let lastLoginItem = loginItems.lastObject as! LSSharedFileListItem;
print("Last login item is: ", lastLoginItem);
return lastLoginItem
}
return kLSSharedFileListItemBeforeFirst.takeRetainedValue();
}
func isLoginItemInList(_ path : CFURL) -> Bool {
if(getLoginItem(path) != nil) {
return true;
}
return false;
}
static func appPath() -> CFURL {
return NSURL.fileURL(withPath: Bundle.main.bundlePath) as CFURL;
}
}
I have used this to turn on/off Login Item by clicking in the checkbox
let loginItemsList = LoginItemsList();
if( checkboxButton.state == 0) {
if(!loginItemsList.removeLoginItem(LoginItemsList.appPath())) {
print("Error while removing Login Item from the list.");
}
} else {
if(!loginItemsList.addLoginItem(LoginItemsList.appPath())) {
print("Error while adding Login Item to the list.");
}
}
I have run it in Debug mode (Xcode Play button) and try to archive it and export to /Applications folder if it matters, but this approach also doesn't work.
Console-printed messaged. Error means that the function Inserting Login Item returns nil.
So after that I even try to implement this (from some stackoverflow example) using Objective-C (as there is many Unmanaged<> in Swift)
So I added new .m and .h file and Bridging-Header.h and then a code like this:
- (void)enableLoginItemWithURL:(NSURL *)itemURL
{
LSSharedFileListRef loginListRef = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL);
if (loginListRef) {
// Insert the item at the bottom of Login Items list.
LSSharedFileListItemRef loginItemRef = LSSharedFileListInsertItemURL(loginListRef,
kLSSharedFileListItemLast,
NULL,
NULL,
(__bridge CFURLRef) itemURL,
NULL,
NULL);
if (loginItemRef) {
CFRelease(loginItemRef);
}
CFRelease(loginListRef);
}
}
Simple (just insertion) without any bells and whistles.
It also has the same issue that LSSharedFileListInsertItemURL returns nil and Login Item is not added to System Preferences > Users & Groups > Login Items.
So any idea why I cannot make this work?
UPDATE 1
I have tried to implement application using first approach (helper Launcher application inside Main application) on another computer iMac (MacOS Sierra and the newest XCode 8.3) and it seems to work there correctly so maybe there is something wrong with my OS or Xcode (provisioning profiles, signing of app or whatever) On MacBook Air where this approach doesn't work I am using OS X El Capitan 10.11.5 and Xcode 8.0.
Watch how it works here:
https://youtu.be/6fnLzkh5Rbs
and testing
https://www.youtube.com/watch?v=sUE7Estju0U
The second approach doesn't work also on my iMac returning the nil while doing LSSharedFileListInsertItemURL. So I don't know why that is happening.
Watch how it works here:
https://youtu.be/S_7ctQLkIuA
UPDATE 2
After upgrade to macOS Sierra 10.12.5 from El Capitan 10.11.5 and using Xcode 8.3.2 instead of Xcode 8.0.0 the second approach also happens to work correctly and is adding Login Items to System Preferences > Users & Groups > Login Items
IMPORTANT! To work this approach with LSSharedFileListInsertItemURL needs to disable App Sandboxing! Like in the video below:
https://youtu.be/UvDkby0t_WI
I also struggled with this a few years ago and ended up making a package for it that makes it much easier to add "launch at login" functionality for sandboxed apps.
Instead of lots of manual steps, you just need:
import LaunchAtLogin
LaunchAtLogin.isEnabled = true
Since macOS 13 Ventura, we can finally use a new SMAppService.
import ServiceManagement
try SMAppService.mainApp.register()
See SMAppService documentation for more details.
For the ServiceManagement approach, sometimes it doesn't work in your development machine because there is another copy of the app in your Xcode's DerivedData. The system don't know which app to launch. So go to ~/Library/Developer/Xcode/DerivedData and delete your development copy could help.
The above solution of Login Item programming problem works correctly both using modern approach with ServiceManagement.framework, and old (deprecated) approach with inserting Login Item into System Preferences > Users & Groups > Login Items. See my UPDATE 1 and UPDATE 2 remarks.
Dear Michal I have had the same problem about log in items. Log in items can be added in two ways; one from LSSharedFileListItemRef which will be shown in Login item of preferences but this approach will only work for non-sandboxing app and if you are making sandbox app then you should go for another way of using ServiceManagement framework.
You can have look over below link which specify everything - :
Launching your app on system start
I am adding another reference of adding app on log in - :
Approach for sandbox app with helper application
May be you are having trouble implementing app on log in item but follow the steps appropriately and you will succeed.
I need yout help to find out how to write and read files from external usb storage from Tizen Smart TVs. Problem starts when detecting it
`
/**
* Hello World Sample Project
*/
// import Label component
var Label = caph.require('ui.base.component.Label');
caph.app.addScene('main', $class({
$extends : caph.require('ui.base.Scene'),
// oncreate is called when the scene is created
oncreate : function() {
// add "Hello World"
this.addChild(new Label({
text : 'Hello World',
size : [ 500, 100 ],
position : [ 300, 400 ]
}).setTextSize('72px').setStyle({
backgroundColor : 'red',
color : 'white'
}));
/// Here the filesystem showd show me all the storages
tizen.filesystem.listStorages(checkCorruptedRemovableDrives);
}
})).run();
`
And here is the Success callback, this show me how much storages I have.
`
/* Success event handler */
var checkCorruptedRemovableDrives = function(storages) {
/// Here I will kow how much storages I have
console.log(storages.length);
for (var i = 0; i < storages.length; i++) {
if (storages[i].type != "EXTERNAL")
continue;
if (storages[i].state == "UNMOUNTABLE")
console.log("External drive " + storages[i].label + " is corrupted.");
}
};
`
Here is the method thrown when there are errors, this is never called.
var checkCorruptedRemovableDrivesError = function(storages){
console.log("Error");
}
Now, the console output is aways a simple 0 meanning I have no storage (but I have the internal one and two usb ones mounted).
Has Anyone faced this problem or have any Idea on how to solve it?
Samsung Tizen TV always uses "removable2" as label for USB.
So you don't need to use listStorage and getStorage.
Multiple USBs are distinguished as "removable2/sda1", "removable2/sda2"
tizen.filesystem.resolve("removable2", function(e){
e.listFiles(function(r){
for(i = 0; i < r.length; i++){
tizen.filesystem.resolve(r[i].path + r[i].name, function(t){
//You resolve USB root. Do something you want with USB.
}, function(t){
console.log("resolve error for " + r[i].path + r[i].name);
console.log(t);
}, "rw"); //you should use rw permission, to write something in usb.
}
});
},function(e){
console.log("removable2 resolve error");
console.log(e);
}, "r"); // permission should be given as r for removable2
Here is test app made by me. and you can check how to use SDK 1.5
http://www.samsungdforum.com/SamsungDForum/ForumView/3ad8bd6023af18a7?forumID=d88a711f47dc6e9f
This app is working in both of TV and SDK 1.5
Do you use Web Simulator?
APIs don't work in Web Simulator properly. It can't simulate things well.
When I check listStorage in 'emulator', it throws list of storages.
but even though I can get list of storage, I can't use it in filesystem. It is bug of SDK 1.4.
SDK 1.5 will have test features for USB storage, and it is planned to release in a month. Wait for a month :(
I'm sure I'm just overlooking this question but I cant seem to find how to check the device.
I want to check whether the device is either a phone, a tablet in landscape mode, a tablet in portrait mode or a other device (computer).
What I have is this:
if (Ext.platform.isPhone) {
console.log("phone");
}
if (Ext.platform.isTablet) {
console.log("tablet");
}
var x = Ext.platform;
But platform is undefined (probably because this is the way of Sencha Touch 1).
Does anyone know the correct place for me to access the device check?
Sencha Environment Detection offers a large spectrum through simple means.
Instead of Ext.os.is.Tablet, you can make life easier via Ext.os.deviceType which will return:
Phone
Tablet
Desktop
NB: this value can also be fudged by adding "?deviceType=" to the url.
http://localhost/mypage.html?deviceType=Tablet
Ext.os.name is the singleton returning:
iOS
Android
webOS
BlackBerry
RIMTablet
MacOS
Windows
Linux
Bada
Other
The usual ability of browser detection is available through Ext.browser.name.
Something I've only recently encountered, which I love is feature detection - allowing coding similar to Modernizr / YepNope based off ability of device. Ext.feature offers:
Ext.feature.has.Audio
Ext.feature.has.Canvas
Ext.feature.has.ClassList
Ext.feature.has.CreateContextualFragment
Ext.feature.has.Css3dTransforms
Ext.feature.has.CssAnimations
Ext.feature.has.CssTransforms
Ext.feature.has.CssTransitions
Ext.feature.has.DeviceMotion
Ext.feature.has.Geolocation
Ext.feature.has.History
Ext.feature.has.Orientation
Ext.feature.has.OrientationChange
Ext.feature.has.Range
Ext.feature.has.SqlDatabase
Ext.feature.has.Svg
Ext.feature.has.Touch
Ext.feature.has.Video
Ext.feature.has.Vml
Ext.feature.has.WebSockets
To detect fullscreen/app/homescreen browser mode on iOS:
window.navigator.standalone == true
Orientation Ext.device.Orientation and orientation change:
Ext.device.Orientation.on({
scope: this,
orientationchange: function(e) {
console.log('Alpha: ', e.alpha);
console.log('Beta: ', e.beta);
console.log('Gamma: ', e.gamma);
}
});
Orientation is based on Viewport. I usually add a listener which is more reliable:
onOrientationChange: function(viewport, orientation, width, height) {
// test trigger and values
console.log('o:' + orientation + ' w:' + width + ' h:' + height);
if (width > height) {
orientation = 'landscape';
} else {
orientation = 'portrait';
}
// add handlers here...
}
Use Ext.env.OS's is() method.
Note that only major component and simplified value of the version are
available via direct property checking. Supported values are: iOS,
iPad, iPhone, iPod, Android, WebOS, BlackBerry, Bada, MacOS, Windows,
Linux and Other
if (Ext.os.is('Android')) { ... }
if (Ext.os.is.Android2) { ... } // Equivalent to (Ext.os.is.Android && Ext.os.version.equals(2))
if (Ext.os.is.iOS32) { ... } // Equivalent to (Ext.os.is.iOS && Ext.os.version.equals(3.2))
Alternatively, you can also use PhoneGap Device API
I found the answer to it:
What seems to be the case is that Ext.os.is.(tablet/phone or something else) is true or undefined. If it is not the case it will be undefined.
I.a. Ext.os.is.Tablet is true when on a tablet and undefined when not.
So this is the answer I was looking for
if(Ext.os.is.Tablet){
this._bIsTablet = true;
}else if(Ext.os.is.Phone){
this._bIsPhone = true;
}else{
this._bIsOther = true;
}
I am experimenting with making Blackberry widgets but having a little trouble.
My first trial involves displaying a button which, when clicked, calls a JavaScript function that should alert the phones latitude and longitude.
The function looks:
function whereAmI() {
var latitude = blackberry.location.latitude;
var longitude = blackberry.location.longitude;
alert("Lat: "+latitude+", Long: "+longitude);
}
But it only ever alerts "Lat: 0, Long: 0". I've checked and my GPS seems to be working ok.
I'm running OS 5.* on a Curve 8900.
Any help would be appreciated :)
I discovered that I wasn't signing my files properly - now that I have, everything works fine.
For kaban:
// called when location object changes
function locationCB()
{
alert("Latitude " + blackberry.location.latitude);
alert("Longitude " + blackberry.location.longitude);
return true;
}
// test to see if the blackberry location API is supported
if( window.blackberry && blackberry.location.GPSSupported)
{
document.write("GPS Supported");
// Set our call back function
blackberry.location.onLocationUpdate("locationCB()");
// set to Autonomous mode
blackberry.location.setAidMode(2);
//refresh the location
blackberry.location.refreshLocation();
}
else
{
document.write("This Device doesn't support the Blackberry Location API");
}
Does your widget have permission to use GPS? Go to Options->Applications, select your app, then "Edit Permissions". Make sure "Location Data" (in Connections) is set to Allow.