Save State iOS - Save Value when leaving application - Xamarin - ios

I want to save the state of my application on iOS.
The app's workflow is to select a PersonID and base on that ID, a page with Details is opened. When I click on the Person's Address, the Maps is opened... but when I get back to my application, the first page is display, not the selected PersonID's page.
How can I keep the state of the application on iOS... I couldn't find something in the documentation.
Thank you in advance!

You could use User Defaults in Xamarin iOS to save the PersonID when selecting it, and get it to show the specified view when launching the app next time.
Save the PersonID:
var plist = NSUserDefaults.StandardUserDefaults;
int personid = 1;
plist.SetDouble(personid , "PersonID ");
And get it to show next time:
public override void ViewDidAppear(bool animated)
{
var plist = NSUserDefaults.StandardUserDefaults;
var personid = plist.DoubleForKey("PersonID");
if (null != personid)
{
// load the matched data
}
}

Related

Xamarin Forms: How to check if GPS is on or off in Xamarin ios app?

Whenever I am opening my app I need to check the GPS is on or off. If the GPS is off, I need to redirect the user to the location settings page. I have done the android part using the dependency service like below.
ILocSettings
public interface ILocSettings
{
void OpenSettings();
bool isGpsAvailable();
}
Android implementation
[assembly: Dependency(typeof(LocationShare))]
namespace Projectname.Droid.Services
{
public class LocationShare : ILocSettings
{
public bool isGpsAvailable()
{
bool value = false;
Android.Locations.LocationManager manager = (Android.Locations.LocationManager)Android.App.Application.Context.GetSystemService(Android.Content.Context.LocationService);
if (!manager.IsProviderEnabled(Android.Locations.LocationManager.GpsProvider))
{
//gps disable
value = false;
}
else
{
//Gps enable
value = true;
}
return value;
}
public void OpenSettings()
{
Intent intent = new Android.Content.Intent(Android.Provider.Settings.ActionLocat‌​ionSourceSettings);
intent.AddFlags(ActivityFlags.NewTask);
Android.App.Application.Context.StartActivity(intent);
}
}
}
Finally from the shared project called like below:
//For checking the GPS Status
bool gpsStatus = DependencyService.Get<ILocSettings>().isGpsAvailable();
//For opening the location settings
DependencyService.Get<ILocSettings>().OpenSettings();
For ios how I can I do the same features? I tried like below:
[assembly: Dependency(typeof(LocationShare))]
namespace Projectname.iOS.Serivces
{
class LocationShare : ILocSettings
{
public bool isGpsAvailable()
{
//how to check the GPS is on or off here
}
public void OpenSettings()
{
UIApplication.SharedApplication.OpenUrl(new NSUrl(UIApplication.OpenSettingsUrlString));
}
}
}
Location settings page opening on ios simulators, but don't know how to check the GPS status.
Update1
I have tried the CLLocationManager code and it is not working as expected. It returns true always even if the location is off or on.
OpenSettings() function code (UIApplication.SharedApplication.OpenUrl(new NSUrl(UIApplication.OpenSettingsUrlString));) is also not working as expected, it is redirecting to some other page, I need to open the location settings page if the GPS is off.
Also, I am requesting location permission like below:
var status = await Permissions.RequestAsync<Permissions.LocationAlways>();
In android, location permission is asking, but in ios, no permissions are asking.
Update2
I have tried the new codes and getting false value always as GPS status. I have added all the location permission on the info.plist like below:
But location permission is not asking when running the app (not even a single time). I have tried Permissions.LocationWhenInUse instead of Permissions.LocationAlways, but no luck.
Update 3
Following is my complete flow for checking location permission, checking GPS status, and open settings. The permission status value is always Disabled.
//Requesting permission like below:
var status = await Permissions.RequestAsync<Permissions.LocationAlways>();
if (status == PermissionStatus.Granted)
{
//Then checking the GPS state like below
bool gpsStatus = DependencyService.Get<ILocSettings>().isGpsAvailable();
if (!gpsStatus)
{
//show a message to user here for sharing the GPS
//If user granted GPS Sharing, opening the location settings page like below:
DependencyService.Get<ILocSettings>().OpenSettings();
}
}
I have tried the below 2 codes for requesting or checking permission. In both cases, the status value is Disabled. If I uninstall the app and reinstall it again, getting the same status and not showing any permission pop-up window.
var status = await Permissions.RequestAsync<Permissions.LocationAlways>();
var status = await Permissions.CheckStatusAsync<Permissions.LocationWhenInUse>();
Unlike the Android system, iOS can set the GPS switch separately, and can only get the status of whether the location service is turned on. The rest of the specific positioning method will be left to the iOS system to choose.
At the beginning, we need to have a look at the status of location in iOS:
CLAuthorizationStatus Enum
UIApplicationOpenSettingsURLString: Used to create a URL that you can pass to the openURL: method. When you open the URL built from this string, the system launches the Settings app and displays the app’s custom settings, if it has any.
From now, iOS only support this way to displays the app’s custom settings. There are two helpful discussion, you could have a look. How to jump to system setting's location service on iOS10? and Open Location Settings Not working in ios 11 Objective c?.
If it is redirecting to some other page as follows:
That means your app not do any settings about the location service after installing the app . Therefore, you not need to open the setting page, because it will not show the location service bellow the setting page of your app. Now the CLAuthorizationStatus should be NotDetermined. You could use CLLocationManager.RequestWhenInUseAuthorization to request the permission, the
popup window of location service will show for customer to choose inside the app.
If customer select Don't Allow first time, that means next time opening the app to check the location service that will show Denied status. Now you will need to use UIApplicationOpenSettingsURLString to open the settings page and will see the location service inside the app’s custom settings list.
At last, the final code of LocationShare is as follows:
public class LocationShare : ILocSettings
{
public bool isGpsAvailable()
{
bool value = false;
if ( CLLocationManager.LocationServicesEnabled )
{
if(CLLocationManager.Status == CLAuthorizationStatus.Authorized || CLLocationManager.Status == CLAuthorizationStatus.AuthorizedAlways || CLLocationManager.Status == CLAuthorizationStatus.AuthorizedWhenInUse)
{//enable
value = true;
}
else if (CLLocationManager.Status == CLAuthorizationStatus.Denied)
{
value = false;
OpenSettings();
}
else{
value = false;
RequestRuntime();
}
}
else
{
//location service false
value = false;
//ask user to open system setting page to turn on it manually.
}
return value;
}
public void RequestRuntime()
{
CLLocationManager cLLocationManager = new CLLocationManager();
cLLocationManager.RequestWhenInUseAuthorization();
}
public void OpenSettings()
{
UIApplication.SharedApplication.OpenUrl(new NSUrl(UIApplication.OpenSettingsUrlString));
}
}
Similarly, if CLAuthorizationStatus is Denied (the same as status == PermissionStatus.Unknown in Forms), the following code will not work in Forms.
var status = await Permissions.RequestAsync<Permissions.LocationAlways>();
It only works when CLAuthorizationStatus is NotDetermined. And you'd better request Permissions.LocationWhenInUse instead of Permissions.LocationAlways, this should be the better recommanded option.
============================Update #2================================
I have modified the above code, and you will see that if CLLocationManager.LocationServicesEnabled is false, we only can ask user to redirect to the system setting page to turn on the service manually. Because from iOS 10, iOS not supports to navigate to system setting page from non-system app.
============================Update #3======================================
If location service is enabled, when using UIApplication.SharedApplication.OpenUrl(new NSUrl(UIApplication.OpenSettingsUrlString)); method you will see the similar screenshot as follows:
The Loaction option will show in the list.

Xamarin forms geolocator plugin working intermittently

We are trying to use the plugin "Xam.Plugin.Geolocator" in our Xamarin Forms project. The project is currently IOS only.
Our app returns a list of business based on the device users current location. We hit an API to return our JSON formatted list data and the API is functioning correctly.
We would like the list to update whenever the user pulls down, changes tab and when the page initially loads but currently this is only working once or twice in around 100 attempts. I've not found a pattern yet to why it's failing, or indeed when it works.
We set App Properties when the page loads, the tab is selected and the user refreshes like this -
public async void GetLocation()
{
try
{
locator = CrossGeolocator.Current;
if (locator.IsGeolocationAvailable && locator.IsGeolocationEnabled)
{
var position = await locator.GetPositionAsync();
App.Current.Properties["Longitude"] = position.Longitude.ToString();
App.Current.Properties["Latitude"] = position.Latitude.ToString();
}
else
{
await DisplayAlert("Location Error", "Unable to retrieve location at this time", "Cancel");
}
}catch(Exception e)
{
await DisplayAlert("Location Error", "Unable to retrieve location at this time","Cancel");
}
}
We call the above method in the three areas
1) when the page is loaded
public NearbyPage()
{
InitializeComponent();
GetLocation();
SetNearbyBusinesses();
NearbyBusinesses = new List<NearbyBusiness>();
SetViewData();
SetViewVisibility();
}
2) when the tab is clicked
protected override void OnAppearing()
{
base.OnAppearing();
GetLocation();
SetNearbyBusinesses();
NearbyLocationsView.ItemsSource = NearbyBusinesses;
NoLocationsView.ItemsSource = UserMessages;
SetViewVisibility();
}
3) when the user pulls down to refresh
public void RefreshData()
{
if (!CrossConnectivity.Current.IsConnected)
{
NoInternetMessage.IsVisible = true;
return;
}
GetLocation();
NoInternetMessage.IsVisible = false;
SetNearbyBusinesses();
NearbyLocationsView.ItemsSource = NearbyBusinesses;
NoLocationsView.ItemsSource = UserMessages;
SetViewVisibility();
_analyticsService.RecordEvent("Refresh Event: Refresh nearby businesses", AnalyticsEventCategory.UserAction);
}
Can anyone shed some light on what we're doing wrong or have experience with this plugin that can help us resolve this issue?
Thank you
EDIT
By "work", i mean that we'd like it to hit our API with the users current location data and return new results from the API every time the user pulls down to refresh, the page is loaded initially or when they press on a specific tab. Currently it works occasionally, very occasionally.
We can't debug with a phone connected to a macbook, as since we installed the geolocator plugin the app always crashes when connected. The app seems to work ok when deployed to a device, apart from the location stuff. We're currently deploying to test devices via Microsofts Mobile Centre.
Ok, so with the debugger always crashing and being unable to see any stack trace etc we took a few shots in the dark.
We've managed to get this working by adding async to our method signatures down through our code stack. This has resolved the issue and the geo location and refresh is working perfectly.
For example when we changed the above method 3. to refresh the data, it worked perfectly.
public async Task RefreshData()
{
if (!CrossConnectivity.Current.IsConnected)
{
NoInternetMessage.IsVisible = true;
return;
}
GetLocation();
NoInternetMessage.IsVisible = false;
SetNearbyBusinesses();
NearbyLocationsView.ItemsSource = NearbyBusinesses;
NoLocationsView.ItemsSource = UserMessages;
SetViewVisibility();
_analyticsService.RecordEvent("Refresh Event: Refresh nearby businesses", AnalyticsEventCategory.UserAction);
}
We refactored more of that code but adding async was what got it working.
I hope this helps someone else save some time.

Samsung IAP - checking if an item is bought upon start up?

I just do not know how to use Samsung IAP!
I come from Google Play IAP where the IAP was pretty easy to implement. I took out all of that stuff and I started integrating the Samsung stuff. Now, I can make purchases, but what I don't understand is how to check if an item has been purchased.
My game has ads, and I have one non-consumable set up that will disable ads forever if purchased. As stated, I can purchase and disable the ads - the issue is that I want to check if that item has been purchased upon each start up, maybe in the on create. Otherwise, the ads come back upon the app closing down (I can use shared preferences, but if the app is uninstalled, the issue remains).
This is how it works in Google Play IAP. I have gone through the docs and the one example, and I understand that I can use doGetInboxList to see what items have been purchased.
However, as in the sample, this just asks for the group ID (no individual items), and even then, just says what and what isn't purchased in a list view. I have searched the code, but I can't even find where this is set. Regardless, programmitically I just want something.. anything! A boolean. Is this item with this id bought or not - yes or no. True or false. Have I missed something? Any help would be appreciated!
You are close.
Take that sample from InboxListActivity and apply to your activity:
public class YourStartUpActivity extends Activity implements OnGetInboxListener
{
private String mItemGroupId = "100000xxxxxx";
private int mIapMode = SamsungIapHelper.IAP_MODE_TEST_SUCCESS;
private int mStartNum = 1;
private int mEndNum = 15;
private String mStartDate = "20140101";
private String mEndDate = "30140101";
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//do your initializations here
SamsungIapHelper iapHelper = SamsungIapHelper.getInstance( this, mIapMode );
iapHelper.getItemInboxList( mItemGroupId,
mStartNum,
mEndNum,
mStartDate,
mEndDate,
this );
}
#Override
public void onGetItemInbox
(
ErrorVo _errorVo,
ArrayList<InboxVo> _inboxList
)
{
if( _errorVo != null &&
_errorVo.getErrorCode() == SamsungIapHelper.IAP_ERROR_NONE )
{
// TODO When inbox list has been loaded successfully,
// processes here.
if( _inboxList != null && _inboxList.size() > 0 )
{
//if you only have 1 item, you can assume that item is purchased, otherwise
//go over the _inboxList and check
//that user has purchased the correct item
}
}
}
}
Hope it helps

Is there a way to rearrange objects on a DevX report?

I want to enable user to move things around on a devexpress print preview and print it only after it is done. If it is possible, could I get some directions where I can start looking? (I will not have the time to look into the whole documentation, what may sound lazy, but devx is kinda huge for the short time I have.)
I don't think you could do this on the Print preview directly, but what you could do is provide a button which launches the XtraReports Designer and pass in the layout from your currently displayed document. When the user has finished editing then you can reload the document in the print preview, loading its new layout as required. You may need to customize the designer heavily to remove various options restricting the user to only editing certain aspects - you can hide much of the functionality including data source, component tray etc:
designer video
designer documentation
hide options in designer
if(EditLayout(document))
RefreshDocument();
public static bool EditLayout(XtraReport document)
{
using (var designer = new XRDesignRibbonForm())
{
designer.OpenReport(document);
XRDesignPanel activePanel = designer.ActiveDesignPanel;
activePanel.AddCommandHandler(new DesignerCommandHandler(activePanel));
HideDesignerOptions(activePanel);
designer.ShowDialog();
changesMade = activePanel.Tag != null && (DialogResult)activePanel.Tag == DialogResult.Yes; //set this tag in your DesignerCommandHandler
activePanel.CloseReport();
}
return changesMade;
}
Finally, some utility methods for changing a document/reports layout:
internal static byte[] GetLayoutData(this XtraReport report)
{
using (MemoryStream mem = new MemoryStream())
{
report.SaveLayoutToXml(mem);
return mem.ToArray();
}
}
internal static void SetLayoutData(this XtraReport report, byte[] data)
{
using (var mem = new MemoryStream(data))
{
report.LoadLayoutFromXml(mem);
}
}

Getting exception when clicking the back button in blackberry

From my application, i am going to the Blackberry Native Message Application to send mail.
when i am clicking the back button, it is giving Runtime Exception.
My code is below:
public void fieldChanged(Field field, int context)
{
if( field == m_lfMailId)
{
displayEmail();
}
}
private void displayEmail()
{
Invoke.invokeApplication(Invoke.APP_TYPE_MESSAGES, new MessageArguments(MessageArguments.ARG_NEW,"feedback#merucabs.com","",""));
Address toList[] = new Address[1];
}
We usually set the simulator to ignore Error 104 - start fledge with the flag /ignore-error=104. This should not be showing on a real device, you can see some more information in this thread. If you click continue on the simulator's white screen, does it continue alright?
Add this code below to your screen and click on back button.
public boolean onClose()
{
return super.onClose();
}

Resources