I am using Rivets with Android to open my app and get data from a webpage.
I have the following in my onCreate method.
if (Intent.HasExtra("al_applink_data"))
{
var data = Intent.Data.ToString();
var appLinkData = Intent.GetStringExtra("al_applink_data");
var alUrl = new Rivets.AppLinkUrl(data, appLinkData);
// InputQueryParameters will contain our token
if (alUrl != null && alUrl.InputQueryParameters.ContainsKey("an"))
{
_token = alUrl.InputQueryParameters["an"];
}
else
{
// No token found
}
}
My activity has this filter at the top.
[IntentFilter(new[] { Intent.ActionView },
DataScheme = "test",
DataHost = "test",
Categories = new[]
{
Intent.CategoryDefault, Intent.CategoryBrowsable
})]
My test content is test://test?an=1234, which successfully opens my activity. However, Intent.HasExtra("al_applink_data") is always false and Intent.GetStringExtra("al_applink_data") is always null. Intent.Data.ToString(); shows my content with the parameter. I am new to Rivets and Android programming in C#. Why might this always be false and null?
Try like this:
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(....);
if (Intent != null)
{
OnNewIntent(Intent);
}
}
protected override void OnNewIntent(Android.Content.Intent intent)
{
base.OnNewIntent(intent);
var appLinkData = intent.GetStringExtra("al_applink_data");
AppLinkUrl alUrl = null;
if (appLinkData != null)
{
alUrl = new Rivets.AppLinkUrl(intent.Data.ToString(), appLinkData);
}
if (alUrl != null) {
// LAUNCH URI
}
}
Remember to use the (lowercase) "intent" parameter passed in the OnNewIntent method:
intent.GetStringExtra("al_applink_data") ----> contains data
Intent.GetStringExtra("al_applink_data") ----> return null.
Related
I'm trying to consume a Rest API to display a listView with MVVM so I created this this service to consume the Rest API:
public class MachineService : IMachineService
{
public string Base_url = "https://169.254.178.79:45455/api/";
public async Task<ObservableCollection<Machine>> GetMachines()
{
string url = Base_url + "machines";
HttpClient client = new HttpClient();
HttpResponseMessage responseMessage = await client.GetAsync(url);
if (responseMessage.StatusCode == System.Net.HttpStatusCode.OK)
{
var result = await responseMessage.Content.ReadAsStringAsync();
var json = JsonConvert.DeserializeObject<ObservableCollection<Machine>>(result);
return json;
}
return null;
}
And this is the ViewModel:
public class MachineListeVM : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
IMachineService _rest = DependencyService.Get<IMachineService>();
public MachineListeVM ()
{
GetMachines();
}
public async void GetMachines()
{
var result = await _rest.GetMachines();
if (result != null)
{
Machines = result;
}
}
public ObservableCollection<Machine> machines;
public ObservableCollection<Machine> Machines
{
get { return machines; }
set
{
machines = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Machines"));
}
}
}
}
the exception details while debugging:
>[monodroid-assembly] open_from_bundles: failed to load assembly Xamarin.Forms.Platform.Android.AppLinks.dll
[SurfaceFactory] [static] sSurfaceFactory = com.mediatek.view.impl.SurfaceFactoryImpl#e0b84b8
[ViewRootImpl[MainActivity]] hardware acceleration = true , fakeHwAccelerated = false, sRendererDisabled = false, forceHwAccelerated = false, sSystemRendererDisabled = false
[libMEOW] applied 1 plugins for [com.companyname.app5]:
[libMEOW] plugin 1: [libMEOW_gift.so]:
[InputTransport] Create ARC handle: 0x7a825386a0
[libMEOW_gift] etEventThreadFunc()::thread Begin. eventRefCnt: 1
[PhoneWindow] DecorView setVisiblity: visibility = 0, Parent = android.view.ViewRootImpl#8503464, this = DecorView#374f6cd[MainActivity]
[ViewRootImpl[Syncfusion License]] hardware acceleration = true , fakeHwAccelerated = false, sRendererDisabled = false, forceHwAccelerated = false, sSystemRendererDisabled = false
[InputTransport] Create ARC handle: 0x7a825ecf60
Thread started: #5
**System.NullReferenceException:** 'Object reference not set to an instance of an object.'
Note: I tried the same code in another project and it's worked fine and the list view is apeared
Im trying obtain data from notification, when my app is closed and when app is just in background. I get notification, tap on it, and in MainActivity(from android project) i want to obtain data.
I can do it when my app is open, by HmsMessageService and OnMessageReceived, there is no problem. But i cant find examples, how to do it when app is closed. Any help, pls.
There is my notification in Json:
var jObject = new
{
message = new
{
notification = new
{
title = titleNot,
body = bodyNot
},
android = new
{
notification = new
{
foreground_show = false,
click_action = new
{
type = 3
}
}
},
token = new[] { token }
}
};
When the application is closed, you can obtain parameters by customizing click_action.
Set intent in the message body on your app server.
{
"message": {
"notification": {
"title": "message title",
"body": "message body"
},
"android": {
"notification": {
"click_action": {
"type": 1,
"intent": "intent://com.huawei.xahmspushdemo/deeplink?#Intent;scheme=pushscheme;launchFlags=0x4000000;i.age=180;S.name=abc;end"
}
}
},
"token": [
"pushtoken1"
]
}
}
This is the document.
Just as what Np0v0 mentioned, you can use click_action to get the data. There is another way to implement the goal.
Register an Activity class to be started in the AndroidManifest.xml file of the app.
3.Receive data using the customized activity class.
For more detail information, pls refer to https://developer.huawei.com/consumer/en/doc/development/HMSCore-Guides/andorid-basic-clickaction-0000001087554076#EN-US_TOPIC_0000001087554076__li7205195217309
Solved problem without changing "click_action type". Just override OnNewIntent() method in main activity, and add "GetIntentData" with some logic.
private void GetIntentData(Bundle bNotification)
{
if (bNotification != null)
{
try
{
if (bNotification.ContainsKey(TITLE_KEY) && bNotification.ContainsKey(BODY_KEY))
{
\\...
}
}
catch
{
}
}
}
protected override void OnNewIntent(Intent intent)
{
base.OnNewIntent(intent);
GetIntentData(intent?.Extras);
}
in OnCreate() I created bundle and if its not null I load app:
Bundle bNotification = Intent.Extras;
if (bNotification == null || bNotification.IsEmpty)
{
LoadApplication(new App(...));
}
else
{
LoadApplication(new App(true, ...));
GetIntentData(bNotification);
}
https://developer.huawei.com/consumer/en/doc/development/HMS-Plugin-Guides/xamarin-customizingactions-0000001055648851
I use this code to receive push notifications on iOS. The code works but I get a warning in this line:
new UIAlertView("Error registering push notifications", error.LocalizedDescription, null, "OK", null).Show();
Warning CS0618: 'UIAlertView.UIAlertView(string, string, UIAlertViewDelegate, string, params string[])' is obsolete: 'Use overload with a IUIAlertViewDelegate parameter'
Is it still possible to use FailedToRegisterForRemoteNotifications(UIApplication application, NSError error)? What should I change in my code?
using System;
using Foundation;
using UIKit;
using Xamarin.Forms;
namespace InapppurchaseTest.iOS
{
[Register("AppDelegate")]
class Program : UIApplicationDelegate
{
private static Game1 game;
internal static void RunGame()
{
game = new Game1();
game.Run();
}
static void Main(string[] args)
{
UIApplication.Main(args, null, "AppDelegate");
}
public override void FinishedLaunching(UIApplication app)
{
global::Xamarin.Forms.Forms.Init();
if (UIDevice.CurrentDevice.CheckSystemVersion(10, 0))
{
var authOptions = UserNotifications.UNAuthorizationOptions.Alert | UserNotifications.UNAuthorizationOptions.Badge | UserNotifications.UNAuthorizationOptions.Sound;
UserNotifications.UNUserNotificationCenter.Current.RequestAuthorization(authOptions, (granted, error) =>
{
Console.WriteLine(granted);
});
UIApplication.SharedApplication.RegisterForRemoteNotifications();
}
else if (UIDevice.CurrentDevice.CheckSystemVersion(8, 0))
{
var settings = UIUserNotificationSettings.GetSettingsForTypes(UIUserNotificationType.Alert | UIUserNotificationType.Badge | UIUserNotificationType.Sound, new NSSet());
UIApplication.SharedApplication.RegisterUserNotificationSettings(settings);
UIApplication.SharedApplication.RegisterForRemoteNotifications();
}
else
{
var notificationTypes = UIRemoteNotificationType.Alert | UIRemoteNotificationType.Badge | UIRemoteNotificationType.Sound;
UIApplication.SharedApplication.RegisterForRemoteNotificationTypes(notificationTypes);
}
RunGame();
}
public override void RegisteredForRemoteNotifications(UIApplication application, NSData deviceToken)
{
// Get current device token
var DeviceToken = deviceToken.Description;
if (!string.IsNullOrWhiteSpace(DeviceToken))
{
DeviceToken = DeviceToken.Trim('<').Trim('>');
}
// Get previous device token
var oldDeviceToken = NSUserDefaults.StandardUserDefaults.StringForKey("PushDeviceToken");
// Has the token changed?
if (string.IsNullOrEmpty(oldDeviceToken) || !oldDeviceToken.Equals(DeviceToken))
{
//TODO: Put your own logic here to notify your server that the device token has changed/been created!
}
// Save new device token
NSUserDefaults.StandardUserDefaults.SetString(DeviceToken, "PushDeviceToken");
}
public override void FailedToRegisterForRemoteNotifications(UIApplication application, NSError error)
{
new UIAlertView("Error registering push notifications", error.LocalizedDescription, null, "OK", null).Show();
}
public override void ReceivedRemoteNotification(UIApplication application, NSDictionary userInfo)
{
ProcessNotification(userInfo, false);
}
void ProcessNotification(NSDictionary options, bool fromFinishedLaunching)
{
// Check to see if the dictionary has the aps key. This is the notification payload you would have sent
if (null != options && options.ContainsKey(new NSString("aps")))
{
//Get the aps dictionary
NSDictionary aps = options.ObjectForKey(new NSString("aps")) as NSDictionary;
string alert = string.Empty;
if (aps.ContainsKey(new NSString("alert")))
alert = (aps[new NSString("alert")] as NSString).ToString();
if (!fromFinishedLaunching)
{
//Manually show an alert
if (!string.IsNullOrEmpty(alert))
{
NSString alertKey = new NSString("alert");
UILocalNotification notification = new UILocalNotification();
notification.FireDate = NSDate.Now;
notification.AlertBody = aps.ObjectForKey(alertKey) as NSString;
notification.TimeZone = NSTimeZone.DefaultTimeZone;
notification.SoundName = UILocalNotification.DefaultSoundName;
UIApplication.SharedApplication.ScheduleLocalNotification(notification);
}
}
}
}
}
}
If want to remove this warnning , adding [Obsolete] berfore Method as follow:
[Obsolete]
public override void FailedToRegisterForRemoteNotifications(UIApplication application, NSError error)
{
new UIAlertView("Error registering push notifications", error.LocalizedDescription, null, "OK", null).Show();
}
By the way , from document Displaying Alerts in Xamarin.iOS
Starting with iOS 8, UIAlertController has completed replaced UIActionSheet and UIAlertView both of which are now deprecated.
Then you can use UIAlertController to realize this:
//Create Alert
var okAlertController = UIAlertController.Create("Title", "The message", UIAlertControllerStyle.Alert);
//Add Action
okAlertController.AddAction(UIAlertAction.Create("OK", UIAlertActionStyle.Default, null));
// Present Alert
PresentViewController(okAlertController, true, null);
I want to update my main activity UI in my foreground service with broadcast receiver. In BroadcastReceiver.OnReceive method,I passed the instance of main activity,but it is always nullable. How can I fix it? Many thanks in advance!
In my broadcast receiver:
public override void OnReceive(Context context, Intent intent)
{
Core.Music music = intent.GetParcelableExtra("selectedMusic") as Core.Music;
mMainActivity.mTxtSongName.Text = Core.MusicHelper.GetTitleAndAuthor(music.Title);
mMainActivity.mTxtAuthorName.Text = Core.MusicHelper.GetTitleAndAuthor(music.Author);
System.Threading.ThreadPool.QueueUserWorkItem(o =>
{
string imageUrl = music.Url.Replace(#"\", "").Replace("http", "https");
var task = Core.MusicHelper.GetSongPic(imageUrl, 35, 35);
var pic = task.Result;
if (pic != null)
{
mMainActivity.RunOnUiThread(() =>
{
mMainActivity.mImageViewSongPic.SetImageBitmap(pic);
});
}
});
}
In my service:
public override StartCommandResult OnStartCommand(Intent intent, [GeneratedEnum] StartCommandFlags flags, int startId)
{
Core.Music music = intent.GetParcelableExtra("selectedMusic") as Core.Music;
BroadcastStarted(music);
//To start the service
return StartCommandResult.NotSticky;
}
In my MainActivity.OnResume:
IntentFilter filter = new IntentFilter();
mReceive = new Service.Boradcast.MusicChangedBroadcastReceiver() { mMainActivity=this};
RegisterReceiver(mReceive,filter);
how do you defined mMainActivity ?
however the simplest example of a reference to MainActivity is to use static
define in your MainActivity OnCreate() method:
public static MainActivity Instance;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
...
Instance = this;
}
then call in your broadcast receiver
public override void OnReceive(Context context, Intent intent)
{
Core.Music music = intent.GetParcelableExtra("selectedMusic") as Core.Music;
MainActivity.Instance.mTxtSongName.Text = Core.MusicHelper.GetTitleAndAuthor(music.Title);
MainActivity.Instance.mTxtAuthorName.Text = Core.MusicHelper.GetTitleAndAuthor(music.Author);
System.Threading.ThreadPool.QueueUserWorkItem(o =>
{
string imageUrl = music.Url.Replace(#"\", "").Replace("http", "https");
var task = Core.MusicHelper.GetSongPic(imageUrl, 35, 35);
var pic = task.Result;
if (pic != null)
{
MainActivity.Instance.RunOnUiThread(() =>
{
MainActivity.Instance.mImageViewSongPic.SetImageBitmap(pic);
});
}
});
}
Or pass MainActivity as a parameter to the constructor :
in your MainActivity.OnResume():
IntentFilter filter = new IntentFilter();
mReceive = new Service.Boradcast.MusicChangedBroadcastReceiver(this);
RegisterReceiver(mReceive,filter);
then in your broadcast receiver:
[BroadcastReceiver]
public class MusicChangedBroadcastReceiver: BroadcastReceiver
{
public MainActivity mMainActivity;
public MusicChangedBroadcastReceiver()
{
}
public MusicChangedBroadcastReceiver(MainActivity activity)
{
this.mMainActivity= activity;
}
public override void OnReceive(Context context, Intent intent)
{
Core.Music music = intent.GetParcelableExtra("selectedMusic") as Core.Music;
mMainActivity.mTxtSongName.Text = Core.MusicHelper.GetTitleAndAuthor(music.Title);
mMainActivity.mTxtAuthorName.Text = Core.MusicHelper.GetTitleAndAuthor(music.Author);
System.Threading.ThreadPool.QueueUserWorkItem(o =>
{
string imageUrl = music.Url.Replace(#"\", "").Replace("http", "https");
var task = Core.MusicHelper.GetSongPic(imageUrl, 35, 35);
var pic = task.Result;
if (pic != null)
{
mMainActivity.RunOnUiThread(() =>
{
mMainActivity.mImageViewSongPic.SetImageBitmap(pic);
});
}
});
}
}
I'm trying to use the ShouldOverrideUrlLoading() method but the app crashes when I call it.
Below is my code:
private class HybridWebViewClient : WebViewClient
{
public override bool ShouldOverrideUrlLoading(WebView webView, string url)
{
var tel = "tel:";
if (url.StartsWith(tel))
{
var uri = Android.Net.Uri.Parse(url);
var intent = new Intent(Intent.ActionDial, uri);
var act = new Activity();
act.StartActivity(intent);
}
}
}
Thanks in Advance!
The problem lies in the following codes snippet:
var act = new Activity();
act.StartActivity(intent);
The method StartActivity should be called from current context instead of a new Activity. So you need to pass the current context to HybridWebViewClient:
public class HybridWebViewClient : WebViewClient
{
Context context;
public HybridWebViewClient(Context context)
{
this.context = context;
}
public override bool ShouldOverrideUrlLoading(WebView view, string url)
{
var tel = "tel:";
if (url != null)
{
if (url.StartsWith(tel))
{
var uri = Android.Net.Uri.Parse(url);
var intent = new Intent(Intent.ActionDial, uri);
context.StartActivity(intent);
}
}
return true;
}
}
And in the OnCreate method:
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
...
webview.SetWebViewClient(new HybridWebViewClient(this));
webview.LoadUrl("http://example.com");
...
}
What is in the craash dump? Is this related?
shouldOverrideUrlLoading(WebView view, String url)
This method was deprecated in API level 24. Use shouldOverrideUrlLoading(WebView, WebResourceRequest) instead.