I create a vpnservice with this codes:
public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
{
if (mThread != null)
{
mThread.Interrupt();
}
mThread = new Java.Lang.Thread(this,"360VpnThread");
mThread.Start();
return StartCommandResult.Sticky;
}
public override void OnDestroy()
{
base.OnDestroy();
}
public void Run()
{
var builder = new VpnService.Builder(this);
builder.SetSession(PackageName)
.SetMtu(1460)
.AddAddress("10.0.6.2", 24)
.AddDnsServer("8.8.8.8").AddRoute("0.0.0.0", 8);
mInterface = builder.Establish();
if (mInterface == null)
{
StopSelf();
}
}
but i get this error:
java.lang.SecurityException: parspeed360.android.VpnService360 does
not require android.permission.BIND_VPN_SERVICE
Already i add these to android manifest:
<application android:label="360.Android" android:icon="#drawable/Icon">
<service android:name=".Parspeed360.Android.VpnService360"
android:label="#string/ApplicationName"
android:exported="false"
android:permission="android.permission.BIND_VPN_SERVICE">
<intent-filter>
<action android:name="android.net.VpnService"/>
</intent-filter>
</service>
</application>
please help me.
Well, Arman Kabir was not so clear on HOW this problem is solved for him. After searching on Google Source Code, I figured out what was wrong for me.
If you write this code before you start your service:
Intent vpnServiceIntent = new Intent(Application.Context, typeof(LocalVpnService));
var resolveInfoList = PackageManager.QueryIntentServices(vpnServiceIntent, 0);
Application.Context.StartService(vpnServiceIntent);
And inspect resolveInfoList as follow:
resolveInfoList[0].ServiceInfo.Name // => "md55bfed5bb232464f797409dd275ac40fc.LocalVpnService"
resolveInfoList[0].ServiceInfo.Permission // => (null)
So I got this working when I change my service name in Manifest:
<application android:allowBackup="true" android:icon="#mipmap/icon" android:label="#string/app_name">
<service
android:name="md55bfed5bb232464f797409dd275ac40fc.LocalVpnService"
android:permission="android.permission.BIND_VPN_SERVICE">
<intent-filter>
<action android:name="android.net.VpnService" />
</intent-filter>
</service>
</application>
Maybe this is some Xamarin specificity...
My Service was declared as:
namespace kitkattest
{
[Service]
public class LocalVpnService : VpnService
{
// ...
}
}
Just add the BIND_VPN_SERVICE permission to the service
namespace MyNamespace
{
[Service(Label = "My Label", Permission = "android.permission.BIND_VPN_SERVICE")]
public class MyService : VpnService
{
...
}
}
Related
I'm trying to make a gps tracking app in Xamarin that works in the background too. Currently I have created a service that every two seconds checks the location of the device.
I am currently testing it on an Android Honor 10 and I notice that when i launch the app in debug with Visual Studio keeping the phone connected to the PC it works without ever stopping.
If, on the other hand, I try the app without debugging, after a while it stop tracking gps if I put it in the background.
So this is my service in the main project:
public class TrackingService
{
readonly bool stopping = false;
public TrackingService()
{
}
public async Task Run(CancellationToken token)
{
await Task.Run(async () => {
while (!stopping)
{
token.ThrowIfCancellationRequested();
try
{
await Task.Delay(2000);
var request = new GeolocationRequest(GeolocationAccuracy.Best);
var location = await Geolocation.GetLocationAsync(request);
//Other stuff like writing coordinates into a local database
}
catch (Exception ex)
{
Device.BeginInvokeOnMainThread(() =>
{
//Error
});
}
}
return;
}, token);
}
}
This is the the start of the service for the Android project:
[Register("com.companyname.dolomicchiostreetapp.TrackingService")]
public class AndroidLocationService : Service
{
CancellationTokenSource _cts;
public const int SERVICE_RUNNING_NOTIFICATION_ID = 10000;
public override IBinder OnBind(Intent intent)
{
return null;
}
public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
{
_cts = new CancellationTokenSource();
Notification notif = DependencyService.Get<INotification>().ReturnNotif();
StartForeground(SERVICE_RUNNING_NOTIFICATION_ID, notif);
Task.Run(() => {
try
{
var locShared = new TrackingService();
locShared.Run(_cts.Token).Wait();
}
catch (OperationCanceledException)
{
}
finally
{
if (_cts.IsCancellationRequested)
{
var message = new StopServiceMessage();
Device.BeginInvokeOnMainThread(
() => MessagingCenter.Send(message, "ServiceStopped")
);
}
}
}, _cts.Token);
return StartCommandResult.Sticky;
}
public override void OnDestroy()
{
if (_cts != null)
{
_cts.Token.ThrowIfCancellationRequested();
_cts.Cancel();
}
base.OnDestroy();
}
}
And this is my AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.companyname.dolomicchiostreetapp">
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="30" />
<application android:label="dolomicchiostreetapp.Android" android:theme="#style/MainTheme">
<service android:enabled="true" android:foregroundServiceType="location" android:exported="false" android:name="com.companyname.dolomicchiostreetapp.TrackingService" />
</application>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
</manifest>
I followed this github example: XamarinForms.LocationService
Has anyone ever had this problem ?
Thanks to those who will help me.
See Limited Updates to Background Tracking - "Android 8.0 (API level 26) and higher - Android preserves device battery life by ... If your app is running in the background, it can receive location updates only a few times each hour".
If you want more frequent updates, then you need a Foreground Service.
I am building a prototype in Xamarin.Forms that sends a push notification to the same App installed on other devices. I'm using OneSignal libraries.
Everything works perfectly. The push notification is sent by one device and received by the others correctly. Whether the App is in the foreground or in the background.
When the push notification arrives on the other devices, I capture it in HandleNotificationReceived and call my service that plays the Ringtone sound.
When push notification arrives on other devices and the app is in the foreground, everything works perfectly. However, when it arrives on the other devices, and the App is in the background, only Push Notification arrives, but the Ringtone sound does not play.
I read about limitations when trying to run some things in Background and I believe my problem has something to do with it.
can anybody help me?
Here is my code:
APPLICATION
namespace SaferProject
{
public partial class App : Application
{
public App()
{
InitializeComponent();
var page = new NavigationPage(new Views.MainMenu());
MainPage = page;
IPlaySoundService playSoundService;
playSoundService = DependencyService.Get<IPlaySoundService>();
OneSignal.Current.SetLogLevel(LOG_LEVEL.VERBOSE, LOG_LEVEL.NONE);
OneSignal.Current.StartInit("417d7b75-ed42-4ca5-aed3-42612d260235")
.Settings(new Dictionary<string, bool>() {
{ IOSSettings.kOSSettingsKeyAutoPrompt, false },
{ IOSSettings.kOSSettingsKeyInAppLaunchURL, false } })
.InFocusDisplaying(OSInFocusDisplayOption.Notification)
.HandleNotificationOpened((result) =>
{
if (playSoundService.GetServiceStatus())
{
playSoundService.StopSystemSound();
}
Debug.WriteLine("HandleNotificationOpened: {0}", result.notification.payload.body);
})
//################ Here I call the PlaySystemSound service###############
//################ Here I call the PlaySystemSound service###############
//################ Here I call the PlaySystemSound service###############
.HandleNotificationReceived((notification) =>
{
playSoundService.PlaySystemSound();
DeviceDisplay.KeepScreenOn = true;
Debug.WriteLine("HandleNotificationReceived: {0}", notification.payload.body);
})
//########################################################################
//########################################################################
//########################################################################
.HandleInAppMessageClicked((action) =>
{
// Example IAM click handling for IAM elements
Debug.WriteLine("HandledInAppMessageClicked: {0}", action.clickName);
})
.EndInit();
// The promptForPushNotificationsWithUserResponse function will show the iOS push notification prompt. We recommend removing the following code and instead using an In-App Message to prompt for notification permission (See step 7)
OneSignal.Current.RegisterForPushNotifications();
}
protected override void OnStart()
{
IPlaySoundService playSoundService;
playSoundService = DependencyService.Get<IPlaySoundService>();
if (playSoundService.GetServiceStatus())
{
playSoundService.StopSystemSound();
}
//Handle when your app sleeps
Task.Run(async () => { await SaferProjectService.GetInstance().GetOut(UserManager.GetLogUser()); });
}
protected override void OnSleep()
{
//Handle when your app sleeps
Task.Run(async()=> { await SaferProjectService.GetInstance().GetOut(UserManager.GetLogUser()); });
}
protected override void OnResume()
{
//Handle when your app resumes
Task.Run(async () => { await SaferProjectService.GetInstance().GetIn(UserManager.GetLogUser()); });
}
}
}
INTERFACE
namespace SaferProject.Services
{
public interface IPlaySoundService
{
Task PlaySystemSound();
Task StopSystemSound();
void SetServiceStatus(bool isPlaying);
bool GetServiceStatus();
}
}
ANDROID SERVICE
[assembly: Xamarin.Forms.Dependency(typeof(PlaySoundService))]
namespace SaferProject.Droid.Services
{
[Activity(Label = "PlaySoundService", NoHistory = true, Theme = "#style/MyTheme", ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
public class PlaySoundService : IPlaySoundService
{
private static PlaySoundService _instance;
readonly Ringtone _rt;
bool IsPlaying;
public static PlaySoundService GetInstance()
{
if (_instance == null)
{
_instance = new PlaySoundService();
}
return _instance;
}
public PlaySoundService()
{
AudioManager am = (AudioManager)Application.Context.GetSystemService(Context.AudioService);
if (!am.RingerMode.Equals(2))
{
am.RingerMode = RingerMode.Normal;
//am.SetVibrateSetting(VibrateType.Ringer, VibrateSetting.On);
}
Android.Net.Uri uri = RingtoneManager.GetDefaultUri(RingtoneType.Ringtone);
_rt = RingtoneManager.GetRingtone(MainActivity.instance.ApplicationContext, uri);
}
public Task PlaySystemSound()
{
_rt.Play();
Vibration.Vibrate(500);
SetServiceStatus(true);
return Task.CompletedTask;
}
public Task StopSystemSound()
{
Vibration.Cancel();
_rt.Stop();
SetServiceStatus(false);
return Task.CompletedTask;
}
public void SetServiceStatus(bool isPlaying)
{
IsPlaying = isPlaying;
}
public bool GetServiceStatus()
{
return IsPlaying;
}
}
}
MAIN ACTIVITY
namespace SaferProject.Droid
{
[Activity(Label = "SaferProject.Droid", Theme = "#style/MainTheme", MainLauncher = false,
ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation,
ScreenOrientation = ScreenOrientation.Portrait, LaunchMode = LaunchMode.SingleTop)] //This is what controls orientation
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
public static MainActivity instance { set; get; }
protected override void OnCreate(Bundle savedInstanceState)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(savedInstanceState);
instance = this;
// Radio Button configuration
Xamarin.Forms.Forms.SetFlags(new string[] { "RadioButton_Experimental" });
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
LoadApplication(new App());
//CreateNotificationFromIntent(Intent); //Local Notification - CRIADO NA MADRUGADA
//################ Início OneSignal #################
// Remove this method to stop OneSignal Debugging
OneSignal.Current.SetLogLevel(LOG_LEVEL.VERBOSE, LOG_LEVEL.NONE);
OneSignal.Current.StartInit("417d7b75-ed42-4ca5-aed3-42612d260235")
.InFocusDisplaying(OSInFocusDisplayOption.Notification)
.EndInit();
//################# Fim OneSignal ###################
}
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults)
{
Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);
base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
}
ANDROID MANIFEST
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="6" android:versionName="1.2.0" package="br.com.safertechnology.saferproject" android:installLocation="auto">
<uses-sdk android:minSdkVersion="24" android:targetSdkVersion="30" />
<permission android:name="$br.com.safertechnology.saferproject.permission.C2D_MESSAGE" android:protectionLevel="signature" />
<application android:label="Safer" android:icon="#mipmap/ic_launcher" android:fullBackupContent="#xml/auto_backup_rules">
<receiver android:name="com.onesignal.GcmBroadcastReceiver" android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<category android:name="$br.com.safertechnology.saferproject" />
</intent-filter>
</receiver>
</application>
<uses-permission android:name="$com.aolserra.sirene.permission.C2D_MESSAGE" />
<uses-permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.FLASHLIGHT" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="com.android.alarm.permission.SET_ALARM" />
</manifest>
IOS SERVICE
[assembly: Xamarin.Forms.Dependency(typeof(PlaySoundService))]
namespace SaferProject.iOS.Services
{
public class PlaySoundService : IPlaySoundService
{
private static PlaySoundService _instance;
readonly SystemSound Sound;
bool IsPlaying;
public static PlaySoundService GetInstance()
{
if (_instance == null)
{
_instance = new PlaySoundService();
}
return _instance;
}
public PlaySoundService()
{
AVAudioSession audioSession = AVAudioSession.SharedInstance();
NSError error;
audioSession.OverrideOutputAudioPort(AVAudioSessionPortOverride.Speaker, out error);
Sound = new SystemSound(1151); //1304 (Alarm)
}
public Task PlaySystemSound()
{
Sound.PlaySystemSound();
Vibration.Vibrate(500);
SetServiceStatus(true);
return Task.CompletedTask;
}
public Task StopSystemSound()
{
Sound.Close();
Vibration.Cancel();
SetServiceStatus(false);
return Task.CompletedTask;
}
public void SetServiceStatus(bool isPlaying)
{
IsPlaying = isPlaying;
}
public bool GetServiceStatus()
{
return IsPlaying;
}
}
}
APPDELEGATE
namespace SaferProject.iOS
{
// The UIApplicationDelegate for the application. This class is responsible for launching the
// User Interface of the application, as well as listening (and optionally responding) to
// application events from iOS.
[Register("AppDelegate")]
public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
{
//
// This method is invoked when the application has loaded and is ready to run. In this
// method you should instantiate the window, load the UI into it and then make the window
// visible.
//
// You have 17 seconds to return from this method, or iOS will terminate your application.
//
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
global::Xamarin.Forms.Forms.Init();
LoadApplication(new App());
//return base.FinishedLaunching(app, options);
base.FinishedLaunching(app, options);
//################ Início OneSignal #################
// Remove this method to stop OneSignal Debugging
OneSignal.Current.SetLogLevel(LOG_LEVEL.VERBOSE, LOG_LEVEL.NONE);
OneSignal.Current.StartInit("417d7b75-ed42-4ca5-aed3-42612d260235")
.Settings(new Dictionary<string, bool>() {
{ IOSSettings.kOSSettingsKeyAutoPrompt, false },
{ IOSSettings.kOSSettingsKeyInAppLaunchURL, false } })
.InFocusDisplaying(OSInFocusDisplayOption.Notification)
.EndInit();
// The promptForPushNotificationsWithUserResponse function will show the iOS push notification prompt. We recommend removing the following code and instead using an In-App Message to prompt for notification permission (See step 7)
OneSignal.Current.RegisterForPushNotifications();
return true;
//################# Fim OneSignal ###################
}
}
}
INFO.PLIST
Info.Plist
I'm following the instructions on this page to create the push notifications. I've actually done it once before and was able to get it to work (a few weeks back), took some time away, and figured I'd do the tutorial again as a refresher only now, for some reason, I can't even get the code to hit the OnNewToken method to generate my token and register the device with the notification hub.
I've watched dozens of videos, read other tutorials, and they're all saying / showing pretty much the same thing so I think I need a new pair of eyes to show me what I'm missing this 2nd time around.
I've tried to pull out specific information but still keep it as readable as I could.
Installed NuGet packages:
Xamarin.Firebase.Messaging - v71.1740.0
Xamarin.GooglePlayServices.Base - v71.1610.0
Xamarin.Forms - v4.4.0.991640
Files in Android project
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="(my firebase package / project package name)" android:installLocation="auto">
<uses-sdk android:minSdkVersion="21" />
<uses-permission android:name="android.permission.INTERNET" />
<!--
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
-->
<application>
<receiver android:name="com.google.firebase.iid.FirebaseInstanceIdInternalReceiver" android:exported="false" />
<receiver android:name="com.google.firebase.iid.FirebaseInstanceIdReceiver" android:exported="true" android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="${applicationId}" />
</intent-filter>
</receiver>
</application>
</manifest>
AppConstants
public static class AppConstants
{
public static string NotificationChannelName { get; set; } = "XamarinNotifyChannel";
public static string NotificationHubName { get; set; } = "(my azure notification hub name)";
public static string ListenConnectionString { get; set; } = "(my default listen shared access signature from azure portal)";
public static string DebugTag { get; set; } = "XamarinNotify";
public static string[] SubscriptionTags { get; set; } = { "default" };
public static string FCMTemplateBody { get; set; } = "{\"data\":{\"message\":\"$(messageParam)\"}}";
public static string APNTemplateBody { get; set; } = "{\"aps\":{\"alert\":\"$(messageParam)\"}}";
}
FirebaseService
[Service(Name = "(my package name).MyFirebaseMessagingService")]
[IntentFilter(new[] { "com.google.firebase.MESSAGING_EVENT" })]
public class FirebaseService : FirebaseMessagingService
{
public override void OnNewToken(string token)
{
base.OnNewToken(token);
Console.WriteLine("NEW_TOKEN", token);
SendRegistrationToServer(token);
}
void SendRegistrationToServer(string token)
{
NotificationHub hub = new NotificationHub(AppConstants.NotificationHubName, AppConstants.ListenConnectionString, this);
// register device with Azure Notification Hub using the token from FCM
Registration reg = hub.Register(token, AppConstants.SubscriptionTags);
// subscribe to the SubscriptionTags list with a simple template.
string pnsHandle = reg.PNSHandle;
hub.RegisterTemplate(pnsHandle, "defaultTemplate", AppConstants.FCMTemplateBody, AppConstants.SubscriptionTags);
}
public override void OnMessageReceived(RemoteMessage message)
{
base.OnMessageReceived(message);
string messageBody = string.Empty;
if (message.GetNotification() != null)
{
messageBody = message.GetNotification().Body;
}
else
{
messageBody = message.Data.Values.First();
}
try
{
MessagingCenter.Send(messageBody, "Update");
}
catch (Exception e)
{ }
SendLocalNotification(messageBody);
}
void SendLocalNotification(string body)
{
var intent = new Intent(this, typeof(MainActivity));
intent.AddFlags(ActivityFlags.ClearTop);
intent.PutExtra("message", body);
//Unique request code to avoid PendingIntent collision.
var requestCode = new Random().Next();
var pendingIntent = PendingIntent.GetActivity(this, requestCode, intent, PendingIntentFlags.OneShot);
var notificationBuilder = new NotificationCompat.Builder(this)
.SetContentTitle("XamarinNotify Message")
.SetSmallIcon(Resource.Drawable.ic_launcher)
.SetContentText(body)
.SetAutoCancel(true)
.SetShowWhen(false)
.SetContentIntent(pendingIntent);
if (Build.VERSION.SdkInt >= BuildVersionCodes.O)
{
notificationBuilder.SetChannelId(AppConstants.NotificationChannelName);
}
var notificationManager = NotificationManager.FromContext(this);
notificationManager.Notify(0, notificationBuilder.Build());
}
}
google-services.json
I just downloaded this file from Firebase, added it to the Android project and set the Build Action to GoogleServicesJson.
Hopefully somebody can see what I'm missing as I've had this same tutorial working before.
Please uninstall the application in your android, then redeploy it.
onNewToken() will be called only once per installation.
If you need it to be called again, uninstall the app from your device and restart it.
You forgot [IntentFilter(new[] { "com.google.firebase.INSTANCE_ID_EVENT" })]
[Service()]
[IntentFilter(new[] { "com.google.firebase.MESSAGING_EVENT" })]
[IntentFilter(new[] { "com.google.firebase.INSTANCE_ID_EVENT" })]
public class FirebaseService : FirebaseMessagingService
{
After two days of troubleshooting, finally i found out that the latest versions of the below nuget packages (or may be one of them) is causing this. I downgraded to the below versions and it started working.
Xamarin.Azure.NotificationHubs.Android -> v0.6.0
Xamarin.Firebase.Messaging -> v71.1740.0
Xamarin.GooglePlayServices.Base -> v71.1610.0
I am currently adding notifications to my Android app. I am using VS2015 and Xamarin. I figured I'd create a side project to test it first. I used the documentation from Xamarin and Firebase.
When my app launches, it tries to create a new token, but I get an error instead:
Java.Lang.IncompatibleClassChangeError: The method 'java.io.File
android.support.v4.content.ContextCompat.getNoBackupFilesDir(android.content.Context)'
was expected to be of type virtual but instead was found to be of type
direct
My code for fetching the token is
MainActivity
namespace ClientApp
{
[Activity(Label = "ClientApp", MainLauncher = true, Icon = "#drawable/icon")]
public class MainActivity : Activity
{
TextView msgText;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.Main);
msgText = FindViewById<TextView>(Resource.Id.msgText);
if (IsPlayServicesAvailable())
{
var intent = new Intent(this, typeof(RegistrationIntentService3));
StartService(intent);
}
}
public bool IsPlayServicesAvailable()
{
int resultCode = GoogleApiAvailability.Instance.IsGooglePlayServicesAvailable(this);
if (resultCode != ConnectionResult.Success)
{
if (GoogleApiAvailability.Instance.IsUserResolvableError(resultCode))
msgText.Text = GoogleApiAvailability.Instance.GetErrorString(resultCode);
else
{
msgText.Text = "Sorry, this device is not supported";
Finish();
}
return false;
}
else
{
msgText.Text = "Google Play Services is available.";
return true;
}
}
}
}
RegistrationIntentService.cs
using System;
using Android.App;
using Android.Content;
using Android.Util;
using Android.Gms.Gcm;
using Android.Gms.Gcm.Iid;
using Android.Support.V4.Content;
namespace ClientApp
{
[Service(Exported = false)]
class RegistrationIntentService : IntentService
{
static object locker = new object();
public RegistrationIntentService() : base("RegistrationIntentService") { }
protected override void OnHandleIntent(Intent intent)
{
try
{
Log.Info("RegistrationIntentService", "Calling InstanceID.GetToken");
lock (locker)
{
var token = InstanceID.GetInstance(this).GetToken("My_Sender_ID", GoogleCloudMessaging.InstanceIdScope, null);
Log.Info("RegistrationIntentService", "GCM Registration Token: " + token);
SendRegistrationToAppServer(token);
Subscribe(token);
}
}
catch (Exception e)
{
Log.Debug("RegistrationIntentService", "Failed to get a registration token");
return;
}
}
void SendRegistrationToAppServer(string token)
{
// Add custom implementation here as needed.
}
void Subscribe(string token)
{
var pubSub = GcmPubSub.GetInstance(this);
pubSub.Subscribe(token, "/topics/global", null);
}
}
}
My Manifest looks like this
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="MY_PACKAGE" android:versionCode="1" android:versionName="1.0" android:installLocation="auto">
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="MY_PACKAGE.permission.C2D_MESSAGE" />
<permission android:name="MY_PACKAGE.permission.C2D_MESSAGE" android:protectionLevel="signature" />
<application android:label="RemoteNotifications" android:icon="#drawable/Icon">
<receiver android:name="com.google.android.gms.gcm.GcmReceiver" android:exported="true" android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="MY_PACKAGE" />
</intent-filter>
</receiver>
</application>
<uses-sdk />
</manifest>
All my packages are up to date and using the latest stable:
Xamarin.GooglePlayServices.Gcm Version 9.0.0.2 with all its dependencies
Xamarin.Android.Support.v4 Version 24.2.1
ok, hello i am trying to implement pushwoosh notification on my xamarin.android application
i am on a stage were notification sent to client and when i click the notification it should redirect me on a certain activity and ui, here is my code
private void DoOnMessageReceive(String message)
{
var messageJson = new JSONObject(message);
if (messageJson.GetString("title") == "akotube")
{
var intent = new Intent(this, typeof(Second));
//intent.PutExtra(PushManager.PushReceiveEvent, messageJson.ToString());
intent.PutExtra("message", "akotube");
StartActivity(intent);
}
`
but i cant make it work , this is my reference pushwoosh
EDIT
Here is my manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest android:versionCode="1" android:versionName="1.0" package="com.pushwosh.sample" xmlns:android="http://schemas.android.com/apk/res/android">
<uses-sdk android:minSdkVersion="8" android:targetSdkVersion="19"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.VIBRATE"/>
<!--library-->
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<!-- GCM connects to Google Services. -->
<uses-permission android:name="android.permission.INTERNET"/>
<!-- GCM requires a Google account. -->
<uses-permission android:name="android.permission.GET_ACCOUNTS"/>
<!-- Keeps the processor from sleeping when a message is received. -->
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<!--
Creates a custom permission so only this app can receive its messages.
NOTE: the permission *must* be called PACKAGE.permission.C2D_MESSAGE,
where PACKAGE is the application's package name.
-->
<permission android:name="com.pushwosh.sample.permission.C2D_MESSAGE" android:protectionLevel="signature"/>
<uses-permission android:name="com.pushwosh.sample.permission.C2D_MESSAGE"/>
<!-- This app has permission to register and receive data message. -->
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE"/>
<!-- GCM requires Android SDK version 2.2 (API level 8) or above. -->
<!-- The targetSdkVersion is optional, but it's always a good practice
to target higher versions. -->
<application android:icon="#drawable/Icon" android:label="PushWosh">
<meta-data android:name="PW_APPID" android:value="CXXXX-XXXX"/>
<meta-data android:name="PW_PROJECT_ID" android:value="AXXXXXXXXX"/>
<activity android:name="com.arellomobile.android.push.PushWebview"/>
<activity android:name="com.arellomobile.android.push.MessageActivity"/>
<activity android:name="com.arellomobile.android.push.PushHandlerActivity"/>
<receiver android:name="com.google.android.gcm.GCMBroadcastReceiver" android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<!-- Receives the actual messages. -->
<action android:name="com.google.android.c2dm.intent.RECEIVE"/>
<!-- Receives the registration id. -->
<action android:name="com.google.android.c2dm.intent.REGISTRATION"/>
<category android:name="com.pushwosh.sample"/>
</intent-filter>
</receiver>
<service android:name="com.arellomobile.android.push.PushGCMIntentService"/>
</application>
</manifest>
here is my class
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.Main);
var btn = FindViewById<Button>(Resource.Id.MyButton);
btn.Click += btn_Click;
var goSecond = FindViewById<Button>(Resource.Id.btnGo);
goSecond.Click += goSecond_Click;
var unregister = FindViewById<Button>(Resource.Id.Unregister);
unregister.Click += unregister_Click;
_mMessageReceiver = new LocalMessageBroadcastReceiver {Activity = this};
_mRegisterReceiver = new LocalRegisterBroadcastReceiver {Activity = this};
_manager = PushManager.GetInstance(this);
//Register for push!
//_manager.RegisterForPushNotifications();
CheckMessage(Intent);
}
private void RegisterReceivers()
{
var intentFilter = new IntentFilter(PackageName + ".action.PUSH_MESSAGE_RECEIVE");
if (MBroadcastPush)
{
RegisterReceiver(_mMessageReceiver, intentFilter);
}
RegisterReceiver(_mRegisterReceiver, new IntentFilter(PackageName + "." + PushManager.RegisterBroadCastAction));
}
private void UnregisterReceivers()
{
UnregisterReceiver(_mMessageReceiver);
UnregisterReceiver(_mRegisterReceiver);
}
class LocalMessageBroadcastReceiver : BasePushMessageReceiver
{
public MainActivity Activity { private get; set; }
protected override void OnMessageReceive(Intent intent)
{
Activity.DoOnMessageReceive(intent.GetStringExtra(JsonDataKey));
}
}
class LocalRegisterBroadcastReceiver : RegisterBroadcastReceiver
{
public MainActivity Activity { private get; set; }
protected override void OnRegisterActionReceive(Context p0, Intent intent)
{
Activity.CheckMessage(intent);
}
}
private void CheckMessage(Intent intent)
{
if (null != intent)
{
if (intent.HasExtra(PushManager.PushReceiveEvent))
{
DoOnMessageReceive(intent.Extras.GetString(PushManager.PushReceiveEvent));
}
else if (intent.HasExtra(PushManager.RegisterEvent))
{
DoOnRegistered(intent.Extras.GetString(PushManager.RegisterEvent));
}
else if (intent.HasExtra(PushManager.UnregisterEvent))
{
DoOnUnregisteredError(intent.Extras.GetString(PushManager.UnregisterEvent));
}
else if (intent.HasExtra(PushManager.RegisterErrorEvent))
{
DoOnRegisteredError(intent.Extras.GetString(PushManager.RegisterErrorEvent));
}
else if (intent.HasExtra(PushManager.UnregisterErrorEvent))
{
DoOnUnregistered(intent.Extras.GetString(PushManager.UnregisterErrorEvent));
}
ResetIntentValues();
}
}
Your Category in Activity needs to match your Activity's Intent filter
Also
Getting the intent and starting the activity on your DoOnMessageRecieved
Intent intent = new Intent(this, typeof(SecondActivity));
intent.PutExtra(PushManager.PushReceiveEvent, messageJson.ToString());
StartActivity(intent);
Where the SecondActivity is the activity you want to navigate to.