Я использую Branch.io в приложении Xamarin Forms, и моя цель - отправлять push-уведомления через концентраторы уведомлений Azure с ссылками на них в филиалах, чтобы открыть приложение и что-то сделать. Кажется, у меня все отлично настроено для iOS, но в Android я получаю push-уведомление и появляется правильная активность, но InitSessionComplete не вызывается для моего объекта IBranchBUOSessionInterface.
Я подозреваю, что проблема в том, как я создаю PendingIntent, но могу ошибаться. И снова InitSessionComplete вызывается при любых других обстоятельствах, кроме случаев, когда я получаю push-уведомление со ссылкой на филиал.
Весь соответствующий код приведен ниже. Спасибо!
MainApplication.cs
using System;
using Android.App;
using Android.OS;
using Android.Runtime;
using BranchXamarinSDK;
using Plugin.CurrentActivity;
namespace MyCompany.MyApp.Droid
{
//You can specify additional application information in this attribute
[Application]
[MetaData("io.branch.sdk.auto_link_disable", Value = "false")]
[MetaData("io.branch.sdk.TestMode", Value = "true")]
[MetaData("io.branch.sdk.BranchKey", Value = "@string/branch_key")]
public class MainApplication : Application, Application.IActivityLifecycleCallbacks
{
public MainApplication (IntPtr handle, JniHandleOwnership transer)
: base (handle, transer)
{
}
public override void OnCreate ()
{
base.OnCreate ();
RegisterActivityLifecycleCallbacks (this);
BranchAndroid.GetAutoInstance(ApplicationContext);
}
public override void OnTerminate ()
{
base.OnTerminate ();
UnregisterActivityLifecycleCallbacks (this);
}
public void OnActivityCreated (Activity activity, Bundle savedInstanceState)
{
CrossCurrentActivity.Current.Activity = activity;
}
public void OnActivityDestroyed (Activity activity)
{
}
public void OnActivityPaused (Activity activity)
{
}
public void OnActivityResumed (Activity activity)
{
CrossCurrentActivity.Current.Activity = activity;
}
public void OnActivitySaveInstanceState (Activity activity, Bundle outState)
{
}
public void OnActivityStarted (Activity activity)
{
CrossCurrentActivity.Current.Activity = activity;
}
public void OnActivityStopped (Activity activity)
{
}
}
}
MainActivity.cs
using Android.App;
using Android.Content;
using Android.Content.PM;
using Android.OS;
using Android.Util;
using BranchXamarinSDK;
using MyCompany.Shared.Droid.Modules;
using App = MyCompany.MyApp.Core.App;
namespace MyCompany.MyApp.Droid
{
[Activity (Theme = "@style/Custom.Holo",
Label = "MyApp",
Icon = "@drawable/icon",
ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation,
ScreenOrientation = ScreenOrientation.Portrait,
LaunchMode = LaunchMode.SingleTask,
MainLauncher = true)]
[IntentFilter(new[] { "android.intent.action.VIEW" },
Categories = new[] { "android.intent.category.DEFAULT", "android.intent.category.BROWSABLE" },
DataScheme = "myapp",
DataHost = "open")]
[IntentFilter(new[] { "android.intent.action.VIEW" },
Categories = new[] { "android.intent.category.DEFAULT", "android.intent.category.BROWSABLE" },
DataScheme = "https",
DataHost = "mycompanymyapp.test-app.link")]
public class MainActivity : Xamarin.Forms.Platform.Android.FormsApplicationActivity, IBranchBUOSessionInterface
{
public const string Tag = "MainActivity";
private App _app;
internal static readonly string ChannelId = "MyCompany";
internal static readonly int NotificationId = 100;
protected override void OnCreate (Bundle savedInstanceState)
{
base.OnCreate (savedInstanceState);
if (Intent.Extras != null)
{
foreach (var key in Intent.Extras.KeySet())
{
if (key == null) { continue; }
var value = Intent.Extras.GetString(key);
Log.Debug(Tag, "Key: {0} Value: {1}", key, value);
}
}
// Removes icon from android navbar
ActionBar.SetIcon(Android.Resource.Color.Transparent);
Xamarin.Forms.Forms.Init (this, savedInstanceState);
BranchAndroid.Debug = true;
var androidModule = new MyCompanyAndroidServicesModule ();
var app = new App (androidModule);
BranchAndroid.Init(this, GetString(Resource.String.branch_key), this);
LoadApplication(app);
_app = app;
}
#region IBranchSessionInterface implementation
public void InitSessionComplete(BranchUniversalObject buo, BranchLinkProperties blp)
{
_app.InitSessionComplete(buo, blp);
}
public void SessionRequestError(BranchError error)
{
_app.SessionRequestError(error);
}
#endregion
protected override void OnNewIntent(Intent intent)
{
Intent = intent;
}
}
}
MyCompany.MyApp.Core.cs
#region Libraries
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Threading.Tasks;
using Autofac;
using BranchXamarinSDK;
using MyCompany.Core;
using MyCompany.Core.Factories;
using MyCompany.Core.Helpers;
using MyCompany.Core.Services;
using MyCompany.Core.ViewModels;
using MyCompany.MyApp.Core.ViewModels;
using Xamarin.Forms;
using Device = Xamarin.Forms.Device;
#endregion Libraries
namespace MyCompany.MyApp.Core
{
public class App : Application, ILoginApp, IBranchBUOSessionInterface
{
#region Variables
readonly IViewFactory _viewFactory;
readonly INavigationService _navService;
#endregion Variables
#region Constructor
public App (Module platformServiceModule = null)
{
var bootstrapper = new TimeAppBootstrapper ();
if (platformServiceModule != null)
bootstrapper.AddModule (platformServiceModule);
bootstrapper.Run ();
_viewFactory = bootstrapper.Container.Resolve<IViewFactory> ();
_navService = bootstrapper.Container.Resolve<INavigationService> ();
Page startView = new NavigationPage (_viewFactory.Resolve<LoginV2ViewModel> ()) {
BarBackgroundColor = Color.White,
BarTextColor = Color.FromRgb(34, 149, 236)
};
MainPage = startView;
}
#endregion Constructor
protected override void OnStart ()
{
// Handle when your app starts
}
protected override void OnSleep ()
{
// Handle when your app sleeps
}
/// <summary>
/// Application developers override this method to perform actions
/// when the application resumes from a sleeping state.
/// </summary>
protected override void OnResume ()
{
}
#region IBranchSessionInterface implementation
public void InitSessionComplete(BranchUniversalObject buo, BranchLinkProperties blp)
{
if (blp.feature == "feature")
{
_navService.NavigateTo<FeatureViewModel>();
}
}
public void SessionRequestError(BranchError error)
{
var e = error;
}
#endregion
}
}
FirebaseMessagingService.cs
using Android.App;
using Android.Content;
using Android.Util;
using Firebase.Messaging;
using Xamarin.Essentials;
namespace Crowdkeep.Time.Droid.Services
{
[Service]
[IntentFilter(new[] { "com.google.firebase.MESSAGING_EVENT" })]
public class MyFirebaseMessagingService : FirebaseMessagingService
{
const string TAG = "MyFirebaseMessagingService";
public override void OnMessageReceived(RemoteMessage message)
{
Log.Debug(TAG, "From: " + message.From);
var notificationManager = NotificationManager.FromContext(this);
InitializeChannels(notificationManager);
if (IsProductionNotification(message))
{
SendProductionNotification(message, notificationManager, this);
}
else
{
SendTestNotification(message, notificationManager);
}
}
private static bool IsProductionNotification(RemoteMessage message)
{
return message.GetNotification() != null;
}
private void SendTestNotification(RemoteMessage message, NotificationManager notificationManager)
{
var notification = CreateNotification(message.Data["message"], message.Data["branch"], this);
notificationManager.Notify(0, notification);
}
private static void SendProductionNotification(RemoteMessage message, NotificationManager manager, Context context)
{
Log.Debug(TAG, "Notification Message Body: " + message.GetNotification().Body);
var notification = CreateNotification(message.GetNotification().Body, "https://mycompanymyapp.test-app.link/feature", context);
manager.Notify(0, notification);
}
private static void InitializeChannels(NotificationManager manager)
{
if (DeviceInfo.Version.Major < 8 || manager.GetNotificationChannel(MainActivity.ChannelId) != null)
{
return;
}
var channel = new NotificationChannel(MainActivity.ChannelId, "Crowdkeep", NotificationImportance.Default)
{
Description = "Default Channel"
};
manager.CreateNotificationChannel(channel);
}
private static Notification CreateNotification(string messageBody, string link, Context context)
{
var pendingIntent = SetupNotificationIntent(link, context);
var notificationBuilder = new Notification.Builder(context, MainActivity.ChannelId)
.SetContentTitle("Message")
.SetSmallIcon(Resource.Drawable.icon)
.SetContentText(messageBody)
.SetAutoCancel(true)
.SetContentIntent(pendingIntent)
.SetVisibility(NotificationVisibility.Public);
return notificationBuilder.Build();
}
private static PendingIntent SetupNotificationIntent(string link, Context context)
{
var intent = new Intent(context, typeof(MainActivity));
intent.SetFlags(ActivityFlags.ClearTop);
intent.PutExtra("branch", link);
intent.PutExtra("branch_force_new_session", true);
var pendingIntent = PendingIntent.GetActivity(context, MainActivity.NotificationId, intent, PendingIntentFlags.OneShot);
return pendingIntent;
}
}
}
Json отправлено с помощью уведомления:
{"data":{"message":"Click this notification to go to the best feature of the app!", "branch": "https://mycompanymyapp.test-app.link/feature"}}
РЕДАКТИРОВАТЬ (1/7/2019)
Я могу воспроизвести это на испытательном стенде. Я раздвоил свою собственную копию Branch и добавил ветку с именем initsessioncomplete-push-messages-issue, , доступ к которой можно получить здесь . Я следовал этим инструкциям , чтобы настроить Firebase и Azure Notification Hubs. В этом решении единственное, что вам нужно изменить, - это две строки в классе AppConstants в проекте TestBed.Droid и добавить файл google-services.json в корень проекта Droid (файл .csproj уже настроен правильно, чтобы прочитать его).
Насколько я могу судить, я вижу успешный вызов API-интерфейса Branch, когда нажимаю push-уведомление, но InitSessionComplete никогда не вызывается.