Can't start intent service
I am writing code for synch data for every 10 minute whenapp is in forground,background or sleep . I had write weakfulintentservice for it calling it from Alaramreceiver but AppService doesn't get call.
AppService
public class AppService : WakefulIntentService
{
public AppService() : base("AppService")
{
}
protected override void DoWakefulWork(Intent intent)
{
Toast.MakeText(this, "In service", ToastLength.Short).Show();
Log.Info("AppService", "I'm awake! I'm awake!");
}
}
WeakFulIntentService
abstract public class WakefulIntentService : IntentService
{
abstract protected void DoWakefulWork(Intent intent);
public static string NAME = "com.jondouglas.wakeful.WakefulIntentService";
public static string LAST_ALARM = "lastAlarm";
private static volatile PowerManager.WakeLock lockStatic = null;
[MethodImpl(MethodImplOptions.Synchronized)]
private static PowerManager.WakeLock GetLock(Context context)
{
if (lockStatic == null)
{
PowerManager manager = (PowerManager) context.GetSystemService(Context.PowerService);
lockStatic = manager.NewWakeLock(WakeLockFlags.Partial, NAME);
lockStatic.SetReferenceCounted(true);
}
return (lockStatic);
}
public static void SendWakefulWork(Context context, Intent intent)
{
GetLock(context.ApplicationContext); //Possibly use of acquire here
context.StartService(intent);
}
public static void SendWakefulWork(Context context, Type classService)
{
SendWakefulWork(context, new Intent(context, classService));
}
public static void ScheduleAlarms(IAlarmListener alarmListener, Context context)
{
ScheduleAlarms(alarmListener, context, true);
}
public static void ScheduleAlarms(IAlarmListener alarmListener, Context context, bool force)
{
ISharedPreferences preferences = context.GetSharedPreferences(NAME, 0);
long lastAlarm = preferences.GetLong(LAST_ALARM, 0);
if (lastAlarm == 0 || force ||
(DateTime.Now.Millisecond > lastAlarm &&
DateTime.Now.Millisecond - lastAlarm > alarmListener.GetMaxAge()))
{
AlarmManager manager = (AlarmManager) context.GetSystemService(Context.AlarmService);
Intent intent = new Intent(context, typeof(AlarmReceiver));
PendingIntent pendingIntent = PendingIntent.GetBroadcast(context, 0, intent, 0);
alarmListener.ScheduleAlarms(manager, pendingIntent, context);
}
}
public static void CancelAlarms(Context context)
{
AlarmManager manager = (AlarmManager) context.GetSystemService(Context.AlarmService);
Intent intent = new Intent(context, typeof (AlarmReceiver));
PendingIntent pendingIntent = PendingIntent.GetBroadcast(context, 0, intent, 0);
manager.Cancel(pendingIntent);
context.GetSharedPreferences(NAME, 0).Edit().Remove(LAST_ALARM).Commit();
}
public WakefulIntentService(string name) : base(name)
{
SetIntentRedelivery(true);
}
public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
{
PowerManager.WakeLock wakeLock = GetLock(this.ApplicationContext);
if (!lockStatic.IsHeld || (flags & StartCommandFlags.Redelivery) != 0)
{
wakeLock.Acquire();
}
return base.OnStartCommand(intent, flags, startId);
return (StartCommandResult.RedeliverIntent);
}
protected override void OnHandleIntent(Intent intent)
{
try
{
DoWakefulWork(intent);
}
finally
{
PowerManager.WakeLock wakeLock = GetLock(this.ApplicationContext);
if (wakeLock.IsHeld)
{
try
{
wakeLock.Release();
}
catch (Exception ex)
{
Log.Error(Class.SimpleName, "Exception when releasing wakelock", ex);
//Log exception when releasing wakelock
}
}
}
}
public interface IAlarmListener
{
void ScheduleAlarms(AlarmManager manager, PendingIntent pendingIntent, Context context);
void SendWakefulWork(Context context);
long GetMaxAge();
}
CallToAppService
public void SendWakefulWork(Context context)
{
WakefulIntentService.SendWakefulWork(context, typeof(AppService));
}
The call for AppService context.StartService(intent); from weakfulintentservice execute perfectly
but AppService cant start In xamarin.android.
Kindly help me to solve this issue.
The call for AppService context.StartService(intent); from weakfulintentservice execute perfectly but AppService cant start In xamarin.android.
You can refer to Started Services, in your Xamarin.Android code where you want to start your AppService, you can code as simply as this:
StartService (new Intent (this, typeof(AppService)));
If you want to start a service with an intent filter, you can refer to this part.
Also you may refer to the case I answered several days ago: Xamarin Android : Change UI TextView text from Service or Receiver.
Related
I'm trying to send a value to the server when the connection doesn't exist, when it connects to the internet it runs fine and is saved to the server and sqlite. but the problem arises when switching state from offline to online. I send one value to the server when the connection is offline but when the state moves to online the value I sent earlier becomes multiple on the server while in the sqlite database only one value is stored.
this is my network state checker class
public class NetworkStateCheckerNama extends BroadcastReceiver {
//context and database helper object
private Context context;
private Database db;
ApiRequestData apiRequestData;
#Override
public void onReceive(Context context, Intent intent) {
this.context = context;
apiRequestData = ServiceGenerator.createBaseService(this.context, ApiRequestData.class);
db = new Database(context);
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
//if there is a network
if (activeNetwork != null) {
//if connected to wifi or mobile data plan
if (activeNetwork.getType() == ConnectivityManager.TYPE_WIFI || activeNetwork.getType() == ConnectivityManager.TYPE_MOBILE) {
//getting all the unsynced user
Cursor cursor2 = db.getUnsyncedNama();
if (cursor2.moveToFirst()) {
do {
//calling the method to save the unsynced name to MySQL
Nama(
cursor2.getString(cursor2.getColumnIndexOrThrow(Database.KOLOM_NAMA_COBA)),
cursor2.getString(cursor2.getColumnIndexOrThrow(Database.KOLOM_NIP_COBA))
);
} while (cursor2.moveToNext());
}
}
}
}
private void Nama(final String nama,final String nip) {
//Call call = retrofit.create(APIInterface.class).saveName(name);
Call call = apiRequestData.nama_query(nama,nip);
call.enqueue(new Callback<Responses>() {
#Override
public void onResponse(Call<Responses> call, Response<Responses> response) {
if (response.code() == 200){
db.updateNamaStatus(nip, MainActivity.NAME_SYNCED_WITH_SERVER);
//sending the broadcast to refresh the list
context.sendBroadcast(new Intent(MainActivity.DATA_SAVED_BROADCAST_MAIN));
}
}
#Override
public void onFailure(Call<Responses> call, Throwable t) {
}
});
}
this is my MainActivity Class
public class MainActivity extends AppCompatActivity {
Session session;
Button buttonLogout,buttonKirim;
TextView textViewNamaMain, textViewNipMain;
EditText editTextNamaMain;
Database database;
private AdapterNama mAdapter;
private RecyclerView listviewNama;
ApiRequestData apiRequestData;
//1 means data is synced and 0 means data is not synced
public static final int NAME_SYNCED_WITH_SERVER = 1;
public static final int NAME_NOT_SYNCED_WITH_SERVER = 0;
//a broadcast to know weather the data is synced or not
public static final String DATA_SAVED_BROADCAST_MAIN = "com.example.myapplication.datasave2";
ArrayList<Nama> namaArray;
ArrayList<User> users;
BroadcastReceiver broadcastReceiver;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
session = new Session(this);
buttonLogout = findViewById(R.id.buttonLogout);
buttonKirim = findViewById(R.id.buttonKirim);
textViewNipMain = findViewById(R.id.textViewNipMain);
textViewNamaMain = findViewById(R.id.textViewNamaMain);
editTextNamaMain = findViewById(R.id.editTextTextNamaMain);
String nip = getIntent().getStringExtra("nip");
listviewNama = findViewById(R.id.lv_nama);
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this);
listviewNama.setLayoutManager(layoutManager);
listviewNama.setItemAnimator(new DefaultItemAnimator());
database = new Database(this);
namaArray = new ArrayList<>();
users = new ArrayList<>();
apiRequestData = ServiceGenerator.createBaseService(this, ApiRequestData.class);
textViewNipMain.setText(nip);
registerReceiver(new NetworkStateCheckerNama(), new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
loadDaftarNama(nip);
broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
//loading the names again
loadDaftarNama(nip);
}
};
registerReceiver(broadcastReceiver, new IntentFilter(DATA_SAVED_BROADCAST_MAIN));
if(!session.isUserLogin()){
logout();
}
buttonKirim.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
SimpanKeServer();
}
});
buttonLogout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
logout();
}
});
users.clear();
Cursor cursor = database.getUsersWhereNip(nip);
if (cursor.moveToFirst()) {
do {
User user = new User(
cursor.getString(cursor.getColumnIndexOrThrow(Database.KOLOM_NIP)),
cursor.getString(cursor.getColumnIndexOrThrow(Database.KOLOM_NAMA)),
cursor.getString(cursor.getColumnIndexOrThrow(Database.KOLOM_PASSWORD)),
cursor.getInt(cursor.getColumnIndexOrThrow(Database.KOLOM_STATUS))
);
users.add(user);
textViewNamaMain.setText(user.getNama());
} while (cursor.moveToNext());
}
}
private void SimpanKeServer(){
final ProgressDialog progressDialog = new ProgressDialog(this);
progressDialog.setMessage("Saving Name...");
progressDialog.show();
String nama = editTextNamaMain.getText().toString();
String nip = textViewNipMain.getText().toString();
Call call = apiRequestData.nama_query(nama,nip);
call.enqueue(new Callback<Responses>() {
#Override
public void onResponse(Call<Responses> call, Response<Responses> response) {
progressDialog.dismiss();
if(response.code() == 200){
//if there is a success
//storing the name to sqlite with status synced
SaveNamaToLocal(nama,nip,NAME_SYNCED_WITH_SERVER);
Toast.makeText(MainActivity.this, "Berhasil", Toast.LENGTH_SHORT).show();
}else {
progressDialog.dismiss();
//if there is some error
//saving the name to sqlite with status unsynced
SaveNamaToLocal(nama,nip,NAME_NOT_SYNCED_WITH_SERVER);
Toast.makeText(MainActivity.this, "Gagal", Toast.LENGTH_SHORT).show();
}
}
#Override
public void onFailure(Call<Responses> call, Throwable t) {
progressDialog.dismiss();
SaveNamaToLocal(nama,nip,NAME_NOT_SYNCED_WITH_SERVER);
Toast.makeText(MainActivity.this, "Gagal", Toast.LENGTH_SHORT).show();
}
});
}
private void SaveNamaToLocal(String nama, String nip, int status){
database.Nama(nama,nip,status);
Nama namas = new Nama(nama,nip,status);
namaArray.add(namas);
refreshList();
}
private void loadDaftarNama(String nip) {
namaArray.clear();
Cursor cursor = database.getNama(nip);
if (cursor.moveToFirst()) {
do {
Nama nama = new Nama(
cursor.getString(cursor.getColumnIndexOrThrow(Database.KOLOM_NAMA_COBA)),
cursor.getString(cursor.getColumnIndexOrThrow(Database.KOLOM_NIP_COBA)),
cursor.getInt(cursor.getColumnIndexOrThrow(Database.KOLOM_STATUS_NAMA_COBA))
);
namaArray.add(nama);
} while (cursor.moveToNext());
}
mAdapter = new AdapterNama(this, namaArray);
listviewNama.setAdapter(mAdapter);
}
#SuppressLint("NotifyDataSetChanged")
private void refreshList() {
mAdapter.notifyDataSetChanged();
}
private void logout(){
session.updateUserLoginStatus(false);
finish();
startActivity(new Intent(MainActivity.this,LoginActivity.class));
}
}
this when online
enter image description here
enter image description here
this the problem when state internet switch from offline to online
enter image description here
enter image description here
Even in server send 3 same values
I'm sorry for my english and my question structure im new in programmer, and thank you for the answer
I created a .net 6 app using server side Blazor and SignalR. The app was basically a single page with 10 different components. Each component was a client that looked something like this:
#code {
private HubConnection? hubConnection;
private ExampleViewModel data { get; set; } = new ExampleViewModel();
protected override async Task OnInitializedAsync()
{
hubConnection = new HubConnectionBuilder()
.WithUrl(NavigationManager.ToAbsoluteUri("/mainhub"))
.Build();
hubConnection.On<ExampleViewModel>("example", (Data) =>
{
data = Data;
StateHasChanged();
});
await hubConnection.StartAsync();
}
public async ValueTask DisposeAsync()
{
if (hubConnection is not null)
{
await hubConnection.DisposeAsync();
}
}
}
Each component has a "broadcaster" that runs on a timer and makes a call to the database using Mediator and Dapper. Example:
public class ExampleBroadcaster : IDataBroadcaster
{
private readonly IMediator _mediator;
private readonly ILogger<ExampleBroadcaster> _logger;
private readonly IHubContext<MainHub> _mainHub;
private readonly IMemoryCache _cache;
private const string Something = "example";
private Timer _timer;
public ExampleBroadcaster(IHubContext<MainHub> mainHub,
IMediator mediator, ILogger<ExampleBroadcaster> logger,
IMemoryCache cache)
{
_mainHub = mainHub;
_mediator = mediator;
_logger = logger;
_cache = cache;
}
public void Start()
{
_timer = new Timer(BroadcastData, null, 0, 30000);
}
private async void BroadcastData(object? state)
{
ExampleViewModel viewModel;
try
{
if (_cache.TryGetValue(Something, out ExampleViewModel data))
{
viewModel = data;
}
else
{
viewModel = _mediator.Send(new GetExampleData()).Result;
_cache.Set(Something, viewModel, TimeSpan.FromMinutes(10));
}
await _mainHub.Clients.All.SendAsync("example", viewModel);
}
catch (Exception ex)
{
_logger.LogError(ex, ex.Message);
}
}
}
The mediator handler simply uses Dapper to get data from the database:
public class GetExampleData : IRequest<ExampleViewModel>
{
}
public class GetExampleDataHandler : IRequestHandler<GetExampleData, ExampleViewModel>
{
private readonly IDbConnectionFactory _connectionFactory;
private string _storedProcedure = "some sproc name";
public GetExampleDataHandler(IDbConnectionFactory connectionFactory)
{
_connectionFactory = connectionFactory;
}
public async Task<ExampleViewModel> Handle(GetExampleData request, CancellationToken cancellationToken)
{
using (var connection = _connectionFactory.GetReadOnlyConnection())
{
return await connection.QueryFirstAsync<ExampleViewModel>(_storedProcedure, CommandType.StoredProcedure);
}
}
}
This is the main razor page that houses all the individual components:
#code {
private HubConnection? hubConnection;
protected override async Task OnInitializedAsync()
{
try
{
hubConnection = new HubConnectionBuilder()
.WithUrl(NavigationManager.ToAbsoluteUri("/mainhub"))
.Build();
await hubConnection.StartAsync();
await hubConnection.SendAsync("Init");
}
catch(Exception exception)
{
Logger.LogError(exception, exception.Message);
}
}
public async ValueTask DisposeAsync()
{
if (hubConnection is not null)
{
await hubConnection.DisposeAsync();
}
}
}
Finally, the MainHub.cs code:
public class MainHub : Hub
{
IEnumerable<IDataBroadcaster> _broadcasters;
private static bool _started;
public MainHub(IEnumerable<IDataBroadcaster> broadcasters)
{
_broadcasters = broadcasters;
}
public void Init()
{
if (!_started)
{
StartBroadcasting();
_started = true;
}
}
private void StartBroadcasting()
{
foreach (var broadcaster in _broadcasters)
{
broadcaster.Start();
}
}
}
This all worked fine locally, in our dev environment, and our test environment. In production, we found that the app was crashing after a number of hours. According to the server admins, the app is opening 100s or 1000s of ports and leaving them open until the number of allotted ports was hit, causing the app to crash.
What is the issue here? The broadcasters are registered as singletons. This app only runs on one web server.
I start the foreground service, when my app is going to background. On that time I go to setting page and change the permission status to Deny on Camera. My app get crashed on android 8.0.
My foreground service code like below:
namespace MyProj.Droid.Services
{
[Service]
public class MyProjService : Service
{
CancellationTokenSource _cts;
private static ILogger logger = DependencyService.Get<ILogManager>().GetLog();
public const string LOCATION_CHANNEL = "default";
NotificationManager manager;
NotificationCompat.Builder notification;
public override void OnCreate()
{
base.OnCreate();
manager = (NotificationManager)Forms.Context.GetSystemService("notification");
}
public override IBinder OnBind(Intent intent)
{
return null;
}
public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
{
StartLocationServiceForeground();
return StartCommandResult.Sticky;
}
void StartLocationServiceForeground()
{
try
{
if (Build.VERSION.SdkInt >= BuildVersionCodes.O)
{
var chan1 = new NotificationChannel(LOCATION_CHANNEL,
new Java.Lang.String("Primary"), NotificationImportance.High);
manager.CreateNotificationChannel(chan1);
notification = new NotificationCompat.Builder(Forms.Context, LOCATION_CHANNEL);
notification.SetOngoing(true)
.SetSmallIcon(Resource.Drawable.icon_transparent)
.SetContentTitle("MyProj 24x7 Trucker is running background")
.SetContentText("Tab for more information or to stop the app")
.SetColor(0x9c6114)
.SetPriority(NotificationCompat.PriorityHigh);
StartForeground(1, notification.Build());
}
}
catch(System.Exception ex)
{
}
}
public override void OnDestroy()
{
StopForeground(true);
if (manager!=null)
{
manager.CancelAll();
}
base.OnDestroy();
}
}
}
Can anyone please help to resolve this issue.
I'm using Branch.io in a Xamarin Forms app, and my goal is to send push notifications through Azure Notification Hubs with Branch links in them to open the app and do something. I seem to have it all configured perfectly fine for iOS, but in Android I'm receiving the push notification and the correct activity is coming up, but InitSessionComplete is not called on my IBranchBUOSessionInterface object.
I'm suspecting the issue is in the way I'm creating the PendingIntent, but I could be totally wrong. Again, InitSessionComplete is called in every other circumstance except for when I receive a push notification with a Branch link.
All relevant code is below. Thanks!
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 Sent via Notification:
{"data":{"message":"Click this notification to go to the best feature of the app!", "branch": "https://mycompanymyapp.test-app.link/feature"}}
EDIT (1/7/2019)
I'm able to reproduce this in the Test Bed. I forked my own copy of Branch and added a branch called initsessioncomplete-push-notification-issue, which you can access here. I followed these instructions to setup Firebase and Azure Notification Hubs. In the solution, the only thing you'll have to modify are the two strings in the AppConstants class in the TestBed.Droid project, and add your google-services.json file to the root of the Droid project (the .csproj is already configured properly to read it).
As far as I can tell, I see a successful call being made to the Branch API when I click the push notification, but InitSessionComplete is never called.
Joon from Branch here. Can you double check that you are using the correct Branch Key in your AndroidManifest? I noticed that you are testing with a test Branch Link so you'll have to use your test Branch Key.
i am getting
StartSensor Attempt to invoke virtual method 'void io.realm.ProxyState.setConstructionFinished()' on a null object reference
i try to create a new object with primarykey inside application class.
primarykeyFactory works it set the new key to "1" the database is empty at this moment.
public class SensorRecord extends MainApplication {
private final static String TAG = SensorRecord.class.getSimpleName();
private Realm mRealm;
public SensorRecord() {
Realm.init(this);
mRealm = getInstance(getRealmConfig());
}
public void StartSensor(long startTime) {
long newprimekey = PrimaryKeyFactory.getInstance().nextKey(SensorData.class);
try {
mRealm.beginTransaction();
SensorData mSensorData = mRealm.createObject(SensorData.class, newprimekey);
mSensorData.setstarted_at(startTime);
mRealm.commitTransaction();
mRealm.close();
} catch (Exception e) {
Log.v(TAG, "StartSensor " + e.getMessage());
}
}}
my main application class which init the realm config
public class MainApplication extends RealmBaseApplication {
private final static String TAG = MainApplication.class.getSimpleName();
Realm mRealm;
#Override
public void onCreate() {
super.onCreate();
Realm.init(this);
mRealm = getInstance(getRealmConfig());
initializePrimaryKeyFactory();
}
public void initializePrimaryKeyFactory() {
try {
Log.v(TAG, "Start PrimaryKeyFactory ");
PrimaryKeyFactory.getInstance().initialize(mRealm);
} catch (Exception e) {
Log.v(TAG, "initializePrimaryKeyFactory " + e.getMessage());
}
}}
and my realm config class
public abstract class RealmBaseApplication extends Application {
private RealmConfiguration realmConfiguration;
protected RealmConfiguration getRealmConfig() {
if (realmConfiguration == null) {
realmConfiguration = new RealmConfiguration
.Builder()
.deleteRealmIfMigrationNeeded()
.build();
}
Realm.setDefaultConfiguration(realmConfiguration);
return realmConfiguration;
}
protected void resetRealm() {
Realm.deleteRealm(getRealmConfig());
}}
kind regards
viktoria
ok fixed by myself. had add butterknife tonight. and with that i add apt to my build.gradle... i removed
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
apply plugin: 'com.neenbedankt.android-apt'
and replaced
apt 'com.jakewharton:butterknife-compiler:8.5.1'
with
annotationProcessor 'com.jakewharton:butterknife-compiler:8.5.1'