mirror of
https://github.com/bitwarden/android.git
synced 2024-12-25 02:18:27 +03:00
local push notification implementation from lib
This commit is contained in:
parent
d5da1d6f3f
commit
7c6cc7b246
23 changed files with 851 additions and 59 deletions
|
@ -164,14 +164,6 @@
|
||||||
<Reference Include="Plugin.Settings.Abstractions, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
<Reference Include="Plugin.Settings.Abstractions, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
<HintPath>..\..\packages\Xam.Plugins.Settings.3.0.1\lib\MonoAndroid10\Plugin.Settings.Abstractions.dll</HintPath>
|
<HintPath>..\..\packages\Xam.Plugins.Settings.3.0.1\lib\MonoAndroid10\Plugin.Settings.Abstractions.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="PushNotification.Plugin, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
|
||||||
<HintPath>..\..\packages\Xam.Plugin.PushNotification.1.2.4\lib\MonoAndroid10\PushNotification.Plugin.dll</HintPath>
|
|
||||||
<Private>True</Private>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="PushNotification.Plugin.Abstractions, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
|
||||||
<HintPath>..\..\packages\Xam.Plugin.PushNotification.1.2.4\lib\MonoAndroid10\PushNotification.Plugin.Abstractions.dll</HintPath>
|
|
||||||
<Private>True</Private>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="SimpleInjector, Version=4.0.8.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
|
<Reference Include="SimpleInjector, Version=4.0.8.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
|
||||||
<HintPath>..\..\packages\SimpleInjector.4.0.8\lib\netstandard1.3\SimpleInjector.dll</HintPath>
|
<HintPath>..\..\packages\SimpleInjector.4.0.8\lib\netstandard1.3\SimpleInjector.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
@ -325,6 +317,7 @@
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
<Compile Include="Services\LogService.cs" />
|
<Compile Include="Services\LogService.cs" />
|
||||||
<Compile Include="Services\MemoryService.cs" />
|
<Compile Include="Services\MemoryService.cs" />
|
||||||
|
<Compile Include="Services\PushNotificationImplementation.cs" />
|
||||||
<Compile Include="Services\ReflectionService.cs" />
|
<Compile Include="Services\ReflectionService.cs" />
|
||||||
<Compile Include="Services\SqlService.cs" />
|
<Compile Include="Services\SqlService.cs" />
|
||||||
<Compile Include="SplashActivity.cs" />
|
<Compile Include="SplashActivity.cs" />
|
||||||
|
|
|
@ -12,8 +12,6 @@ using Plugin.Connectivity;
|
||||||
using Plugin.CurrentActivity;
|
using Plugin.CurrentActivity;
|
||||||
using Plugin.Fingerprint;
|
using Plugin.Fingerprint;
|
||||||
using Plugin.Settings;
|
using Plugin.Settings;
|
||||||
using PushNotification.Plugin;
|
|
||||||
using PushNotification.Plugin.Abstractions;
|
|
||||||
using XLabs.Ioc;
|
using XLabs.Ioc;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Plugin.Settings.Abstractions;
|
using Plugin.Settings.Abstractions;
|
||||||
|
|
564
src/Android/Services/PushNotificationImplementation.cs
Normal file
564
src/Android/Services/PushNotificationImplementation.cs
Normal file
|
@ -0,0 +1,564 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Android.App;
|
||||||
|
using Android.Content;
|
||||||
|
using Android.OS;
|
||||||
|
using Bit.App.Abstractions;
|
||||||
|
using Bit.App.Utilities;
|
||||||
|
using System.Threading;
|
||||||
|
using Xamarin.Forms;
|
||||||
|
using Android.Gms.Gcm.Iid;
|
||||||
|
using Android.Gms.Gcm;
|
||||||
|
using Java.IO;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
using Android.Support.V4.App;
|
||||||
|
using Android.Media;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Bit.Android.Services
|
||||||
|
{
|
||||||
|
public class PushNotificationImplementation : IPushNotification
|
||||||
|
{
|
||||||
|
private const string GcmPreferencesKey = "GCMPreferences";
|
||||||
|
private const string Tag = "PushNotification";
|
||||||
|
|
||||||
|
internal static IPushNotificationListener Listener { get; set; }
|
||||||
|
public string Token => GetRegistrationId();
|
||||||
|
|
||||||
|
public void Register()
|
||||||
|
{
|
||||||
|
|
||||||
|
System.Diagnostics.Debug.WriteLine(
|
||||||
|
$"{PushNotificationKey.DomainName} - Register - Registering push notifications");
|
||||||
|
|
||||||
|
if(string.IsNullOrEmpty(CrossPushNotification.SenderId))
|
||||||
|
{
|
||||||
|
System.Diagnostics.Debug.WriteLine(
|
||||||
|
$"{PushNotificationKey.DomainName} - Register - SenderId is missing.");
|
||||||
|
|
||||||
|
CrossPushNotification.PushNotificationListener.OnError(
|
||||||
|
$"{PushNotificationKey.DomainName} - Register - Sender Id is missing.", Device.Android);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
System.Diagnostics.Debug.WriteLine(
|
||||||
|
$"{PushNotificationKey.DomainName} - Register - Registering for Push Notifications");
|
||||||
|
|
||||||
|
ThreadPool.QueueUserWorkItem(state =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Intent intent = new Intent(global::Android.App.Application.Context,
|
||||||
|
typeof(PushNotificationRegistrationIntentService));
|
||||||
|
|
||||||
|
global::Android.App.Application.Context.StartService(intent);
|
||||||
|
}
|
||||||
|
catch(Exception ex)
|
||||||
|
{
|
||||||
|
System.Diagnostics.Debug.WriteLine($"{Tag} - Error : {ex.Message}");
|
||||||
|
CrossPushNotification.PushNotificationListener.OnError($"{Tag} - Register - {ex.Message}",
|
||||||
|
Device.Android);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Unregister()
|
||||||
|
{
|
||||||
|
ThreadPool.QueueUserWorkItem(state =>
|
||||||
|
{
|
||||||
|
System.Diagnostics.Debug.WriteLine(
|
||||||
|
$"{PushNotificationKey.DomainName} - Unregister - Unregistering push notifications");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
InstanceID instanceID = InstanceID.GetInstance(global::Android.App.Application.Context);
|
||||||
|
instanceID.DeleteToken(CrossPushNotification.SenderId, GoogleCloudMessaging.InstanceIdScope);
|
||||||
|
|
||||||
|
CrossPushNotification.PushNotificationListener.OnUnregistered(Device.Android);
|
||||||
|
StoreRegistrationId(global::Android.App.Application.Context, string.Empty);
|
||||||
|
|
||||||
|
}
|
||||||
|
catch(IOException ex)
|
||||||
|
{
|
||||||
|
System.Diagnostics.Debug.WriteLine($"{Tag} - Error : {ex.Message}");
|
||||||
|
CrossPushNotification.PushNotificationListener.OnError(
|
||||||
|
$"{Tag} - Unregister - {ex.Message}", Device.Android);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetRegistrationId()
|
||||||
|
{
|
||||||
|
var retVal = string.Empty;
|
||||||
|
var context = global::Android.App.Application.Context;
|
||||||
|
var prefs = GetGCMPreferences(context);
|
||||||
|
var registrationId = prefs.GetString(PushNotificationKey.Token, string.Empty);
|
||||||
|
if(string.IsNullOrEmpty(registrationId))
|
||||||
|
{
|
||||||
|
System.Diagnostics.Debug.WriteLine($"{PushNotificationKey.DomainName} - Registration not found.");
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if app was updated; if so, it must clear the registration ID
|
||||||
|
// since the existing registration ID is not guaranteed to work with
|
||||||
|
// the new app version.
|
||||||
|
var registeredVersion = prefs.GetInt(PushNotificationKey.AppVersion, Java.Lang.Integer.MinValue);
|
||||||
|
var currentVersion = GetAppVersion(context);
|
||||||
|
if(registeredVersion != currentVersion)
|
||||||
|
{
|
||||||
|
System.Diagnostics.Debug.WriteLine($"{PushNotificationKey.DomainName} - App version changed.");
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
retVal = registrationId;
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static ISharedPreferences GetGCMPreferences(Context context)
|
||||||
|
{
|
||||||
|
// This sample app persists the registration ID in shared preferences, but
|
||||||
|
// how you store the registration ID in your app is up to you.
|
||||||
|
return context.GetSharedPreferences(GcmPreferencesKey, FileCreationMode.Private);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static int GetAppVersion(Context context)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var packageInfo = context.PackageManager.GetPackageInfo(context.PackageName, 0);
|
||||||
|
return packageInfo.VersionCode;
|
||||||
|
}
|
||||||
|
catch(global::Android.Content.PM.PackageManager.NameNotFoundException e)
|
||||||
|
{
|
||||||
|
// should never happen
|
||||||
|
throw new Java.Lang.RuntimeException("Could not get package name: " + e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void StoreRegistrationId(Context context, string regId)
|
||||||
|
{
|
||||||
|
var prefs = GetGCMPreferences(context);
|
||||||
|
var appVersion = GetAppVersion(context);
|
||||||
|
|
||||||
|
System.Diagnostics.Debug.WriteLine(
|
||||||
|
$"{PushNotificationKey.DomainName} - Saving token on app version {appVersion}");
|
||||||
|
|
||||||
|
var editor = prefs.Edit();
|
||||||
|
editor.PutString(PushNotificationKey.Token, regId);
|
||||||
|
editor.PutInt(PushNotificationKey.AppVersion, appVersion);
|
||||||
|
editor.Commit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Service(Exported = false)]
|
||||||
|
public class PushNotificationRegistrationIntentService : IntentService
|
||||||
|
{
|
||||||
|
private const string Tag = "PushNotificationRegistationIntentService";
|
||||||
|
private string[] _topics = new string[] { "global" };
|
||||||
|
private readonly object _syncLock = new object();
|
||||||
|
|
||||||
|
protected override void OnHandleIntent(Intent intent)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var extras = intent.Extras;
|
||||||
|
lock(_syncLock)
|
||||||
|
{
|
||||||
|
var instanceID = InstanceID.GetInstance(global::Android.App.Application.Context);
|
||||||
|
var token = instanceID.GetToken(CrossPushNotification.SenderId,
|
||||||
|
GoogleCloudMessaging.InstanceIdScope, null);
|
||||||
|
CrossPushNotification.PushNotificationListener.OnRegistered(token, Device.Android);
|
||||||
|
PushNotificationImplementation.StoreRegistrationId(global::Android.App.Application.Context, token);
|
||||||
|
SubscribeTopics(token);
|
||||||
|
System.Diagnostics.Debug.WriteLine($"{token} - Device registered, registration ID={Tag}");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
catch(Exception ex)
|
||||||
|
{
|
||||||
|
System.Diagnostics.Debug.WriteLine($"{ex.Message} - Error : {Tag}");
|
||||||
|
CrossPushNotification.PushNotificationListener.OnError(
|
||||||
|
$"{ex.ToString()} - Register - {Tag}", Device.Android);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SubscribeTopics(string token)
|
||||||
|
{
|
||||||
|
var pubSub = GcmPubSub.GetInstance(this);
|
||||||
|
foreach(var topic in _topics)
|
||||||
|
{
|
||||||
|
pubSub.Subscribe(token, "/topics/" + topic, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Service(Exported = false)]
|
||||||
|
[IntentFilter(new string[] { "com.google.android.gms.iid.InstanceID" })]
|
||||||
|
public class PushNotificationInstanceIDListenerService : InstanceIDListenerService
|
||||||
|
{
|
||||||
|
private const string Tag = "PushNotificationInstanceIDLS";
|
||||||
|
|
||||||
|
public override void OnTokenRefresh()
|
||||||
|
{
|
||||||
|
base.OnTokenRefresh();
|
||||||
|
ThreadPool.QueueUserWorkItem(state =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var intent = new Intent(global::Android.App.Application.Context,
|
||||||
|
typeof(PushNotificationRegistrationIntentService));
|
||||||
|
global::Android.App.Application.Context.StartService(intent);
|
||||||
|
}
|
||||||
|
catch(Exception ex)
|
||||||
|
{
|
||||||
|
System.Diagnostics.Debug.WriteLine($"{ex.Message} - Error : {Tag}");
|
||||||
|
CrossPushNotification.PushNotificationListener.OnError(
|
||||||
|
$"{ex.ToString()} - Register - {Tag}", Device.Android);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Service(Exported = false, Name = "pushnotification.plugin.PushNotificationGcmListener")]
|
||||||
|
[IntentFilter(new string[] { "com.google.android.c2dm.intent.RECEIVE" },
|
||||||
|
Categories = new string[] { "com.x8bit.bitwarden" })]
|
||||||
|
public class PushNotificationGcmListener : GcmListenerService
|
||||||
|
{
|
||||||
|
public override void OnMessageReceived(string from, Bundle extras)
|
||||||
|
{
|
||||||
|
if(extras != null && !extras.IsEmpty)
|
||||||
|
{
|
||||||
|
System.Diagnostics.Debug.WriteLine(
|
||||||
|
$"{PushNotificationKey.DomainName} - GCM Listener - Push Received");
|
||||||
|
|
||||||
|
var parameters = new Dictionary<string, object>();
|
||||||
|
var values = new JObject();
|
||||||
|
foreach(var key in extras.KeySet())
|
||||||
|
{
|
||||||
|
var value = extras.Get(key).ToString();
|
||||||
|
|
||||||
|
if(ValidateJSON(value))
|
||||||
|
{
|
||||||
|
values.Add(key, JObject.Parse(value));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
values.Add(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
parameters.Add(key, extras.Get(key));
|
||||||
|
System.Diagnostics.Debug.WriteLine(
|
||||||
|
$"{PushNotificationKey.DomainName} - GCM Listener - Push Params {key} : {extras.Get(key)}");
|
||||||
|
}
|
||||||
|
|
||||||
|
var context = global::Android.App.Application.Context;
|
||||||
|
CrossPushNotification.PushNotificationListener.OnMessage(values, Device.Android);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var notifyId = 0;
|
||||||
|
var title = context.ApplicationInfo.LoadLabel(context.PackageManager);
|
||||||
|
var message = string.Empty;
|
||||||
|
var tag = string.Empty;
|
||||||
|
|
||||||
|
if(!string.IsNullOrEmpty(CrossPushNotification.NotificationContentTextKey) &&
|
||||||
|
parameters.ContainsKey(CrossPushNotification.NotificationContentTextKey))
|
||||||
|
{
|
||||||
|
message = parameters[CrossPushNotification.NotificationContentTextKey].ToString();
|
||||||
|
}
|
||||||
|
else if(parameters.ContainsKey(PushNotificationKey.Alert))
|
||||||
|
{
|
||||||
|
message = parameters[PushNotificationKey.Alert].ToString();
|
||||||
|
}
|
||||||
|
else if(parameters.ContainsKey(PushNotificationKey.Message))
|
||||||
|
{
|
||||||
|
message = parameters[PushNotificationKey.Message].ToString();
|
||||||
|
}
|
||||||
|
else if(parameters.ContainsKey(PushNotificationKey.Subtitle))
|
||||||
|
{
|
||||||
|
message = parameters[PushNotificationKey.Subtitle].ToString();
|
||||||
|
}
|
||||||
|
else if(parameters.ContainsKey(PushNotificationKey.Text))
|
||||||
|
{
|
||||||
|
message = parameters[PushNotificationKey.Text].ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!string.IsNullOrEmpty(CrossPushNotification.NotificationContentTitleKey) &&
|
||||||
|
parameters.ContainsKey(CrossPushNotification.NotificationContentTitleKey))
|
||||||
|
{
|
||||||
|
title = parameters[CrossPushNotification.NotificationContentTitleKey].ToString();
|
||||||
|
}
|
||||||
|
else if(parameters.ContainsKey(PushNotificationKey.Title))
|
||||||
|
{
|
||||||
|
if(!string.IsNullOrEmpty(message))
|
||||||
|
{
|
||||||
|
title = parameters[PushNotificationKey.Title].ToString();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
message = parameters[PushNotificationKey.Title].ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(string.IsNullOrEmpty(message))
|
||||||
|
{
|
||||||
|
var data = (
|
||||||
|
!string.IsNullOrEmpty(CrossPushNotification.NotificationContentDataKey) &&
|
||||||
|
values[CrossPushNotification.NotificationContentDataKey] != null) ?
|
||||||
|
values[CrossPushNotification.NotificationContentDataKey] :
|
||||||
|
values[PushNotificationKey.Data];
|
||||||
|
|
||||||
|
if(data != null)
|
||||||
|
{
|
||||||
|
if(!string.IsNullOrEmpty(CrossPushNotification.NotificationContentTextKey) &&
|
||||||
|
data[CrossPushNotification.NotificationContentTextKey] != null)
|
||||||
|
{
|
||||||
|
message = data[CrossPushNotification.NotificationContentTextKey].ToString();
|
||||||
|
}
|
||||||
|
else if(data[PushNotificationKey.Alert] != null)
|
||||||
|
{
|
||||||
|
message = data[PushNotificationKey.Alert].ToString();
|
||||||
|
}
|
||||||
|
else if(data[PushNotificationKey.Message] != null)
|
||||||
|
{
|
||||||
|
message = data[PushNotificationKey.Message].ToString();
|
||||||
|
}
|
||||||
|
else if(data[PushNotificationKey.Subtitle] != null)
|
||||||
|
{
|
||||||
|
message = data[PushNotificationKey.Subtitle].ToString();
|
||||||
|
}
|
||||||
|
else if(data[PushNotificationKey.Text] != null)
|
||||||
|
{
|
||||||
|
message = data[PushNotificationKey.Text].ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!string.IsNullOrEmpty(CrossPushNotification.NotificationContentTitleKey) &&
|
||||||
|
data[CrossPushNotification.NotificationContentTitleKey] != null)
|
||||||
|
{
|
||||||
|
title = data[CrossPushNotification.NotificationContentTitleKey].ToString();
|
||||||
|
}
|
||||||
|
else if(data[PushNotificationKey.Title] != null)
|
||||||
|
{
|
||||||
|
if(!string.IsNullOrEmpty(message))
|
||||||
|
{
|
||||||
|
title = data[PushNotificationKey.Title].ToString();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
message = data[PushNotificationKey.Title].ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(parameters.ContainsKey(PushNotificationKey.Id))
|
||||||
|
{
|
||||||
|
var str = parameters[PushNotificationKey.Id].ToString();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
notifyId = Convert.ToInt32(str);
|
||||||
|
}
|
||||||
|
catch(Exception)
|
||||||
|
{
|
||||||
|
// Keep the default value of zero for the notify_id, but log the conversion problem.
|
||||||
|
System.Diagnostics.Debug.WriteLine("Failed to convert {0} to an integer", str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(parameters.ContainsKey(PushNotificationKey.Tag))
|
||||||
|
{
|
||||||
|
tag = parameters[PushNotificationKey.Tag].ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!parameters.ContainsKey(PushNotificationKey.Silent) ||
|
||||||
|
!System.Boolean.Parse(parameters[PushNotificationKey.Silent].ToString()))
|
||||||
|
{
|
||||||
|
if(CrossPushNotification.PushNotificationListener.ShouldShowNotification())
|
||||||
|
{
|
||||||
|
CreateNotification(title, message, notifyId, tag, extras);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
catch(Java.Lang.Exception ex)
|
||||||
|
{
|
||||||
|
System.Diagnostics.Debug.WriteLine(ex.ToString());
|
||||||
|
}
|
||||||
|
catch(Exception ex1)
|
||||||
|
{
|
||||||
|
System.Diagnostics.Debug.WriteLine(ex1.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CreateNotification(string title, string message, int notifyId, string tag, Bundle extras)
|
||||||
|
{
|
||||||
|
System.Diagnostics.Debug.WriteLine(
|
||||||
|
$"{PushNotificationKey.DomainName} - PushNotification - Message {title} : {message}");
|
||||||
|
|
||||||
|
NotificationCompat.Builder builder = null;
|
||||||
|
var context = global::Android.App.Application.Context;
|
||||||
|
|
||||||
|
if(CrossPushNotification.SoundUri == null)
|
||||||
|
{
|
||||||
|
CrossPushNotification.SoundUri = RingtoneManager.GetDefaultUri(RingtoneType.Notification);
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if(CrossPushNotification.IconResource == 0)
|
||||||
|
{
|
||||||
|
CrossPushNotification.IconResource = context.ApplicationInfo.Icon;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var name = context.Resources.GetResourceName(CrossPushNotification.IconResource);
|
||||||
|
if(name == null)
|
||||||
|
{
|
||||||
|
CrossPushNotification.IconResource = context.ApplicationInfo.Icon;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(global::Android.Content.Res.Resources.NotFoundException ex)
|
||||||
|
{
|
||||||
|
CrossPushNotification.IconResource = context.ApplicationInfo.Icon;
|
||||||
|
System.Diagnostics.Debug.WriteLine(ex.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
var resultIntent = context.PackageManager.GetLaunchIntentForPackage(context.PackageName);
|
||||||
|
if(extras != null)
|
||||||
|
{
|
||||||
|
resultIntent.PutExtras(extras);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a PendingIntent; we're only using one PendingIntent (ID = 0):
|
||||||
|
const int pendingIntentId = 0;
|
||||||
|
var resultPendingIntent = PendingIntent.GetActivity(context, pendingIntentId,
|
||||||
|
resultIntent, PendingIntentFlags.OneShot);
|
||||||
|
|
||||||
|
// Build the notification
|
||||||
|
builder = new NotificationCompat.Builder(context)
|
||||||
|
.SetAutoCancel(true) // dismiss the notification from the notification area when the user clicks on it
|
||||||
|
.SetContentIntent(resultPendingIntent) // start up this activity when the user clicks the intent.
|
||||||
|
.SetContentTitle(title) // Set the title
|
||||||
|
.SetSound(CrossPushNotification.SoundUri)
|
||||||
|
.SetSmallIcon(CrossPushNotification.IconResource) // This is the icon to display
|
||||||
|
.SetContentText(message); // the message to display.
|
||||||
|
|
||||||
|
if(Build.VERSION.SdkInt >= BuildVersionCodes.JellyBean)
|
||||||
|
{
|
||||||
|
// Using BigText notification style to support long message
|
||||||
|
var style = new NotificationCompat.BigTextStyle();
|
||||||
|
style.BigText(message);
|
||||||
|
builder.SetStyle(style);
|
||||||
|
}
|
||||||
|
|
||||||
|
var notificationManager = (NotificationManager)context.GetSystemService(NotificationService);
|
||||||
|
notificationManager.Notify(tag, notifyId, builder.Build());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool ValidateJSON(string s)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
JObject.Parse(s);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch(JsonReaderException ex)
|
||||||
|
{
|
||||||
|
System.Diagnostics.Debug.WriteLine(ex.ToString());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[BroadcastReceiver(Exported = true, Permission = "com.google.android.c2dm.permission.SEND")]
|
||||||
|
[IntentFilter(new string[] { "com.google.android.c2dm.intent.RECEIVE" },
|
||||||
|
Categories = new string[] { "com.x8bit.bitwarden" })]
|
||||||
|
public class PushNotificationsReceiver : GcmReceiver
|
||||||
|
{ }
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
public class PushNotificationService : Service
|
||||||
|
{
|
||||||
|
public override void OnCreate()
|
||||||
|
{
|
||||||
|
base.OnCreate();
|
||||||
|
System.Diagnostics.Debug.WriteLine("Push Notification Service - Created");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
|
||||||
|
{
|
||||||
|
System.Diagnostics.Debug.WriteLine("Push Notification Service - Started");
|
||||||
|
return StartCommandResult.Sticky;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IBinder OnBind(Intent intent)
|
||||||
|
{
|
||||||
|
System.Diagnostics.Debug.WriteLine("Push Notification Service - Binded");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnDestroy()
|
||||||
|
{
|
||||||
|
System.Diagnostics.Debug.WriteLine("Push Notification Service - Destroyed");
|
||||||
|
base.OnDestroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class CrossPushNotification
|
||||||
|
{
|
||||||
|
private static Lazy<IPushNotification> Implementation = new Lazy<IPushNotification>(
|
||||||
|
() => new PushNotificationImplementation(),
|
||||||
|
LazyThreadSafetyMode.PublicationOnly);
|
||||||
|
public static bool IsInitialized => PushNotificationListener != null;
|
||||||
|
public static IPushNotificationListener PushNotificationListener { get; private set; }
|
||||||
|
|
||||||
|
public static string SenderId { get; set; }
|
||||||
|
public static string NotificationContentTitleKey { get; set; }
|
||||||
|
public static string NotificationContentTextKey { get; set; }
|
||||||
|
public static string NotificationContentDataKey { get; set; }
|
||||||
|
public static int IconResource { get; set; }
|
||||||
|
public static global::Android.Net.Uri SoundUri { get; set; }
|
||||||
|
|
||||||
|
public static void Initialize<T>(T listener, string senderId) where T : IPushNotificationListener
|
||||||
|
{
|
||||||
|
SenderId = senderId;
|
||||||
|
|
||||||
|
if(PushNotificationListener == null)
|
||||||
|
{
|
||||||
|
PushNotificationListener = listener;
|
||||||
|
System.Diagnostics.Debug.WriteLine("PushNotification plugin initialized.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
System.Diagnostics.Debug.WriteLine("PushNotification plugin already initialized.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Initialize<T>(string senderId) where T : IPushNotificationListener, new()
|
||||||
|
{
|
||||||
|
Initialize(new T(), senderId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IPushNotification Current
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if(!IsInitialized)
|
||||||
|
{
|
||||||
|
throw new Exception("Not initialized.");
|
||||||
|
}
|
||||||
|
|
||||||
|
var ret = Implementation.Value;
|
||||||
|
if(ret == null)
|
||||||
|
{
|
||||||
|
throw new Exception("Not in PCL");
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -69,7 +69,6 @@
|
||||||
<package id="System.Xml.XDocument" version="4.0.11" targetFramework="monoandroid71" />
|
<package id="System.Xml.XDocument" version="4.0.11" targetFramework="monoandroid71" />
|
||||||
<package id="Validation" version="2.3.7" targetFramework="monoandroid60" />
|
<package id="Validation" version="2.3.7" targetFramework="monoandroid60" />
|
||||||
<package id="Xam.Plugin.Connectivity" version="3.0.2" targetFramework="monoandroid71" />
|
<package id="Xam.Plugin.Connectivity" version="3.0.2" targetFramework="monoandroid71" />
|
||||||
<package id="Xam.Plugin.PushNotification" version="1.2.4" targetFramework="monoandroid60" developmentDependency="true" />
|
|
||||||
<package id="Xam.Plugins.Settings" version="3.0.1" targetFramework="monoandroid71" />
|
<package id="Xam.Plugins.Settings" version="3.0.1" targetFramework="monoandroid71" />
|
||||||
<package id="Xamarin.Android.Support.Animated.Vector.Drawable" version="23.3.0" targetFramework="monoandroid60" />
|
<package id="Xamarin.Android.Support.Animated.Vector.Drawable" version="23.3.0" targetFramework="monoandroid60" />
|
||||||
<package id="Xamarin.Android.Support.Design" version="23.3.0" targetFramework="monoandroid60" />
|
<package id="Xamarin.Android.Support.Design" version="23.3.0" targetFramework="monoandroid60" />
|
||||||
|
|
9
src/App/Abstractions/Services/IPushNotification.cs
Normal file
9
src/App/Abstractions/Services/IPushNotification.cs
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
namespace Bit.App.Abstractions
|
||||||
|
{
|
||||||
|
public interface IPushNotification
|
||||||
|
{
|
||||||
|
string Token { get; }
|
||||||
|
void Register();
|
||||||
|
void Unregister();
|
||||||
|
}
|
||||||
|
}
|
13
src/App/Abstractions/Services/IPushNotificationListener.cs
Normal file
13
src/App/Abstractions/Services/IPushNotificationListener.cs
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
|
namespace Bit.App.Abstractions
|
||||||
|
{
|
||||||
|
public interface IPushNotificationListener
|
||||||
|
{
|
||||||
|
void OnMessage(JObject values, string device);
|
||||||
|
void OnRegistered(string token, string device);
|
||||||
|
void OnUnregistered(string device);
|
||||||
|
void OnError(string message, string device);
|
||||||
|
bool ShouldShowNotification();
|
||||||
|
}
|
||||||
|
}
|
|
@ -44,6 +44,8 @@
|
||||||
<Compile Include="Abstractions\Repositories\ISettingsRepository.cs" />
|
<Compile Include="Abstractions\Repositories\ISettingsRepository.cs" />
|
||||||
<Compile Include="Abstractions\Services\IAppSettingsService.cs" />
|
<Compile Include="Abstractions\Services\IAppSettingsService.cs" />
|
||||||
<Compile Include="Abstractions\Services\IMemoryService.cs" />
|
<Compile Include="Abstractions\Services\IMemoryService.cs" />
|
||||||
|
<Compile Include="Abstractions\Services\IPushNotificationListener.cs" />
|
||||||
|
<Compile Include="Abstractions\Services\IPushNotification.cs" />
|
||||||
<Compile Include="Abstractions\Services\ISettingsService.cs" />
|
<Compile Include="Abstractions\Services\ISettingsService.cs" />
|
||||||
<Compile Include="Abstractions\Services\ITokenService.cs" />
|
<Compile Include="Abstractions\Services\ITokenService.cs" />
|
||||||
<Compile Include="Abstractions\Services\IHttpService.cs" />
|
<Compile Include="Abstractions\Services\IHttpService.cs" />
|
||||||
|
@ -87,6 +89,7 @@
|
||||||
<Compile Include="Controls\PinControl.cs" />
|
<Compile Include="Controls\PinControl.cs" />
|
||||||
<Compile Include="Controls\VaultAttachmentsViewCell.cs" />
|
<Compile Include="Controls\VaultAttachmentsViewCell.cs" />
|
||||||
<Compile Include="Controls\VaultListViewCell.cs" />
|
<Compile Include="Controls\VaultListViewCell.cs" />
|
||||||
|
<Compile Include="Enums\DeviceType.cs" />
|
||||||
<Compile Include="Enums\FieldType.cs" />
|
<Compile Include="Enums\FieldType.cs" />
|
||||||
<Compile Include="Enums\TwoFactorProviderType.cs" />
|
<Compile Include="Enums\TwoFactorProviderType.cs" />
|
||||||
<Compile Include="Enums\EncryptionType.cs" />
|
<Compile Include="Enums\EncryptionType.cs" />
|
||||||
|
@ -355,6 +358,7 @@
|
||||||
<Compile Include="Utilities\Extentions.cs" />
|
<Compile Include="Utilities\Extentions.cs" />
|
||||||
<Compile Include="Utilities\ExtendedObservableCollection.cs" />
|
<Compile Include="Utilities\ExtendedObservableCollection.cs" />
|
||||||
<Compile Include="Utilities\ApiHttpClient.cs" />
|
<Compile Include="Utilities\ApiHttpClient.cs" />
|
||||||
|
<Compile Include="Utilities\PushNotificationKey.cs" />
|
||||||
<Compile Include="Utilities\TokenHttpRequestMessage.cs" />
|
<Compile Include="Utilities\TokenHttpRequestMessage.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -528,14 +532,6 @@
|
||||||
<Reference Include="Plugin.Settings.Abstractions, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
<Reference Include="Plugin.Settings.Abstractions, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
<HintPath>..\..\packages\Xam.Plugins.Settings.3.0.1\lib\netstandard1.0\Plugin.Settings.Abstractions.dll</HintPath>
|
<HintPath>..\..\packages\Xam.Plugins.Settings.3.0.1\lib\netstandard1.0\Plugin.Settings.Abstractions.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="PushNotification.Plugin, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
|
||||||
<HintPath>..\..\packages\Xam.Plugin.PushNotification.1.2.4\lib\portable-net45+wp8+wpa81+win8+MonoAndroid10+MonoTouch10+Xamarin.iOS10+UAP10\PushNotification.Plugin.dll</HintPath>
|
|
||||||
<Private>True</Private>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="PushNotification.Plugin.Abstractions, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
|
||||||
<HintPath>..\..\packages\Xam.Plugin.PushNotification.1.2.4\lib\portable-net45+wp8+wpa81+win8+MonoAndroid10+MonoTouch10+Xamarin.iOS10+UAP10\PushNotification.Plugin.Abstractions.dll</HintPath>
|
|
||||||
<Private>True</Private>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Splat, Version=1.6.2.0, Culture=neutral, processorArchitecture=MSIL">
|
<Reference Include="Splat, Version=1.6.2.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
<HintPath>..\..\packages\Splat.1.6.2\lib\Portable-net45+win+wpa81+wp80\Splat.dll</HintPath>
|
<HintPath>..\..\packages\Splat.1.6.2\lib\Portable-net45+win+wpa81+wp80\Splat.dll</HintPath>
|
||||||
<Private>True</Private>
|
<Private>True</Private>
|
||||||
|
|
9
src/App/Enums/DeviceType.cs
Normal file
9
src/App/Enums/DeviceType.cs
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
namespace Bit.App.Enums
|
||||||
|
{
|
||||||
|
public enum DeviceType
|
||||||
|
{
|
||||||
|
Android = 0,
|
||||||
|
iOS = 1,
|
||||||
|
UWP = 16
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
using Bit.App.Abstractions;
|
using Bit.App.Abstractions;
|
||||||
using PushNotification.Plugin.Abstractions;
|
using Bit.App.Enums;
|
||||||
using Xamarin.Forms;
|
using Xamarin.Forms;
|
||||||
|
|
||||||
namespace Bit.App.Models.Api
|
namespace Bit.App.Models.Api
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
using System;
|
using Bit.App.Enums;
|
||||||
using PushNotification.Plugin.Abstractions;
|
using System;
|
||||||
|
|
||||||
namespace Bit.App.Models.Api
|
namespace Bit.App.Models.Api
|
||||||
{
|
{
|
||||||
|
|
|
@ -7,7 +7,6 @@ using XLabs.Ioc;
|
||||||
using Acr.UserDialogs;
|
using Acr.UserDialogs;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Plugin.Settings.Abstractions;
|
using Plugin.Settings.Abstractions;
|
||||||
using PushNotification.Plugin.Abstractions;
|
|
||||||
using Bit.App.Utilities;
|
using Bit.App.Utilities;
|
||||||
|
|
||||||
namespace Bit.App.Pages
|
namespace Bit.App.Pages
|
||||||
|
|
|
@ -6,7 +6,6 @@ using Xamarin.Forms;
|
||||||
using XLabs.Ioc;
|
using XLabs.Ioc;
|
||||||
using Acr.UserDialogs;
|
using Acr.UserDialogs;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using PushNotification.Plugin.Abstractions;
|
|
||||||
using Bit.App.Models;
|
using Bit.App.Models;
|
||||||
using Bit.App.Utilities;
|
using Bit.App.Utilities;
|
||||||
using Bit.App.Enums;
|
using Bit.App.Enums;
|
||||||
|
|
|
@ -4,10 +4,7 @@ using Bit.App.Resources;
|
||||||
using Xamarin.Forms;
|
using Xamarin.Forms;
|
||||||
using XLabs.Ioc;
|
using XLabs.Ioc;
|
||||||
using Bit.App.Controls;
|
using Bit.App.Controls;
|
||||||
using Acr.UserDialogs;
|
|
||||||
using Plugin.Settings.Abstractions;
|
using Plugin.Settings.Abstractions;
|
||||||
using Plugin.Fingerprint.Abstractions;
|
|
||||||
using PushNotification.Plugin.Abstractions;
|
|
||||||
|
|
||||||
namespace Bit.App.Pages
|
namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
|
|
|
@ -7,7 +7,6 @@ using Bit.App.Controls;
|
||||||
using Acr.UserDialogs;
|
using Acr.UserDialogs;
|
||||||
using Plugin.Settings.Abstractions;
|
using Plugin.Settings.Abstractions;
|
||||||
using Plugin.Fingerprint.Abstractions;
|
using Plugin.Fingerprint.Abstractions;
|
||||||
using PushNotification.Plugin.Abstractions;
|
|
||||||
using Bit.App.Utilities;
|
using Bit.App.Utilities;
|
||||||
|
|
||||||
namespace Bit.App.Pages
|
namespace Bit.App.Pages
|
||||||
|
|
|
@ -9,7 +9,6 @@ using Bit.App.Resources;
|
||||||
using Xamarin.Forms;
|
using Xamarin.Forms;
|
||||||
using XLabs.Ioc;
|
using XLabs.Ioc;
|
||||||
using Bit.App.Utilities;
|
using Bit.App.Utilities;
|
||||||
using PushNotification.Plugin.Abstractions;
|
|
||||||
using Plugin.Settings.Abstractions;
|
using Plugin.Settings.Abstractions;
|
||||||
using Plugin.Connectivity.Abstractions;
|
using Plugin.Connectivity.Abstractions;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
using PushNotification.Plugin.Abstractions;
|
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using PushNotification.Plugin;
|
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
using Bit.App.Abstractions;
|
using Bit.App.Abstractions;
|
||||||
|
@ -37,7 +35,7 @@ namespace Bit.App.Services
|
||||||
_resolved = true;
|
_resolved = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnMessage(JObject value, DeviceType deviceType)
|
public void OnMessage(JObject value, string deviceType)
|
||||||
{
|
{
|
||||||
Resolve();
|
Resolve();
|
||||||
|
|
||||||
|
@ -144,7 +142,7 @@ namespace Bit.App.Services
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async void OnRegistered(string token, DeviceType deviceType)
|
public async void OnRegistered(string token, string deviceType)
|
||||||
{
|
{
|
||||||
Resolve();
|
Resolve();
|
||||||
|
|
||||||
|
@ -168,12 +166,12 @@ namespace Bit.App.Services
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnUnregistered(DeviceType deviceType)
|
public void OnUnregistered(string deviceType)
|
||||||
{
|
{
|
||||||
Debug.WriteLine("Push Notification - Device Unnregistered");
|
Debug.WriteLine("Push Notification - Device Unnregistered");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnError(string message, DeviceType deviceType)
|
public void OnError(string message, string deviceType)
|
||||||
{
|
{
|
||||||
Debug.WriteLine(string.Format("Push notification error - {0}", message));
|
Debug.WriteLine(string.Format("Push notification error - {0}", message));
|
||||||
}
|
}
|
||||||
|
|
78
src/App/Utilities/PushNotificationKey.cs
Normal file
78
src/App/Utilities/PushNotificationKey.cs
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
namespace Bit.App.Utilities
|
||||||
|
{
|
||||||
|
public static class PushNotificationKey
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Type
|
||||||
|
/// </summary>
|
||||||
|
public const string Type = "type";
|
||||||
|
/// <summary>
|
||||||
|
/// Error
|
||||||
|
/// </summary>
|
||||||
|
public const string Error = "error";
|
||||||
|
/// <summary>
|
||||||
|
/// Domain Name
|
||||||
|
/// </summary>
|
||||||
|
public const string DomainName = "CrossPushNotification";
|
||||||
|
/// <summary>
|
||||||
|
/// Title
|
||||||
|
/// </summary>
|
||||||
|
public const string Title = "title";
|
||||||
|
/// <summary>
|
||||||
|
/// Text
|
||||||
|
/// </summary>
|
||||||
|
public const string Text = "text";
|
||||||
|
/// <summary>
|
||||||
|
/// Subtitle
|
||||||
|
/// </summary>
|
||||||
|
public const string Subtitle = "subtitle";
|
||||||
|
/// <summary>
|
||||||
|
/// Message
|
||||||
|
/// </summary>
|
||||||
|
public const string Message = "message";
|
||||||
|
/// <summary>
|
||||||
|
/// Silent
|
||||||
|
/// </summary>
|
||||||
|
public const string Silent = "silent";
|
||||||
|
/// <summary>
|
||||||
|
/// Alert
|
||||||
|
/// </summary>
|
||||||
|
public const string Alert = "alert";
|
||||||
|
/// <summary>
|
||||||
|
/// Data
|
||||||
|
/// </summary>
|
||||||
|
public const string Data = "data";
|
||||||
|
/// <summary>
|
||||||
|
/// Token
|
||||||
|
/// </summary>
|
||||||
|
public const string Token = "token";
|
||||||
|
/// <summary>
|
||||||
|
/// App Version
|
||||||
|
/// </summary>
|
||||||
|
public const string AppVersion = "appVersion";
|
||||||
|
/// <summary>
|
||||||
|
/// IntentFromGcmMessage
|
||||||
|
/// </summary>
|
||||||
|
public const string IntentFromGcmMessage = "com.google.android.c2dm.intent.RECEIVE";
|
||||||
|
/// <summary>
|
||||||
|
/// BackOffMilliseconds
|
||||||
|
/// </summary>
|
||||||
|
public const string BackOffMilliseconds = "backoff_ms";
|
||||||
|
/// <summary>
|
||||||
|
/// ErrorServiceNotAvailable
|
||||||
|
/// </summary>
|
||||||
|
public const string ErrorServiceNotAvailable = "SERVICE_NOT_AVAILABLE";
|
||||||
|
/// <summary>
|
||||||
|
/// Tag
|
||||||
|
/// </summary>
|
||||||
|
public const string Tag = "tag";
|
||||||
|
/// <summary>
|
||||||
|
/// Id
|
||||||
|
/// </summary>
|
||||||
|
public const string Id = "id";
|
||||||
|
/// <summary>
|
||||||
|
/// RegistrationComplete
|
||||||
|
/// </summary>
|
||||||
|
public const string RegistrationComplete = "registrationComplete";
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,7 +16,6 @@
|
||||||
<package id="SQLitePCLRaw.core" version="1.1.8" targetFramework="portable45-net45+win8+wpa81" />
|
<package id="SQLitePCLRaw.core" version="1.1.8" targetFramework="portable45-net45+win8+wpa81" />
|
||||||
<package id="Validation" version="2.3.7" targetFramework="portable45-net45+win8+wpa81" />
|
<package id="Validation" version="2.3.7" targetFramework="portable45-net45+win8+wpa81" />
|
||||||
<package id="Xam.Plugin.Connectivity" version="3.0.2" targetFramework="portable45-net45+win8+wpa81" />
|
<package id="Xam.Plugin.Connectivity" version="3.0.2" targetFramework="portable45-net45+win8+wpa81" />
|
||||||
<package id="Xam.Plugin.PushNotification" version="1.2.4" targetFramework="portable45-net45+win8+wpa81" developmentDependency="true" />
|
|
||||||
<package id="Xam.Plugins.Settings" version="3.0.1" targetFramework="portable45-net45+win8+wpa81" />
|
<package id="Xam.Plugins.Settings" version="3.0.1" targetFramework="portable45-net45+win8+wpa81" />
|
||||||
<package id="Xamarin.FFImageLoading" version="2.2.9" targetFramework="portable45-net45+win8+wpa81" />
|
<package id="Xamarin.FFImageLoading" version="2.2.9" targetFramework="portable45-net45+win8+wpa81" />
|
||||||
<package id="Xamarin.FFImageLoading.Forms" version="2.2.9" targetFramework="portable45-net45+win8+wpa81" />
|
<package id="Xamarin.FFImageLoading.Forms" version="2.2.9" targetFramework="portable45-net45+win8+wpa81" />
|
||||||
|
|
|
@ -170,9 +170,6 @@
|
||||||
<PackageReference Include="Xam.Plugin.Connectivity">
|
<PackageReference Include="Xam.Plugin.Connectivity">
|
||||||
<Version>3.0.2</Version>
|
<Version>3.0.2</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Xam.Plugin.PushNotification">
|
|
||||||
<Version>1.2.4</Version>
|
|
||||||
</PackageReference>
|
|
||||||
<PackageReference Include="Xam.Plugins.Settings">
|
<PackageReference Include="Xam.Plugins.Settings">
|
||||||
<Version>3.0.1</Version>
|
<Version>3.0.1</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
|
|
@ -1,8 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using XLabs.Ioc;
|
using XLabs.Ioc;
|
||||||
|
|
||||||
using Foundation;
|
using Foundation;
|
||||||
using UIKit;
|
using UIKit;
|
||||||
using Bit.App.Abstractions;
|
using Bit.App.Abstractions;
|
||||||
|
@ -16,7 +13,6 @@ using Plugin.Settings.Abstractions;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using Xamarin.Forms;
|
using Xamarin.Forms;
|
||||||
using Bit.iOS.Core.Services;
|
using Bit.iOS.Core.Services;
|
||||||
using PushNotification.Plugin;
|
|
||||||
using Plugin.Connectivity.Abstractions;
|
using Plugin.Connectivity.Abstractions;
|
||||||
using Bit.App.Pages;
|
using Bit.App.Pages;
|
||||||
using HockeyApp.iOS;
|
using HockeyApp.iOS;
|
||||||
|
@ -81,14 +77,16 @@ namespace Bit.iOS
|
||||||
UINavigationBar.Appearance.ShadowImage = new UIImage();
|
UINavigationBar.Appearance.ShadowImage = new UIImage();
|
||||||
UINavigationBar.Appearance.SetBackgroundImage(new UIImage(), UIBarMetrics.Default);
|
UINavigationBar.Appearance.SetBackgroundImage(new UIImage(), UIBarMetrics.Default);
|
||||||
UIBarButtonItem.AppearanceWhenContainedIn(new Type[] { typeof(UISearchBar) }).TintColor = primaryColor;
|
UIBarButtonItem.AppearanceWhenContainedIn(new Type[] { typeof(UISearchBar) }).TintColor = primaryColor;
|
||||||
UIButton.AppearanceWhenContainedIn(new Type[] { typeof(UISearchBar) }).SetTitleColor(primaryColor, UIControlState.Normal);
|
UIButton.AppearanceWhenContainedIn(new Type[] { typeof(UISearchBar) }).SetTitleColor(primaryColor,
|
||||||
|
UIControlState.Normal);
|
||||||
UIButton.AppearanceWhenContainedIn(new Type[] { typeof(UISearchBar) }).TintColor = primaryColor;
|
UIButton.AppearanceWhenContainedIn(new Type[] { typeof(UISearchBar) }).TintColor = primaryColor;
|
||||||
UIStepper.Appearance.TintColor = grayLight;
|
UIStepper.Appearance.TintColor = grayLight;
|
||||||
UISlider.Appearance.TintColor = primaryColor;
|
UISlider.Appearance.TintColor = primaryColor;
|
||||||
|
|
||||||
MessagingCenter.Subscribe<Xamarin.Forms.Application, ToolsExtensionPage>(Xamarin.Forms.Application.Current, "ShowAppExtension", (sender, page) =>
|
MessagingCenter.Subscribe<Xamarin.Forms.Application, ToolsExtensionPage>(
|
||||||
|
Xamarin.Forms.Application.Current, "ShowAppExtension", (sender, page) =>
|
||||||
{
|
{
|
||||||
var itemProvider = new NSItemProvider(new NSDictionary(), iOS.Core.Constants.UTTypeAppExtensionSetup);
|
var itemProvider = new NSItemProvider(new NSDictionary(), Core.Constants.UTTypeAppExtensionSetup);
|
||||||
var extensionItem = new NSExtensionItem();
|
var extensionItem = new NSExtensionItem();
|
||||||
extensionItem.Attachments = new NSItemProvider[] { itemProvider };
|
extensionItem.Attachments = new NSItemProvider[] { itemProvider };
|
||||||
var activityViewController = new UIActivityViewController(new NSExtensionItem[] { extensionItem }, null);
|
var activityViewController = new UIActivityViewController(new NSExtensionItem[] { extensionItem }, null);
|
||||||
|
@ -112,7 +110,8 @@ namespace Bit.iOS
|
||||||
UIApplication.SharedApplication.StatusBarHidden = false;
|
UIApplication.SharedApplication.StatusBarHidden = false;
|
||||||
UIApplication.SharedApplication.StatusBarStyle = UIStatusBarStyle.LightContent;
|
UIApplication.SharedApplication.StatusBarStyle = UIStatusBarStyle.LightContent;
|
||||||
|
|
||||||
MessagingCenter.Subscribe<Xamarin.Forms.Application, bool>(Xamarin.Forms.Application.Current, "ShowStatusBar", (sender, show) =>
|
MessagingCenter.Subscribe<Xamarin.Forms.Application, bool>(Xamarin.Forms.Application.Current,
|
||||||
|
"ShowStatusBar", (sender, show) =>
|
||||||
{
|
{
|
||||||
UIApplication.SharedApplication.SetStatusBarHidden(!show, false);
|
UIApplication.SharedApplication.SetStatusBarHidden(!show, false);
|
||||||
});
|
});
|
||||||
|
@ -196,7 +195,8 @@ namespace Bit.iOS
|
||||||
Debug.WriteLine("WillEnterForeground");
|
Debug.WriteLine("WillEnterForeground");
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool OpenUrl(UIApplication application, NSUrl url, string sourceApplication, NSObject annotation)
|
public override bool OpenUrl(UIApplication application, NSUrl url, string sourceApplication,
|
||||||
|
NSObject annotation)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -217,12 +217,14 @@ namespace Bit.iOS
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void DidRegisterUserNotificationSettings(UIApplication application, UIUserNotificationSettings notificationSettings)
|
public override void DidRegisterUserNotificationSettings(UIApplication application,
|
||||||
|
UIUserNotificationSettings notificationSettings)
|
||||||
{
|
{
|
||||||
application.RegisterForRemoteNotifications();
|
application.RegisterForRemoteNotifications();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void DidReceiveRemoteNotification(UIApplication application, NSDictionary userInfo, Action<UIBackgroundFetchResult> completionHandler)
|
public override void DidReceiveRemoteNotification(UIApplication application, NSDictionary userInfo,
|
||||||
|
Action<UIBackgroundFetchResult> completionHandler)
|
||||||
{
|
{
|
||||||
if(CrossPushNotification.Current is IPushNotificationHandler)
|
if(CrossPushNotification.Current is IPushNotificationHandler)
|
||||||
{
|
{
|
||||||
|
|
152
src/iOS/Services/PushNotificationImplementation.cs
Normal file
152
src/iOS/Services/PushNotificationImplementation.cs
Normal file
|
@ -0,0 +1,152 @@
|
||||||
|
using Bit.App.Abstractions;
|
||||||
|
using Bit.App.Utilities;
|
||||||
|
using Foundation;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Threading;
|
||||||
|
using UIKit;
|
||||||
|
using Xamarin.Forms;
|
||||||
|
|
||||||
|
namespace Bit.iOS.Services
|
||||||
|
{
|
||||||
|
public class PushNotificationImplementation : IPushNotification, IPushNotificationHandler
|
||||||
|
{
|
||||||
|
public string Token => NSUserDefaults.StandardUserDefaults.StringForKey(PushNotificationKey.Token);
|
||||||
|
|
||||||
|
public void Register()
|
||||||
|
{
|
||||||
|
var userNotificationTypes = UIUserNotificationType.Alert | UIUserNotificationType.Badge |
|
||||||
|
UIUserNotificationType.Sound;
|
||||||
|
var settings = UIUserNotificationSettings.GetSettingsForTypes(userNotificationTypes, null);
|
||||||
|
UIApplication.SharedApplication.RegisterUserNotificationSettings(settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Unregister()
|
||||||
|
{
|
||||||
|
UIApplication.SharedApplication.UnregisterForRemoteNotifications();
|
||||||
|
OnUnregisteredSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string DictionaryToJson(NSDictionary dictionary)
|
||||||
|
{
|
||||||
|
NSError error;
|
||||||
|
var json = NSJsonSerialization.Serialize(dictionary, NSJsonWritingOptions.PrettyPrinted, out error);
|
||||||
|
return json.ToString(NSStringEncoding.UTF8);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnMessageReceived(NSDictionary userInfo)
|
||||||
|
{
|
||||||
|
var parameters = new Dictionary<string, object>();
|
||||||
|
var json = DictionaryToJson(userInfo);
|
||||||
|
var values = JObject.Parse(json);
|
||||||
|
|
||||||
|
var keyAps = new NSString("aps");
|
||||||
|
if(userInfo.ContainsKey(keyAps))
|
||||||
|
{
|
||||||
|
var aps = userInfo.ValueForKey(keyAps) as NSDictionary;
|
||||||
|
if(aps != null)
|
||||||
|
{
|
||||||
|
foreach(var apsKey in aps)
|
||||||
|
{
|
||||||
|
parameters.Add(apsKey.Key.ToString(), apsKey.Value);
|
||||||
|
JToken temp;
|
||||||
|
if(!values.TryGetValue(apsKey.Key.ToString(), out temp))
|
||||||
|
{
|
||||||
|
values.Add(apsKey.Key.ToString(), apsKey.Value.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CrossPushNotification.PushNotificationListener.OnMessage(values, Device.iOS);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnErrorReceived(NSError error)
|
||||||
|
{
|
||||||
|
Debug.WriteLine("{0} - Registration Failed.", PushNotificationKey.DomainName);
|
||||||
|
CrossPushNotification.PushNotificationListener.OnError(error.LocalizedDescription, Device.iOS);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnRegisteredSuccess(NSData token)
|
||||||
|
{
|
||||||
|
Debug.WriteLine("{0} - Succesfully Registered.", PushNotificationKey.DomainName);
|
||||||
|
|
||||||
|
var trimmedDeviceToken = token.Description;
|
||||||
|
if(!string.IsNullOrWhiteSpace(trimmedDeviceToken))
|
||||||
|
{
|
||||||
|
trimmedDeviceToken = trimmedDeviceToken.Trim('<');
|
||||||
|
trimmedDeviceToken = trimmedDeviceToken.Trim('>');
|
||||||
|
trimmedDeviceToken = trimmedDeviceToken.Trim();
|
||||||
|
trimmedDeviceToken = trimmedDeviceToken.Replace(" ", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine("{0} - Token: {1}", PushNotificationKey.DomainName, trimmedDeviceToken);
|
||||||
|
CrossPushNotification.PushNotificationListener.OnRegistered(trimmedDeviceToken, Device.iOS);
|
||||||
|
NSUserDefaults.StandardUserDefaults.SetString(trimmedDeviceToken, PushNotificationKey.Token);
|
||||||
|
NSUserDefaults.StandardUserDefaults.Synchronize();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnUnregisteredSuccess()
|
||||||
|
{
|
||||||
|
CrossPushNotification.PushNotificationListener.OnUnregistered(Device.iOS);
|
||||||
|
NSUserDefaults.StandardUserDefaults.SetString(string.Empty, PushNotificationKey.Token);
|
||||||
|
NSUserDefaults.StandardUserDefaults.Synchronize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IPushNotificationHandler
|
||||||
|
{
|
||||||
|
void OnMessageReceived(NSDictionary parameters);
|
||||||
|
void OnErrorReceived(NSError error);
|
||||||
|
void OnRegisteredSuccess(NSData token);
|
||||||
|
void OnUnregisteredSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class CrossPushNotification
|
||||||
|
{
|
||||||
|
private static Lazy<IPushNotification> Implementation = new Lazy<IPushNotification>(
|
||||||
|
() => new PushNotificationImplementation(),
|
||||||
|
LazyThreadSafetyMode.PublicationOnly);
|
||||||
|
public static bool IsInitialized => PushNotificationListener != null;
|
||||||
|
public static IPushNotificationListener PushNotificationListener { get; private set; }
|
||||||
|
|
||||||
|
public static void Initialize<T>(T listener) where T : IPushNotificationListener
|
||||||
|
{
|
||||||
|
if(PushNotificationListener == null)
|
||||||
|
{
|
||||||
|
PushNotificationListener = listener;
|
||||||
|
Debug.WriteLine("PushNotification plugin initialized.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Debug.WriteLine("PushNotification plugin already initialized.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Initialize<T>() where T : IPushNotificationListener, new()
|
||||||
|
{
|
||||||
|
Initialize(new T());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IPushNotification Current
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if(!IsInitialized)
|
||||||
|
{
|
||||||
|
throw new Exception("Not initialized.");
|
||||||
|
}
|
||||||
|
|
||||||
|
var ret = Implementation.Value;
|
||||||
|
if(ret == null)
|
||||||
|
{
|
||||||
|
throw new Exception("Not in PCL");
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -238,6 +238,7 @@
|
||||||
<Compile Include="Services\DeviceActionService.cs" />
|
<Compile Include="Services\DeviceActionService.cs" />
|
||||||
<Compile Include="Main.cs" />
|
<Compile Include="Main.cs" />
|
||||||
<Compile Include="AppDelegate.cs" />
|
<Compile Include="AppDelegate.cs" />
|
||||||
|
<Compile Include="Services\PushNotificationImplementation.cs" />
|
||||||
<Compile Include="Services\ReflectionService.cs" />
|
<Compile Include="Services\ReflectionService.cs" />
|
||||||
<None Include="app.config">
|
<None Include="app.config">
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
|
@ -324,14 +325,6 @@
|
||||||
<Reference Include="Plugin.Settings.Abstractions, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
<Reference Include="Plugin.Settings.Abstractions, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
<HintPath>..\..\packages\Xam.Plugins.Settings.3.0.1\lib\Xamarin.iOS10\Plugin.Settings.Abstractions.dll</HintPath>
|
<HintPath>..\..\packages\Xam.Plugins.Settings.3.0.1\lib\Xamarin.iOS10\Plugin.Settings.Abstractions.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="PushNotification.Plugin, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
|
||||||
<HintPath>..\..\packages\Xam.Plugin.PushNotification.1.2.4\lib\Xamarin.iOS10\PushNotification.Plugin.dll</HintPath>
|
|
||||||
<Private>True</Private>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="PushNotification.Plugin.Abstractions, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
|
||||||
<HintPath>..\..\packages\Xam.Plugin.PushNotification.1.2.4\lib\Xamarin.iOS10\PushNotification.Plugin.Abstractions.dll</HintPath>
|
|
||||||
<Private>True</Private>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="SimpleInjector, Version=4.0.8.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
|
<Reference Include="SimpleInjector, Version=4.0.8.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
|
||||||
<HintPath>..\..\packages\SimpleInjector.4.0.8\lib\netstandard1.3\SimpleInjector.dll</HintPath>
|
<HintPath>..\..\packages\SimpleInjector.4.0.8\lib\netstandard1.3\SimpleInjector.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
|
|
@ -67,7 +67,6 @@
|
||||||
<package id="Validation" version="2.3.7" targetFramework="xamarinios10" />
|
<package id="Validation" version="2.3.7" targetFramework="xamarinios10" />
|
||||||
<package id="WebP.Touch" version="1.0.3" targetFramework="xamarinios10" />
|
<package id="WebP.Touch" version="1.0.3" targetFramework="xamarinios10" />
|
||||||
<package id="Xam.Plugin.Connectivity" version="3.0.2" targetFramework="xamarinios10" />
|
<package id="Xam.Plugin.Connectivity" version="3.0.2" targetFramework="xamarinios10" />
|
||||||
<package id="Xam.Plugin.PushNotification" version="1.2.4" targetFramework="xamarinios10" developmentDependency="true" />
|
|
||||||
<package id="Xam.Plugins.Settings" version="3.0.1" targetFramework="xamarinios10" />
|
<package id="Xam.Plugins.Settings" version="3.0.1" targetFramework="xamarinios10" />
|
||||||
<package id="Xamarin.Build.Download" version="0.4.7" targetFramework="xamarinios10" />
|
<package id="Xamarin.Build.Download" version="0.4.7" targetFramework="xamarinios10" />
|
||||||
<package id="Xamarin.FFImageLoading" version="2.2.9" targetFramework="xamarinios10" />
|
<package id="Xamarin.FFImageLoading" version="2.2.9" targetFramework="xamarinios10" />
|
||||||
|
|
Loading…
Reference in a new issue