Navigate from one app to another using Xamarin - c#

I need to Navigate from one app to another in Xamarin.Forms.
Tried this but didn't work
await Xamarin.Essentials.Launcher.OpenAsync("myapp://com.companyname.myapp1");

Suppose the package name of the app you want to open is com.xamarin.secondapp.
Then you need to add IntentFilter and Exported =true to MainActivity.cs of the app you want to open(com.xamarin.secondapp).
Just as follows.
[Activity(Label = "SearchBarDemos", Icon = "#mipmap/icon", Theme = "#style/MainTheme", MainLauncher = true,Exported =true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
[
IntentFilter
(
new[] { Android.Content.Intent.ActionView },
Categories = new[]
{
Android.Content.Intent.CategoryDefault,
Android.Content.Intent.CategoryBrowsable
},
DataSchemes = new[] { "myapp" }
)
]
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
LoadApplication(new App());
}
}
Note: remember to add code DataSchemes = new[] { "myapp" }.
For the current app, you need to add queries tag for the app you want to open in file manifest.xml.
For example:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.companyname.openappapp1">
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="33" />
<application android:label="OpenappApp1.Android" android:theme="#style/MainTheme">
      </application>
      <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
      <queries>
            <package android:name="com.xamarin.secondapp" />
      </queries>
</manifest>
And the code is:
private void Button_Clicked(object sender, EventArgs e)
{
OpenSecondApp();
}
public async void OpenSecondApp()
{
var supportsUri = await Launcher.CanOpenAsync("myapp://");
if (supportsUri)
await Launcher.OpenAsync("myapp://com.xamarin.secondapp");
}

Try this:
public class Test
{
public async Task OpenRideShareAsync()
{
var supportsUri = await Launcher.CanOpenAsync("myapp://");
if (supportsUri)
await Launcher.OpenAsync("myapp://com.companyname.myapp1");
}
}

Related

Play Notification Sound like a Phone Call Ringtone sound

I am building a prototype in Xamarin.Forms that sends a push notification to the same App installed on other devices. I'm using OneSignal libraries.
Everything works perfectly. The push notification is sent by one device and received by the others correctly. Whether the App is in the foreground or in the background.
When the push notification arrives on the other devices, I capture it in HandleNotificationReceived and call my service that plays the Ringtone sound.
When push notification arrives on other devices and the app is in the foreground, everything works perfectly. However, when it arrives on the other devices, and the App is in the background, only Push Notification arrives, but the Ringtone sound does not play.
I read about limitations when trying to run some things in Background and I believe my problem has something to do with it.
can anybody help me?
Here is my code:
APPLICATION
namespace SaferProject
{
public partial class App : Application
{
public App()
{
InitializeComponent();
var page = new NavigationPage(new Views.MainMenu());
MainPage = page;
IPlaySoundService playSoundService;
playSoundService = DependencyService.Get<IPlaySoundService>();
OneSignal.Current.SetLogLevel(LOG_LEVEL.VERBOSE, LOG_LEVEL.NONE);
OneSignal.Current.StartInit("417d7b75-ed42-4ca5-aed3-42612d260235")
.Settings(new Dictionary<string, bool>() {
{ IOSSettings.kOSSettingsKeyAutoPrompt, false },
{ IOSSettings.kOSSettingsKeyInAppLaunchURL, false } })
.InFocusDisplaying(OSInFocusDisplayOption.Notification)
.HandleNotificationOpened((result) =>
{
if (playSoundService.GetServiceStatus())
{
playSoundService.StopSystemSound();
}
Debug.WriteLine("HandleNotificationOpened: {0}", result.notification.payload.body);
})
//################ Here I call the PlaySystemSound service###############
//################ Here I call the PlaySystemSound service###############
//################ Here I call the PlaySystemSound service###############
.HandleNotificationReceived((notification) =>
{
playSoundService.PlaySystemSound();
DeviceDisplay.KeepScreenOn = true;
Debug.WriteLine("HandleNotificationReceived: {0}", notification.payload.body);
})
//########################################################################
//########################################################################
//########################################################################
.HandleInAppMessageClicked((action) =>
{
// Example IAM click handling for IAM elements
Debug.WriteLine("HandledInAppMessageClicked: {0}", action.clickName);
})
.EndInit();
// The promptForPushNotificationsWithUserResponse function will show the iOS push notification prompt. We recommend removing the following code and instead using an In-App Message to prompt for notification permission (See step 7)
OneSignal.Current.RegisterForPushNotifications();
}
protected override void OnStart()
{
IPlaySoundService playSoundService;
playSoundService = DependencyService.Get<IPlaySoundService>();
if (playSoundService.GetServiceStatus())
{
playSoundService.StopSystemSound();
}
//Handle when your app sleeps
Task.Run(async () => { await SaferProjectService.GetInstance().GetOut(UserManager.GetLogUser()); });
}
protected override void OnSleep()
{
//Handle when your app sleeps
Task.Run(async()=> { await SaferProjectService.GetInstance().GetOut(UserManager.GetLogUser()); });
}
protected override void OnResume()
{
//Handle when your app resumes
Task.Run(async () => { await SaferProjectService.GetInstance().GetIn(UserManager.GetLogUser()); });
}
}
}
INTERFACE
namespace SaferProject.Services
{
public interface IPlaySoundService
{
Task PlaySystemSound();
Task StopSystemSound();
void SetServiceStatus(bool isPlaying);
bool GetServiceStatus();
}
}
ANDROID SERVICE
[assembly: Xamarin.Forms.Dependency(typeof(PlaySoundService))]
namespace SaferProject.Droid.Services
{
[Activity(Label = "PlaySoundService", NoHistory = true, Theme = "#style/MyTheme", ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
public class PlaySoundService : IPlaySoundService
{
private static PlaySoundService _instance;
readonly Ringtone _rt;
bool IsPlaying;
public static PlaySoundService GetInstance()
{
if (_instance == null)
{
_instance = new PlaySoundService();
}
return _instance;
}
public PlaySoundService()
{
AudioManager am = (AudioManager)Application.Context.GetSystemService(Context.AudioService);
if (!am.RingerMode.Equals(2))
{
am.RingerMode = RingerMode.Normal;
//am.SetVibrateSetting(VibrateType.Ringer, VibrateSetting.On);
}
Android.Net.Uri uri = RingtoneManager.GetDefaultUri(RingtoneType.Ringtone);
_rt = RingtoneManager.GetRingtone(MainActivity.instance.ApplicationContext, uri);
}
public Task PlaySystemSound()
{
_rt.Play();
Vibration.Vibrate(500);
SetServiceStatus(true);
return Task.CompletedTask;
}
public Task StopSystemSound()
{
Vibration.Cancel();
_rt.Stop();
SetServiceStatus(false);
return Task.CompletedTask;
}
public void SetServiceStatus(bool isPlaying)
{
IsPlaying = isPlaying;
}
public bool GetServiceStatus()
{
return IsPlaying;
}
}
}
MAIN ACTIVITY
namespace SaferProject.Droid
{
[Activity(Label = "SaferProject.Droid", Theme = "#style/MainTheme", MainLauncher = false,
ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation,
ScreenOrientation = ScreenOrientation.Portrait, LaunchMode = LaunchMode.SingleTop)] //This is what controls orientation
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
public static MainActivity instance { set; get; }
protected override void OnCreate(Bundle savedInstanceState)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(savedInstanceState);
instance = this;
// Radio Button configuration
Xamarin.Forms.Forms.SetFlags(new string[] { "RadioButton_Experimental" });
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
LoadApplication(new App());
//CreateNotificationFromIntent(Intent); //Local Notification - CRIADO NA MADRUGADA
//################ Início OneSignal #################
// Remove this method to stop OneSignal Debugging
OneSignal.Current.SetLogLevel(LOG_LEVEL.VERBOSE, LOG_LEVEL.NONE);
OneSignal.Current.StartInit("417d7b75-ed42-4ca5-aed3-42612d260235")
.InFocusDisplaying(OSInFocusDisplayOption.Notification)
.EndInit();
//################# Fim OneSignal ###################
}
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults)
{
Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);
base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
}
ANDROID MANIFEST
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="6" android:versionName="1.2.0" package="br.com.safertechnology.saferproject" android:installLocation="auto">
<uses-sdk android:minSdkVersion="24" android:targetSdkVersion="30" />
<permission android:name="$br.com.safertechnology.saferproject.permission.C2D_MESSAGE" android:protectionLevel="signature" />
<application android:label="Safer" android:icon="#mipmap/ic_launcher" android:fullBackupContent="#xml/auto_backup_rules">
<receiver android:name="com.onesignal.GcmBroadcastReceiver" android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<category android:name="$br.com.safertechnology.saferproject" />
</intent-filter>
</receiver>
</application>
<uses-permission android:name="$com.aolserra.sirene.permission.C2D_MESSAGE" />
<uses-permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.FLASHLIGHT" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="com.android.alarm.permission.SET_ALARM" />
</manifest>
IOS SERVICE
[assembly: Xamarin.Forms.Dependency(typeof(PlaySoundService))]
namespace SaferProject.iOS.Services
{
public class PlaySoundService : IPlaySoundService
{
private static PlaySoundService _instance;
readonly SystemSound Sound;
bool IsPlaying;
public static PlaySoundService GetInstance()
{
if (_instance == null)
{
_instance = new PlaySoundService();
}
return _instance;
}
public PlaySoundService()
{
AVAudioSession audioSession = AVAudioSession.SharedInstance();
NSError error;
audioSession.OverrideOutputAudioPort(AVAudioSessionPortOverride.Speaker, out error);
Sound = new SystemSound(1151); //1304 (Alarm)
}
public Task PlaySystemSound()
{
Sound.PlaySystemSound();
Vibration.Vibrate(500);
SetServiceStatus(true);
return Task.CompletedTask;
}
public Task StopSystemSound()
{
Sound.Close();
Vibration.Cancel();
SetServiceStatus(false);
return Task.CompletedTask;
}
public void SetServiceStatus(bool isPlaying)
{
IsPlaying = isPlaying;
}
public bool GetServiceStatus()
{
return IsPlaying;
}
}
}
APPDELEGATE
namespace SaferProject.iOS
{
// The UIApplicationDelegate for the application. This class is responsible for launching the
// User Interface of the application, as well as listening (and optionally responding) to
// application events from iOS.
[Register("AppDelegate")]
public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
{
//
// This method is invoked when the application has loaded and is ready to run. In this
// method you should instantiate the window, load the UI into it and then make the window
// visible.
//
// You have 17 seconds to return from this method, or iOS will terminate your application.
//
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
global::Xamarin.Forms.Forms.Init();
LoadApplication(new App());
//return base.FinishedLaunching(app, options);
base.FinishedLaunching(app, options);
//################ Início OneSignal #################
// Remove this method to stop OneSignal Debugging
OneSignal.Current.SetLogLevel(LOG_LEVEL.VERBOSE, LOG_LEVEL.NONE);
OneSignal.Current.StartInit("417d7b75-ed42-4ca5-aed3-42612d260235")
.Settings(new Dictionary<string, bool>() {
{ IOSSettings.kOSSettingsKeyAutoPrompt, false },
{ IOSSettings.kOSSettingsKeyInAppLaunchURL, false } })
.InFocusDisplaying(OSInFocusDisplayOption.Notification)
.EndInit();
// The promptForPushNotificationsWithUserResponse function will show the iOS push notification prompt. We recommend removing the following code and instead using an In-App Message to prompt for notification permission (See step 7)
OneSignal.Current.RegisterForPushNotifications();
return true;
//################# Fim OneSignal ###################
}
}
}
INFO.PLIST
Info.Plist

How to set Title of Tab with MVVMCross 6.2?

I'm trying to figure out how to properly set the localized string as Tab Title (or dynamically change the Tab Title) with MVVMCross 6.2+ in Xamarin Android.
How should I set the title of the tab in the simple example app?
Thanks in advance for your help.
Here is the simple example app:
MvvmCrossTabs.Core
HomeViewModel.cs
using System.Collections.Generic;
using System.Threading.Tasks;
using MvvmCross.Commands;
using MvvmCross.Logging;
using MvvmCross.Navigation;
using MvvmCross.ViewModels;
namespace MvvmCrossTabs.Core.ViewModels
{
public class HomeViewModel : MvxNavigationViewModel
{
public IMvxAsyncCommand ShowInitialViewModelsCommand { get; private set; }
public HomeViewModel(IMvxLogProvider logProvider, IMvxNavigationService navigationService) : base(logProvider, navigationService)
{
ShowInitialViewModelsCommand = new MvxAsyncCommand(ShowInitialViewModels);
}
private async Task ShowInitialViewModels()
{
await Task.WhenAll(new List<Task>
{
NavigationService.Navigate<Tab1ViewModel>(),
NavigationService.Navigate<Tab2ViewModel>(),
NavigationService.Navigate<Tab3ViewModel>()
});
}
}
}
Tab1ViewModel.cs (Tab2ViewModel.cs, Tab3ViewModel.cs)
using MvvmCross.Logging;
using MvvmCross.Navigation;
using MvvmCross.ViewModels;
namespace MvvmCrossTabs.Core.ViewModels
{
public class Tab1ViewModel : MvxNavigationViewModel
{
public Tab1ViewModel(IMvxLogProvider logProvider, IMvxNavigationService navigationService) : base(logProvider, navigationService)
{
}
}
}
App.cs
using MvvmCross.IoC;
using MvvmCross.ViewModels;
using MvvmCrossTabs.Core.ViewModels;
namespace MvvmCrossTabs.Core
{
public class App : MvxApplication
{
public override void Initialize()
{
CreatableTypes()
.EndingWith("Service")
.AsInterfaces()
.RegisterAsLazySingleton();
RegisterAppStart<HomeViewModel>();
}
}
}
MvvmCrossTabs.Android
MainApplication.cs
using System;
using Android.App;
using Android.Runtime;
using MvvmCross.Droid.Support.V7.AppCompat;
using MvvmCrossTabs.Core;
namespace MvvmCrossTabs.Android
{
[Application]
public class MainApplication : MvxAppCompatApplication<MvxAppCompatSetup<App>, App>
{
public MainApplication() : base() { }
public MainApplication(IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer) { }
}
}
home.axml
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/maincontent"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.AppBarLayout
android:id="#+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_scrollFlags="scroll|enterAlways" />
<android.support.design.widget.TabLayout
android:id="#+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_scrollFlags="enterAlways"
app:tabGravity="fill"
app:tabMaxWidth="0dp" />
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
android:id="#+id/viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior" />
</android.support.design.widget.CoordinatorLayout>
tab1.axml (tab2.axml, tab3.axml)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:local="http://schemas.android.com/apk/res-auto"
android:id="#+id/main_frame"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
</LinearLayout>
styles.xml
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
<!-- Customize your theme here. -->
<item name="colorPrimary">#color/colorPrimary</item>
<item name="colorPrimaryDark">#color/colorPrimaryDark</item>
<item name="colorAccent">#color/colorAccent</item>
</style>
</resources>
HomeView.cs
using Android.App;
using Android.Content.PM;
using Android.OS;
using Android.Support.V7.Widget;
using MvvmCross.Droid.Support.V7.AppCompat;
using MvvmCross.Platforms.Android.Presenters.Attributes;
using MvvmCrossTabs.Core.ViewModels;
namespace MvvmCrossTabs.Android
{
[Activity(Label = "#string/app_name", LaunchMode = LaunchMode.SingleTask, Theme = "#style/AppTheme", MainLauncher = true)]
[MvxActivityPresentation]
public class HomeView : MvxAppCompatActivity<HomeViewModel>
{
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.home);
// Replaces Action Bar with new Toolbar.
var toolbar = FindViewById<Toolbar>(Resource.Id.toolbar);
SetSupportActionBar(toolbar);
ViewModel.ShowInitialViewModelsCommand.Execute();
}
}
}
Tab1View.cs (Tab2View.cs, Tab3View.cs)
using Android.OS;
using Android.Runtime;
using Android.Views;
using MvvmCross.Droid.Support.V4;
using MvvmCross.Platforms.Android.Binding.BindingContext;
using MvvmCross.Platforms.Android.Presenters.Attributes;
using MvvmCrossTabs.Core.ViewModels;
namespace MvvmCrossTabs.Android.Views
{
[MvxTabLayoutPresentation(TabLayoutResourceId = Resource.Id.tabs, ViewPagerResourceId = Resource.Id.viewpager, Title = "Tab 1", ActivityHostViewModelType = typeof(HomeViewModel))]
[Register(nameof(Tab1View))]
public class Tab1View : MvxFragment<Tab1ViewModel>
{
public override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Create your fragment here
}
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
base.OnCreateView(inflater, container, savedInstanceState);
return this.BindingInflate(Resource.Layout.tab1, null);
}
}
}
When your tabs are created using the ShowInitialViewModelsCommand, the built-in presenter creates a list of MvxViewPagerFragmentInfo objects, passing in the Title value from the attributes. You can see that happening in the ShowViewPagerFragment method in the MvvmCross source code.
The list of MvxViewPagerFragmentInfo objects is then passed into the MvxCachingFragmentStatePagerAdapter that is created for the ViewPager. You can see that happening here
MvxCachingFragmentStatePagerAdapter inherits from the MvxFragmentPagerAdapter class. Inside the MvxFragmentPagerAdapter class is finally where the Title you provided is actually used. You can see it being used in the GetPageTitleFormatted method here
So in order to change the Title at runtime, you could do the following:
Subclass the default presenter and override the ShowViewPagerFragment method (it is marked virtual) and provide the correct localized title string instead of the one defined in the attribute
Here is an example of how to accomplish this:
1.) Create a custom presenter and override ShowViewPagerFragment
public class LocalizedTabPresenter : MvxAppCompatViewPresenter
{
public LocalizedTabPresenter(IEnumerable<Assembly> androidViewAssemblies) : base(androidViewAssemblies)
{
}
protected override Task<bool> ShowViewPagerFragment(Type view, MvxViewPagerFragmentPresentationAttribute attribute, MvxViewModelRequest request)
{
if (attribute.ViewModelType == typeof(Tab1ViewModel)) {
attribute.Title = "My Localized Title for Tab 1"
}
return base.ShowViewPagerFragment(view, attribute, request);
}
}
2.) In your Setup.cs class, let MvvmCross know to use the custom presenter instead
protected override IMvxAndroidViewPresenter CreateViewPresenter()
{
return new LocalizedTabPresenter(AndroidViewAssemblies);
}
Note:
This will only work if you need to set the title only once when the
app launches and is setting up the tabs for the first time.
If you are in a situation where the Title can change multiple times while the app is running, you need to subclass MvxCachingFragmentStatePagerAdapter and override the GetPageTitleFormatted method and provide a more custom implementation that fits your use case.
Hope that helps.
Another possible solution would be to use the IMvxOverridePresentationAttribute interface.
This way you can change these values at runtime from the fragment itself.
To do it, simply implement IMvxOverridePresentationAttribute in your tab fragment, and then return something like this:
public MvxBasePresentationAttribute PresentationAttribute(MvxViewModelRequest request)
{
return new MvxTabLayoutPresentationAttribute(title: _("Results"), viewPagerResourceId: Resource.Id.viewPager, tabLayoutResourceId: Resource.Id.tab_layout, fragmentHostViewType: typeof(HostFragment));
}
I like this approach because I don't need to change anything at app level and I have all the code related to the fragment contained in that fragment specifically.
I've been using this and it has been working perfectly.
Be aware that this.ViewModel property will be null during PresentationAttribute
If you want a more detailed explanation on how it works, have a look at this
You have to do something like that:
if (fragments == null || fragments.Count == 0)
{
_firstFragment= (YourFragmentType)Activator.CreateInstance(typeof(YourFragmentType));
_firstFragment.ViewModel = YourVM;
_secondFragment= (YourFragmentType)Activator.CreateInstance(typeof(YourFragmentType));
_secondFragment.ViewModel = YourVM;
_thridFragment= (YourFragmentType)Activator.CreateInstance(typeof(YourFragmentType));
_thridFragment.ViewModel = YourVM;
// Strings from RESX Localization
fragments = new Dictionary<string, Fragment>
{
{ Strings.first_localized_string, _firstFragment},
{ Strings.second_localized_string, _secondFragment},
{ Strings.thrid_localized_string, _thridFragment}
};
}
viewPager = View.FindViewById<ViewPager>(Resource.Id.viewpager);
adapter = new TabsFragmentPagerAdapter(ChildFragmentManager, fragments);
viewPager.Adapter = adapter;
var tabLayout = View.FindViewById<TabLayout>(Resource.Id.tabs);
tabLayout.SetupWithViewPager(viewPager);
Your adapter:
public class TabsFragmentPagerAdapter : FragmentPagerAdapter
{
private readonly Fragment[] fragments;
private readonly string[] titles;
public TabsFragmentPagerAdapter(FragmentManager fm, Dictionary<string, Fragment> fragments) : base(fm)
{
this.fragments = fragments.Values.ToArray();
this.titles = fragments.Keys.ToArray();
}
public override int Count => fragments.Length;
private String GetCharSeuenceFromString(string s)
{
return new String(s);
}
public override Object InstantiateItem(ViewGroup container, int position)
{
return base.InstantiateItem(container, position);
}
public override void SetPrimaryItem(ViewGroup container, int position, Object #object)
{
base.SetPrimaryItem(container, position, #object);
}
public override Fragment GetItem(int position)
{
return fragments[position];
}
public override ICharSequence GetPageTitleFormatted(int position)
{
return GetCurrentPageTitle(position);
}
private ICharSequence GetCurrentPageTitle(int position)
{
return GetCharSeuenceFromString(titles[position]);
}
}
Happy codding!
P.S. Don't use fragments with generics.

Missing Component "MainActivity" Xamarin Android

I am trying to complete this tutorial in my application. Since I have a PCL App.cs, I attempted to add that code to my MainActivity.cs. However, when I build the project, it appears that either my MainActivity is missing or my manifest is not correct.
MainActivity.cs
using System;
using Android.App;
using Android.Content;
using Android.Content.PM;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.OS;
using Plugin.Messaging;
using Plugin.Permissions;
using Plugin.Permissions.Abstractions;
using System.Threading.Tasks;
namespace Divco.Droid
{
[Activity(Label = "Divco.Droid", Icon = "#drawable/logo_size_icon", Theme = "#style/MyTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
public event EventHandler<ServiceConnectedEventArgs> LocationServiceConnected = delegate { };
protected static LocationServiceConnection locationServiceConnection;
public static MainActivity Current
{
get { return current; }
}
private static MainActivity current;
public LocationService LocationService
{
get
{
if (locationServiceConnection.Binder == null)
throw new Exception("Service not bound yet");
// note that we use the ServiceConnection to get the Binder, and the Binder to get the Service here
return locationServiceConnection.Binder.Service;
}
}
protected override void OnCreate(Bundle bundle)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(bundle);
global::Xamarin.Forms.Forms.Init(this, bundle);
Xamarin.FormsMaps.Init(this, bundle);
CrossMessaging.Current.Settings().Phone.AutoDial = true;
LoadApplication(new App());
MainActivity.StartLocationService();
}
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
base.OnActivityResult(requestCode, resultCode, data);
}
//public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Permission[] grantResults)
//{
// PermissionsImplementation.Current.OnRequestPermissionsResult(requestCode, permissions, grantResults);
//}
public static void StartLocationService()
{
// create a new service connection so we can get a binder to the service
locationServiceConnection = new LocationServiceConnection(null);
// this event will fire when the Service connectin in the OnServiceConnected call
locationServiceConnection.ServiceConnected += (object sender, ServiceConnectedEventArgs e) => {
Console.WriteLine("Service Connected");
};
// Starting a service like this is blocking, so we want to do it on a background thread
new Task(() => {
// Start our main service
Console.WriteLine("App", "Calling StartService");
Android.App.Application.Context.StartService(new Intent(Android.App.Application.Context, typeof(LocationService)));
// bind our service (Android goes and finds the running service by type, and puts a reference
// on the binder to that service)
// The Intent tells the OS where to find our Service (the Context) and the Type of Service
// we're looking for (LocationService)
Intent locationServiceIntent = new Intent(Android.App.Application.Context, typeof(LocationService));
Console.WriteLine("App", "Calling service binding");
// Finally, we can bind to the Service using our Intent and the ServiceConnection we
// created in a previous step.
Android.App.Application.Context.BindService(locationServiceIntent, locationServiceConnection, Bind.AutoCreate);
}).Start();
}
public static void StopLocationService()
{
// Check for nulls in case StartLocationService task has not yet completed.
Console.WriteLine("App", "StopLocationService");
// Unbind from the LocationService; otherwise, StopSelf (below) will not work:
if (locationServiceConnection != null)
{
Console.WriteLine("App", "Unbinding from LocationService");
Android.App.Application.Context.UnbindService(locationServiceConnection);
}
// Stop the LocationService:
if (Current.LocationService != null)
{
Console.WriteLine("App", "Stopping the LocationService");
Current.LocationService.StopSelf();
}
}
}
}
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="9" android:versionName="0.1" package="com.divcodelivery.divco">
<uses-sdk android:minSdkVersion="15" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.SEND_SMS" />
<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
<uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_SURFACE_FLINGER" />
<application android:label="Divco" android:icon="#drawable/logo_size_icon"></application>
</manifest>
Here are my results when I attempt to build to my phone:
am start -n "com.divcodelivery.divco/md58047ec786dcfdff107cc37976c308625.MainActivity"
Starting: Intent { cmp=com.divcodelivery.divco/md58047ec786dcfdff107cc37976c308625.MainActivity }
Error type 3
Error: Activity class {com.divcodelivery.divco/md58047ec786dcfdff107cc37976c308625.MainActivity} does not exist.
Failed to launch app: Device could not find component named: com.divcodelivery.divco/md58047ec786dcfdff107cc37976c308625.MainActivity

Android - InstanceID.GetToken Throws Java.Lang.IncompatibleClassChangeError

I am currently adding notifications to my Android app. I am using VS2015 and Xamarin. I figured I'd create a side project to test it first. I used the documentation from Xamarin and Firebase.
When my app launches, it tries to create a new token, but I get an error instead:
Java.Lang.IncompatibleClassChangeError: The method 'java.io.File
android.support.v4.content.ContextCompat.getNoBackupFilesDir(android.content.Context)'
was expected to be of type virtual but instead was found to be of type
direct
My code for fetching the token is
MainActivity
namespace ClientApp
{
[Activity(Label = "ClientApp", MainLauncher = true, Icon = "#drawable/icon")]
public class MainActivity : Activity
{
TextView msgText;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.Main);
msgText = FindViewById<TextView>(Resource.Id.msgText);
if (IsPlayServicesAvailable())
{
var intent = new Intent(this, typeof(RegistrationIntentService3));
StartService(intent);
}
}
public bool IsPlayServicesAvailable()
{
int resultCode = GoogleApiAvailability.Instance.IsGooglePlayServicesAvailable(this);
if (resultCode != ConnectionResult.Success)
{
if (GoogleApiAvailability.Instance.IsUserResolvableError(resultCode))
msgText.Text = GoogleApiAvailability.Instance.GetErrorString(resultCode);
else
{
msgText.Text = "Sorry, this device is not supported";
Finish();
}
return false;
}
else
{
msgText.Text = "Google Play Services is available.";
return true;
}
}
}
}
RegistrationIntentService.cs
using System;
using Android.App;
using Android.Content;
using Android.Util;
using Android.Gms.Gcm;
using Android.Gms.Gcm.Iid;
using Android.Support.V4.Content;
namespace ClientApp
{
[Service(Exported = false)]
class RegistrationIntentService : IntentService
{
static object locker = new object();
public RegistrationIntentService() : base("RegistrationIntentService") { }
protected override void OnHandleIntent(Intent intent)
{
try
{
Log.Info("RegistrationIntentService", "Calling InstanceID.GetToken");
lock (locker)
{
var token = InstanceID.GetInstance(this).GetToken("My_Sender_ID", GoogleCloudMessaging.InstanceIdScope, null);
Log.Info("RegistrationIntentService", "GCM Registration Token: " + token);
SendRegistrationToAppServer(token);
Subscribe(token);
}
}
catch (Exception e)
{
Log.Debug("RegistrationIntentService", "Failed to get a registration token");
return;
}
}
void SendRegistrationToAppServer(string token)
{
// Add custom implementation here as needed.
}
void Subscribe(string token)
{
var pubSub = GcmPubSub.GetInstance(this);
pubSub.Subscribe(token, "/topics/global", null);
}
}
}
My Manifest looks like this
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="MY_PACKAGE" android:versionCode="1" android:versionName="1.0" android:installLocation="auto">
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="MY_PACKAGE.permission.C2D_MESSAGE" />
<permission android:name="MY_PACKAGE.permission.C2D_MESSAGE" android:protectionLevel="signature" />
<application android:label="RemoteNotifications" android:icon="#drawable/Icon">
<receiver android:name="com.google.android.gms.gcm.GcmReceiver" android:exported="true" android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="MY_PACKAGE" />
</intent-filter>
</receiver>
</application>
<uses-sdk />
</manifest>
All my packages are up to date and using the latest stable:
Xamarin.GooglePlayServices.Gcm Version 9.0.0.2 with all its dependencies
Xamarin.Android.Support.v4 Version 24.2.1

pushwoosh onMessageReceive xamarin android

ok, hello i am trying to implement pushwoosh notification on my xamarin.android application
i am on a stage were notification sent to client and when i click the notification it should redirect me on a certain activity and ui, here is my code
private void DoOnMessageReceive(String message)
{
var messageJson = new JSONObject(message);
if (messageJson.GetString("title") == "akotube")
{
var intent = new Intent(this, typeof(Second));
//intent.PutExtra(PushManager.PushReceiveEvent, messageJson.ToString());
intent.PutExtra("message", "akotube");
StartActivity(intent);
}
`
but i cant make it work , this is my reference pushwoosh
EDIT
Here is my manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest android:versionCode="1" android:versionName="1.0" package="com.pushwosh.sample" xmlns:android="http://schemas.android.com/apk/res/android">
<uses-sdk android:minSdkVersion="8" android:targetSdkVersion="19"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.VIBRATE"/>
<!--library-->
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<!-- GCM connects to Google Services. -->
<uses-permission android:name="android.permission.INTERNET"/>
<!-- GCM requires a Google account. -->
<uses-permission android:name="android.permission.GET_ACCOUNTS"/>
<!-- Keeps the processor from sleeping when a message is received. -->
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<!--
Creates a custom permission so only this app can receive its messages.
NOTE: the permission *must* be called PACKAGE.permission.C2D_MESSAGE,
where PACKAGE is the application's package name.
-->
<permission android:name="com.pushwosh.sample.permission.C2D_MESSAGE" android:protectionLevel="signature"/>
<uses-permission android:name="com.pushwosh.sample.permission.C2D_MESSAGE"/>
<!-- This app has permission to register and receive data message. -->
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE"/>
<!-- GCM requires Android SDK version 2.2 (API level 8) or above. -->
<!-- The targetSdkVersion is optional, but it's always a good practice
to target higher versions. -->
<application android:icon="#drawable/Icon" android:label="PushWosh">
<meta-data android:name="PW_APPID" android:value="CXXXX-XXXX"/>
<meta-data android:name="PW_PROJECT_ID" android:value="AXXXXXXXXX"/>
<activity android:name="com.arellomobile.android.push.PushWebview"/>
<activity android:name="com.arellomobile.android.push.MessageActivity"/>
<activity android:name="com.arellomobile.android.push.PushHandlerActivity"/>
<receiver android:name="com.google.android.gcm.GCMBroadcastReceiver" android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<!-- Receives the actual messages. -->
<action android:name="com.google.android.c2dm.intent.RECEIVE"/>
<!-- Receives the registration id. -->
<action android:name="com.google.android.c2dm.intent.REGISTRATION"/>
<category android:name="com.pushwosh.sample"/>
</intent-filter>
</receiver>
<service android:name="com.arellomobile.android.push.PushGCMIntentService"/>
</application>
</manifest>
here is my class
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.Main);
var btn = FindViewById<Button>(Resource.Id.MyButton);
btn.Click += btn_Click;
var goSecond = FindViewById<Button>(Resource.Id.btnGo);
goSecond.Click += goSecond_Click;
var unregister = FindViewById<Button>(Resource.Id.Unregister);
unregister.Click += unregister_Click;
_mMessageReceiver = new LocalMessageBroadcastReceiver {Activity = this};
_mRegisterReceiver = new LocalRegisterBroadcastReceiver {Activity = this};
_manager = PushManager.GetInstance(this);
//Register for push!
//_manager.RegisterForPushNotifications();
CheckMessage(Intent);
}
private void RegisterReceivers()
{
var intentFilter = new IntentFilter(PackageName + ".action.PUSH_MESSAGE_RECEIVE");
if (MBroadcastPush)
{
RegisterReceiver(_mMessageReceiver, intentFilter);
}
RegisterReceiver(_mRegisterReceiver, new IntentFilter(PackageName + "." + PushManager.RegisterBroadCastAction));
}
private void UnregisterReceivers()
{
UnregisterReceiver(_mMessageReceiver);
UnregisterReceiver(_mRegisterReceiver);
}
class LocalMessageBroadcastReceiver : BasePushMessageReceiver
{
public MainActivity Activity { private get; set; }
protected override void OnMessageReceive(Intent intent)
{
Activity.DoOnMessageReceive(intent.GetStringExtra(JsonDataKey));
}
}
class LocalRegisterBroadcastReceiver : RegisterBroadcastReceiver
{
public MainActivity Activity { private get; set; }
protected override void OnRegisterActionReceive(Context p0, Intent intent)
{
Activity.CheckMessage(intent);
}
}
private void CheckMessage(Intent intent)
{
if (null != intent)
{
if (intent.HasExtra(PushManager.PushReceiveEvent))
{
DoOnMessageReceive(intent.Extras.GetString(PushManager.PushReceiveEvent));
}
else if (intent.HasExtra(PushManager.RegisterEvent))
{
DoOnRegistered(intent.Extras.GetString(PushManager.RegisterEvent));
}
else if (intent.HasExtra(PushManager.UnregisterEvent))
{
DoOnUnregisteredError(intent.Extras.GetString(PushManager.UnregisterEvent));
}
else if (intent.HasExtra(PushManager.RegisterErrorEvent))
{
DoOnRegisteredError(intent.Extras.GetString(PushManager.RegisterErrorEvent));
}
else if (intent.HasExtra(PushManager.UnregisterErrorEvent))
{
DoOnUnregistered(intent.Extras.GetString(PushManager.UnregisterErrorEvent));
}
ResetIntentValues();
}
}
Your Category in Activity needs to match your Activity's Intent filter
Also
Getting the intent and starting the activity on your DoOnMessageRecieved
Intent intent = new Intent(this, typeof(SecondActivity));
intent.PutExtra(PushManager.PushReceiveEvent, messageJson.ToString());
StartActivity(intent);
Where the SecondActivity is the activity you want to navigate to.

Categories