Xamarin MvvmCross iOS state restoration issues - ios

I am currently unable to get state save/restore working for an iOS (target iOS 8) Xamarin solution using MvvmCross. The core view model implements save/restore as specified here https://github.com/MvvmCross/MvvmCross/wiki/View-Model-Lifecycle
The state is saved and restored correctly in the Android version of the solution, but is not working for the iOS version.
I have set a Restoration ID on the associated view controllers, and added the “opt in” methods to the app delegate class…
public override bool ShouldSaveApplicationState(UIApplication application, NSCoder coder)
{
return true;
}
public override bool ShouldRestoreApplicationState(UIApplication application, NSCoder coder)
{
return true;
}
If I create a basic single view iOS Xamarin app then I do see a call to the view controller’s EncodeRestorableState override method when the app goes into the background. However, for a similar simple MvvmCross implementation, this overridden method is no longer called (and neither is the SaveState method of the view model).
I have been unable to find anything to help, and only seem to find many people asking similar questions, but currently with no answers (e.g. SaveState in MvvmCross is not being called in an iOS application).
I would be very grateful for any information that could help point me in the right direction with this. Thanks.

Related

Xamarin iOS App check if GPS is enabled or prompt the user

Hi I am looking into an app which is written in Xamarin iOS. The feature I am trying to implement is
GPS must be enabled when app is running, if gps is not enabled prompt the user to enable. If the answer is yes enable the gps and continue otherwise exit app.
I am really new Xamarin and mobile development in general. After research i have found this link which shows the lifecycle of Xamarin iOS app.
Xamarin Lifecycle
The question I have is
1) Will I be able to show an alert to user from App Delegate to enable GPS when app returns from background or launched in the overrides (See link)
2) If a dialog is not possible from app delegate will it be better to create a new screen and show the dialog to enable gps instead of adding gps check in all screens.
3) Is this the correct way of checking if GPS is enabled
e.g., when app returns from background
public override void WillEnterForeground(UIApplication application)
{
Console.WriteLine("App will enter foreground");
if(CLLocationManager.Status == CLAuthorizationStatus.Denied)
{
}
}
Welcome #Abe you are on the right path!
Yes, you will be. You just have to place it in the overrides as you mentioned.
You can place the check in the AppDelegate, but it may not be the best thing to do. You might want to just place it in the Appear override of your page.
Yes using AppDelegate lifecycle overrides, is one way of checking for GPS if you need the it when your app is in the background.
Tips:
If you are using Xamarin Native, inside the ViewController, you could instead use the ViewDidLoad override to perform the check for GPS
You could instead just also just look into the Xamarin Essentials examples for a simplified way of dealing with GPS

Put app on foreground programmatically on Swift

I tested:
UIControl().sendAction(#selector(URLSessionTask.suspend), to: UIApplication.shared, for: nil)
which is for putting app on background and it works.
How do I put app back on foreground?
I tried:
UIControl().sendAction(#selector(URLSessionTask.resume), to: UIApplication.shared, for: nil)
But eventually it crashes...
Thank you
Update:
Since you've indicated that you're looking for any technical solution, even those not compatible with the App Store or Apple's terms, this should be possible using the Private API LSApplicationWorkspace: openApplicationWithBundleID. Try something like this:
Create a .h file and set up an interface to the LSApplicationWorkspace class and list the required method. You will need to #import "PrivateHeaders.h" in your bridging header.
//
// PrivateHeaders.h
//
#ifndef PrivateHeaders_h
#define PrivateHeaders_h
#interface LSApplicationWorkspace : NSObject
- (bool)openApplicationWithBundleID:(id)arg1;
#end
#endif /* PrivateHeaders_h */
You should then be able to call this function and pass in the Bundle Identifier of your app as an string.
//
// SomeClass.swift
//
import MobileCoreServices
let workspace = LSApplicationWorkspace()
/**
Launch an App given its bundle identifier
- parameter bundleIdentifier: The bundle identifier of the app to launch
- returns: True if app is launched, otherwise false
*/
func openApp(withBundleIdentifier bundleIdentifier: String) -> Bool {
// Call the Private API LSApplicationWorkspace method
return workspace.openApplication(withBundleID: bundleIdentifier)
}
Original:
What you are doing is likely a violation of the iOS Human Interface Guidelines (although the "Don’t Quit Programmatically" is no longer specifically defined), so as the comments have said, it is not suited to the App Store. Regardless, once your app is suspended in this way, I don't expect that there is a way to resume it programmatically, unless you can hook into a Background Operation to run URLSessionTask.resume, but I have not tested it and am unsure whether it can work.
Apps can be launched (and hence brought into the foreground) programmatically from another app or today extension by using a Custom URL Scheme, or via a Push Notification. It isn't possible to launch the app from the Background Operation via a URL Scheme, since it is part of the UIKit framework, which must be run in the main thread.
In summary, I think your best option is to try to use a Notification. This just means that the user will need to click on the notification to bring your app back into the foreground.
Closing/opening the app should be done explicitly by the user. Any other way of closing or opening the app is not supported by Apple and will be rejected when uploaded to app store. iOS Human Interface Guideline states:
Don’t Quit Programmatically
Never quit an iOS application
programmatically because people tend to interpret this as a crash.
However, if external circumstances prevent your application from
functioning as intended, you need to tell your users about the
situation and explain what they can do about it. Depending on how
severe the application malfunction is, you have two choices.
*Display
an attractive screen that describes the problem and suggests a
correction. A screen provides feedback that reassures usersthat
there’s nothing wrong with your application. It puts usersin control,
letting them decide whether they want to take corrective action and
continue using your application or press the Home button and open a
different application
*If only some of your application's features are
not working, display either a screen or an alert when people activate
the feature. Display the alert only when people try to accessthe
feature that isn’t functioning
Just as a follow up to Jordan's excellent answer I want to give an explanation for why your code works in the first place and why that alone will get your app rejected, even without any functionality to make it active again and bring it to the foreground.
As maddy pointed out in a comment, you're basically calling a method from UIApplication's private API. This works due to the Objective-C runtime's dynamic linking. You might wonder "But I am using Swift, what does that have to do with Objective-C?" The answer lies in #selector mechanism. A Selector is basically just a symbol that the Objective-C runtime looks up in a table to get a method it invokes (for you). This is why it's technically not correct to say you "call a method" when you do something like myObjectInstance.someMethod(). The correct way to phrase that would be to "send a message" to the object, because that's what is happening in the runtime. The target-action mechanism is build around that. The sendAction(_: Selector?, to: Any?) method does the same thing. So in effect your code does the following:
Get the symbol that corresponds to URLSessionTask's suspend() method.
Tell the shared instance of UIApplication to invoke the method that it has for that symbol.
Now usually that would result in a crash with the typical "unknown selector sent to instance..." error message. But here, by sure coincidence UIApplication also has a method for that instance (or rather, the runtime also has one of its methods listed in its table for that symbol). You kind of "found" a method that is not declared in its public header. You successfully circumvented a compile-time check for this and invoke a method that is part of a private API. This is explicitly forbidden in the Apple Developer Program License Agreement
Besides all that, I would strongly advise against trying to design an app that way in the first place. As maddy pointed out it's also likely considered to violate the HIGs. Even if you're not trying to do anything malicious and properly explain the feature in your app's description, that won't make Apple let it slide (I assume). Personally, as a user, I'd also find it annoying if the app did something the system already has a specific mechanic for in a different manner, at least in terms of app's coming to background and foreground.
I don't think it can be done without user interaction
The option is you can generate a push notification to tell the user to bring the application to foreground
When the operating system delivers push notification and the target application is not running in the foreground, it presents the notification.
If there is a notification alert and the user taps or clicks the action button (or moves the action slider), the application launches and calls a method to pass in the local-notification object or remote-notification payload.

Detect App idle time period for iOS in Xamarin forms

I recently started working in Xamarin forms and quite happy to be part of Xamarin community. I've a requirement to kick out the loggedIn User if he is idle on app for 10 mins. I got through of it in Android part using usual Life Cycle methods (combination of OnResume/OnPause) but not yet succeeded in iOS app.
I've hard time trying to find a solution over the internet but not able to find the one so far. I also tried with using Some Life cycle methods like WillEnterForeground/DidEnterbackground but due to some reason these method are not invoked on desired actions.
FYI, I am from the Android background so not expertise in iOS.
Any help would be highly appreciated or let me know If I am missing anything.
in App class
DateTime sleepTime;
protected override void OnSleep()
{
base.OnSleep();
sleepTime = DateTime.Now;
}
protected override void OnResume()
{
base.OnResume();
var sleepDuration = DateTime.Now - sleepTime;
}

Explanation of AppDelegate? [duplicate]

This question already has answers here:
What is the AppDelegate for and how do I know when to use it?
(4 answers)
Closed 8 years ago.
I have an android background . I want to learn XCode . Now i want to understand what does the Appdelegate.h and Appdelegate.m do? As in Android Manifest.xml is the mainFile which launches other Activities . permissions, feature ,broadcast service etc are written in it.
Now can some one explain me the importance of AppDelegate file and explain its component and benefits ?
And where to include permission or Service or BroadCast in app.
I have created an app in Android . Now i am creating it in IPhone which requires permission and services...
Thanks in Advance..
Edit..
According to my study and knowledge. AppDelegate is a controller, it doesn't visually present data (a view) nor does it represent the actual data (a model) but it does determine what view controllers to show etc and manage other views (status bar etc) at the start of the application .it is the launcher class where the first class launches . it consist of some predefined function didFinishLauching and other functions. Is there any detail explanation.
From:
https://developer.apple.com/library/ios/documentation/iphone/conceptual/iphoneosprogrammingguide/AppArchitecture/AppArchitecture.html
The app delegate is a custom object created at app launch time,
usually by the UIApplicationMain function. The primary job of this
object is to handle state transitions within the app. For example,
this object is responsible for launch-time initialization and handling
transitions to and from the background. For information about how you
use the app delegate to manage state transitions, see “Managing App
State Changes.”
In iOS 5 and later, you can use the app delegate to handle other
app-related events. The Xcode project templates declare the app
delegate as a subclass of UIResponder. If the UIApplication object
does not handle an event, it dispatches the event to your app delegate
for processing. For more information about the types of events you can
handle, see UIResponder Class Reference.

App State Preservation and Restoration in MonoTouch

I need to implement the status preservation protocol in my monotouch app, like described in the Apple Docs:
App State Preservation and Restoration
But I cannot find any documentation or project sample on the Xamarin website about the UIViewControllerRestoration Protocol.
Any help is appreciated.
This protocol is not currently bound in MonoTouch. There is a bug for it here:
https://bugzilla.xamarin.com/show_bug.cgi?id=8778
That said, there is a similar callback in the AppDelegate, application:viewControllerWithRestorationIdentifierPath:coder: that is bound in MonoTouch to the method:
UIViewController GetViewController (UIApplication application, string[] restorationIdentifierComponents, NSCoder coder).
This will be called once for each saved controller that has no restoration class set. Therefore, in lieu of the restoration class, you could override this method in the App Delegate.

Resources