xamarin forms app link - open PCL view from ios app delegate - c#

In a Xamarin Forms cross platform app I can open the app from an external email app link.
It opens in android just fine, by adding an intent to the manifest, then within the activity which starts, I create another intent to fire the main activity
public class AppLinkActivity : Activity
{
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
string code = null;
if (Intent.Data.Query != null)
{
code = Intent.Data.Query.Substring(Intent.Data.Query.LastIndexOf('=') + 1);
}
if (Intent.Data != null)
{
var uri = Intent.Data;
if (uri != null)
{
Intent i = new Intent(this, typeof(MainActivity));
i.AddFlags(ActivityFlags.ReorderToFront);
i.PutExtra("code", code);
i.PutExtra("flag", true);
this.StartActivity(i);
}
}
this.FinishActivity(0);
}
}
In ios, the applink triggers the override of OpenUrl in the app delegate, but I'm not sure how to navigate to a particular PCL page from here, what happens is the app opens at it's last open page
public override bool OpenUrl(UIApplication app, NSUrl url, string sourceApp, NSObject annotation)
{
string _uri = url.ToString();
string code = _uri.Substring(_uri.LastIndexOf('=') + 1);
LoadApplication(new App(true, code));
return true;
}
Can anyone point me in the right direction with this? All I really need to do is, from the OpenUrl method, navigate to a view within the PCL

for anyone interested, I sorted this by replacing
LoadApplication(new App(true, code));
with
App.Current.MainPage = enterPin();
which calls
public Page enterPin()
{
return new EnterPinPage(SimpleIoc.Default.GetInstance<ISecureStorage>(), code, 1);
}

Related

How to grab intent on initial launch of application

I currently have a xamarin application. I redirect the client based on what intent is received. It works perfectly when the app in in the background or foreground.
The issue I currently have is the redirect bit of code doesn't trigger when the app is removed from the system tray.
protected async override void OnNewIntent(Intent intent)
{
var data = intent.Data; // this returns testurl.com/?firstname=john&lastname=doe
App.Firstname= intent.GetStringExtra("firstname");
App.Lastname= intent.GetStringExtra("lastname");
base.OnNewIntent(intent);
}
May I ask how do I keep my intents on app launch? I am unsure how to even debug this, when the app is removed from the system tray, visual studio stops running.
You can use the Bundle that you get from your MainActivity OnCreate method:
protected override void OnCreate(Bundle bundle)
{
Android.Net.Uri uri = Intent.Data;
if (uri != null)
{
App.Firstname = uri.GetQueryParameter("firstname");
App.Lastname = uri.GetQueryParameter("lastname");
}
}

How do I get PendingIntent using the MvvmCross 5 IMvxNavigationService?

I have a method I used in MvvmCross 4.x that was used with the NotificationCompat.Builder to set a PendingIntent of a notification to display a ViewModel when the notification is clicked by the user. I'm trying to convert this method to use the MvvmCross 5.x IMvxNavigationService but can't see how to setup the presentation parameters, and get a PendingIntent using the new navigation API.
private PendingIntent RouteNotificationViewModelPendingIntent(int controlNumber, RouteNotificationContext notificationContext, string stopType)
{
var request = MvxViewModelRequest<RouteNotificationViewModel>.GetDefaultRequest();
request.ParameterValues = new Dictionary<string, string>
{
{ "controlNumber", controlNumber.ToString() },
{ "notificationContext", notificationContext.ToString() },
{ "stopType", stopType }
};
var translator = Mvx.Resolve<IMvxAndroidViewModelRequestTranslator>();
var intent = translator.GetIntentFor(request);
intent.SetFlags(ActivityFlags.NewTask | ActivityFlags.ClearTask);
return PendingIntent.GetActivity(Application.Context,
_notificationId,
intent,
PendingIntentFlags.UpdateCurrent);
}
The RouteNotificationViewModel does appear when I click the notification but Prepare and Initialize are not being called. What is necessary to convert this method from MvvmCross 4.x style of navigation to MvvmCross 5.x style of navigation?
It's possible to do this in MvvmCross 5+ but it's not as clean as it previously was.
For starters you want to specify the singleTop launch mode for your activity:
[Activity(LaunchMode = LaunchMode.SingleTop, ...)]
public class MainActivity : MvxAppCompatActivity
Generate the notification PendingIntent like this:
var intent = new Intent(Context, typeof(MainActivity));
intent.AddFlags(ActivityFlags.SingleTop);
// Putting an extra in the Intent to pass data to the MainActivity
intent.PutExtra("from_notification", true);
var pendingIntent = PendingIntent.GetActivity(Context, notificationId, intent, 0);
Now there are two places to handle this Intent from MainActivity while still allowing the use of MvvmCross navigation service:
If the app was not running while the notification was clicked then OnCreate will be called.
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
if (bundle == null && Intent.HasExtra("from_notification"))
{
// The notification was clicked while the app was not running.
// Calling MvxNavigationService multiple times in a row here won't always work as expected. Use a Task.Delay(), Handler.Post(), or even an MvvmCross custom presentation hint to make it work as needed.
}
}
If the app was running while the notification was clicked then OnNewIntent will be called.
protected override void OnNewIntent(Intent intent)
{
base.OnNewIntent(intent);
if (intent.HasExtra("from_notification"))
{
// The notification was clicked while the app was already running.
// Back stack is already setup.
// Show a new fragment using MvxNavigationService.
}
}

Xamarin.Android app resumed by shortcut intent - Master and Detail must be set before adding MasterDetailPage to a container

I have Xamarin.Android todo list mobile app using Prism.
The problem is:
In android system, I can create shortcut to open specific list in
app.
When I open app, and press home button, it remains on background
(thats ok)
When I then run app from desktop shortcut, it opens
android activity and when I create new PrismApplication (
LoadApplication(new App()); ) everything is running OK, but after
creating viewmodel for view, app is still using old viewmodel from
before.
I made this workaroud and I use same instance of PrismApplication:
static App xamApp;
protected override void OnCreate(Bundle bundle)
{
if (xamApp == null)
{
Forms.Init(this, bundle);
xamApp = new App();
}
LoadApplication(xamApp);
xamApp.Redirect(Intent.GetStringExtra("ListID"));
}
Now, problem is redirecting. This code:
public void Redirect(string listId)
{
NavigationService.NavigateAsync($"MainPage/MainNavigationPage/TodoList?id={listId}", animated: false);
}
leads to the error:
System.InvalidOperationException: Master and Detail must be set before adding MasterDetailPage to a container.
Prism should take care of Binding of Detail in MasterDetailPage by the "TodoList" from NavigateAsync uri.
Does enyone know what can be the problem here?
So I finally got it working.
First I used LaunchMode = LaunchMode.SingleTask in my ActivityAttribute of MainActivity
[Activity(Label = "..", LaunchMode = LaunchMode.SingleTask, Icon = "#drawable/icon", Theme = "#style/MainTheme", MainLauncher = true]
public class MainActivity : FormsAppCompatActivity
Then I used OnNewIntent method of FormsAppCompatActivity so after app is on backgroud, only this event is launched :
protected override void OnNewIntent(Intent intent)
{
var listId = intent.GetStringExtra("ListID");
((App)App.Current).Redirect(listId);
}
Now even $"MainNavigationPage/TodoList?id={listId}" works
Based on the info you provided, I am assuming that when the app is launched again, it is already running, your previous MasterDetail page is already on the stack. IN your reset method, you want to reset your navigation stack to the new uri passing in the parameter. IN this case, you should use an absolute uri. This means try adding a "/" prefix to your uri. So something like this:
public void Redirect(string listId)
{
NavigationService.NavigateAsync($"/MainPage/MainNavigationPage/TodoList?id={listId}", animated: false);
}

How can I get the content of QR code scanned in an another activity?

well I use Zxing to scan a QR Code. That is my code for that:
public class ScanActivity : Activity
{
public ZXing.Result scanningResult;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Create your application here
SetContentView(Resource.Layout.activity_scan);
mReturnValue = new Intent();
Button scanBtn = FindViewById<Button>(Resource.Id.button_scan);
MobileBarcodeScanner.Initialize(Application);
scanBtn.Click += async (sender, e) =>
{
var scanner = new ZXing.Mobile.MobileBarcodeScanner();
scanningResult = await scanner.Scan();
// if (scanningResult != null)
// Console.WriteLine("Scanned Barcode: " + scanningResult.Text);
};
My problem is that I couldn't find how can I get and use the values of the scanned result in another activity?
From the activity, where you need the result you should start the scan activity for result. In the calling activity OnActivityResult event you can do what you want with the retuned code.
Look at the sample:
https://developer.xamarin.com/recipes/android/fundamentals/activity/start_activity_for_result/

How to open gallery in android device through xamarin.forms app?

I am working on xamarin.forms app. I created a xaml page in Global folder. I have a button on the page. I want to open the gallery of android device on click of that button. So I created a method in MainActivity.cs in Android folder. But I don't know how to access this method from button click event from xaml.cs page. I tried to create an object of MainActivity and access the method with the object. But getting null reference exception on "StartActivityForResult". following is my code. Please tell me how I can access the gallery open method in xamarin.forms.
My code is below that I am using to open gallery in MainActivity.cs class:
public void ImagePicker()
{
try
{
var imageIntent = new Intent ();
imageIntent.SetType ("image/*");
imageIntent.PutExtra(Intent.ExtraAllowMultiple,true);
imageIntent.SetAction (Intent.ActionGetContent);
this.StartActivityForResult (Intent.CreateChooser (imageIntent, "Select photo"), 0);
}
catch(Exception ex) {
}
}
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
base.OnActivityResult (requestCode, resultCode, data);
if ((requestCode == 0) && (resultCode == Result.Ok) && (data != null))
{
}
}
Regards,
Anand Dubey

Categories