Xamarin iOS reference in Android project in Xamarin Forms - xamarin.forms

I created a cross platform application using Xamarin. I need to call native functions of iOS and Android platform in my project. Here is the code:
private static Func<IDownloadFile, string> _downloadPath = new Func<IDownloadFile, string>(file =>
{
if (Device.RuntimePlatform == Device.iOS)
{
string fileName = (new NSUrl(file.Url, false)).LastPathComponent;
return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), fileName);
}
else if (Device.RuntimePlatform == Device.Android)
{
string fileName = Android.Net.Uri.Parse(file.Url).Path.Split('/').Last();
return Path.Combine(Android.App.Application.Context.GetExternalFilesDir(Android.OS.Environment.DirectoryDownloads).AbsolutePath, fileName);
}
return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "");
});
This is the code from notification plugin https://github.com/thudugala/Plugin.LocalNotification.
The problem is when I use that code the Mono.Android and Xamarin.iOS references are being added to my shared project in Dependencies/Assemblies and then when I try to run application in the release mode there is a reference error - I noticed that in my Android project in bin/Release there is Xamarin.iOS reference but there is no reference in Android project. When I remove that reference from Dependencies/Assemblies and comment native calls in my code everything compiles correctly. I am confused because of this. Is my above code correctly or I need to call native functions in another way?

When using .net Standard the approach taken is using an interface that defines the functionality you want to expose then implement in each platform.
In Shared:
public interface IMyInterface
{
string GetUrlPath(string fileUrl);
}
iOS Implementation:
public class MyClass : IMyInterface
{
public string GetUrlPath(string fileUrl)
{
string fileName = (new NSUrl(file.Url, false)).LastPathComponent;
return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), fileName);
}
}
Android Implementation:
public class MyClass : IMyInterface
{
public string GetUrlPath(string fileUrl)
{
string fileName = (new NSUrl(file.Url, false)).LastPathComponent;
return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), fileName);
}
}
Then using either Xamarin.Forms DependencyService or any other IoC container you can match the Interface with the correct implementation.
In your shared code you will use the Interface and the implementation picked will be transparent.
This post shows a very complete example of how to do it.

Related

How to do Login with Firebase integration in .NET MAUI?

I'm trying to login with integration to social networks, more specifically to Google in .NET MAUI. I've done it with Xamarin Forms and it worked perfectly, however, in MAUI a standard error is occurring:
Error CS0246 The type or namespace name 'Android' could not be found (are you missing a using directive or an assembly reference?) LoginWithRedes (net6.0-ios), LoginWithRedes (net6.0-maccatalyst), LoginWithRedes (net6.0-windows10.0.19041) C:\MAUI\LoginWithRedes\LoginWithRedes\Platforms\Android\GoogleManager.cs
Libraries not being recognized
Packages I added to the project
Code of the GoogleManager.CS Class where the standard error occurs to me:
`[assembly: Dependency(typeof(GoogleManager))]
namespace LoginWithRedes.Platforms.Android
{
public class GoogleManager : Java.Lang.Object, IGoogleManager, GoogleApiClient.IConnectionCallbacks, GoogleApiClient.IOnConnectionFailedListener
{
public static GoogleApiClient _googleApiClient { get; set; }
public static GoogleManager Instance { get; private set; }
public bool IsLogedIn { get; set; }
Context _context;
public GoogleManager()
{
_context = global::Android.App.Application.Context;
Instance = this;
}
public void Login()
{
GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DefaultSignIn)
.RequestEmail()
.Build();
_googleApiClient = new GoogleApiClient.Builder((_context).ApplicationContext)
.AddConnectionCallbacks(this)
.AddOnConnectionFailedListener(this)
.AddApi(Auth.GOOGLE_SIGN_IN_API, gso)
.AddScope(new Scope(Scopes.Profile))
.Build();
Intent signInIntent = Auth.GoogleSignInApi.GetSignInIntent(_googleApiClient);
((MainActivity)Forms.Context).StartActivityForResult(signInIntent, 1);
_googleApiClient.Connect();
}
public void Logout()
{
var gsoBuilder = new GoogleSignInOptions.Builder(GoogleSignInOptions.DefaultSignIn).RequestEmail();
GoogleSignIn.GetClient(_context, gsoBuilder.Build())?.SignOut();
_googleApiClient.Disconnect();
}
public void OnAuthCompleted(GoogleSignInResult result)
{
if (result.IsSuccess)
{
IsLogedIn = true;
Application.Current.MainPage = new MainPage();
}
else
{
}
}`
OnActivityResult method that I implemented in MainActivity class
If anyone can help me with this error, I would be very grateful.
Note: I'm new to Xamarin and Maui.
Thank you very much in advance
I'm also new to Maui, and in my experience, these errors were caused by using native Xamarin libraries in Maui. Xamarin targets each platform separately using separate nuget packages. Maui's combined 1-project architecture means you need to use packages that work for both at once.
At least when I was getting started a few months ago, these weren't readily available. Firebase client was not yet released for .NET 6.0 (Multiplatform by default).
Things may have changed since then. But I had great success using Firebase with this plugin https://github.com/TobiasBuchholz/Plugin.Firebase. It wraps up the platform specific libraries into a single project API, with a really easy to use c# interface. You can use await and stuff as you would expect. Calling the native APIs was difficult, and required a lot of code duplication. This plugin saves a lot of time, and I haven't yet run into any problems.
The documentation on the plugin is a bit sparse, but hey, it's free and works.

How do you get version of Platform in xamarin forms

I have a page where I display all sorts of info and I would like to display either the android Sdk used or the iOS version used
How can I retrieve those in xamarin forms? Looked at xamarin essentials but cannot find it.
Result wanted
Android Sdk
29 (10)
ioS
14
Hope makes sense
thanks
You can get via Dependency Service. Create Interface in shared project and then implement this interface in platform specific projects.
Shared Project
public interface IDeviceInfo
{
string GetOSVersion();
}
iOS Project
[assembly: Dependency(typeof(DeviceInfo_iOS))]
namespace App1.iOS
{
public class DeviceInfo_iOS : IDeviceInfo
{
public string GetOSVersion()
{
return UIDevice.CurrentDevice.SystemVersion;
}
}
}
Android Project
[assembly: Dependency(typeof(DeviceInfo_Android))]
namespace App1.Droid
{
public class DeviceInfo_Android : IDeviceInfo
{
public string GetOSVersion()
{
return "Android Sdk " + (int)Build.VERSION.SdkInt +" (" + Build.VERSION.Release +")";
}
}
}
Call the DependencyService in Shared Project
var version = DependencyService.Get<IDeviceInfo>().GetOSVersion();

implement android beam in xamarin forms

I'm develop cross-platform mobile application that use NFC. I already check the xamarin android beam here. Now i'm trying implement the same sample using xamarin forms so i'm using dependency service to call the function from android project. I try to make simple message that pass from device to another but it didn't work. The problem is the implementation of NfcAdapter.IOnNdefPushCompleteCallback
PhoneBeam.cs
using System;
using System.Text;
using Android.App;
using MyApp.Droid;
using Android.Nfc;
using Xamarin.Forms;
[assembly: Dependency(typeof(PhoneBeam))]
namespace MyApp.Droid
{
public class PhoneBeam : Activity, NfcAdapter.ICreateNdefMessageCallback, NfcAdapter.IOnNdefPushCompleteCallback, iBeam
{
private NfcAdapter nfcAdapter;
public void Beam()
{
nfcAdapter = NfcAdapter.GetDefaultAdapter(MainActivity.Instance);
nfcAdapter.SetNdefPushMessageCallback(this, MainActivity.Instance);
nfcAdapter.SetOnNdefPushCompleteCallback(this, MainActivity.Instance);
}
public NdefMessage CreateNdefMessage(NfcEvent evt)
{
DateTime time = DateTime.Now;
var text = ("Beam me up!\n\n" + "Beam : " +
time.ToString("HH:mm:ss"));
NdefMessage msg = new NdefMessage(
new NdefRecord[]{ CreateMimeRecord (
"application/com.example.android.beam",
Encoding.UTF8.GetBytes (text)) });
return msg;
}
public NdefRecord CreateMimeRecord(String mimeType, byte[] payload)
{
byte[] mimeBytes = Encoding.UTF8.GetBytes(mimeType);
NdefRecord mimeRecord = new NdefRecord(
NdefRecord.TnfMimeMedia, mimeBytes, new byte[0], payload);
return mimeRecord;
}
}
}
It says 'PhoneBeam does not implement interface member NfcAdapter.IOnNdefPushCompleteCallback.OnNdefPushComplete(NfcEvent)'. Am i missing something?
Your class implements IOnNdefPushCompleteCallback, which has a public method OnNdefPushComplete that must be implemented in order to satisfy the Interface.

Keeping screen turned on for certain pages

I am using a portable project so do not have direct access to native code.
I have an interface in my project that allows me to access native objects in the Android/iOS projects. We use this primarily for playing audio.
Android, for example, has things like
Window w = new Window();
w.SetFlags(WindowManagerFlags.Fullscreen, WindowManagerFlags.KeepScreenOn);
However the main issue would be accessing a Window object. I could pass a Xamarin.Forms.Page object to the native code, but there would be no way (I don't think) to cast it to a native Android Window object to access the flags.
Is there a way to do this with a portable project?
You can't do this without platform specific services or renderers. A portable project will have to call platform specific code in order to achieve this.
From that platform specific code, either as a DependencyService or Renderer, you can access the Window object through the Forms.Context. The Forms.Context is your Android Activity, through which you can reach the Window object.
On Android it works like this:
Android.Views.Window window = (Forms.Context as Activity).Window;
window.SetFlags(WindowManagerFlags.KeepScreenOn);
On iOS you can try this (Apple docs):
UIApplication.SharedApplication.IdleTimerDisabled = true;
Now there is a plugin doing exactly what Tim wrote
https://learn.microsoft.com/en-us/xamarin/essentials/screen-lock
simple source code is here
https://github.com/xamarin/Essentials/blob/main/Samples/Samples/ViewModel/KeepScreenOnViewModel.cs
using System.Windows.Input;
using Xamarin.Essentials;
using Xamarin.Forms;
namespace Samples.ViewModel
{
public class KeepScreenOnViewModel : BaseViewModel
{
public KeepScreenOnViewModel()
{
RequestActiveCommand = new Command(OnRequestActive);
RequestReleaseCommand = new Command(OnRequestRelease);
}
public bool IsActive => DeviceDisplay.KeepScreenOn;
public ICommand RequestActiveCommand { get; }
public ICommand RequestReleaseCommand { get; }
void OnRequestActive()
{
DeviceDisplay.KeepScreenOn = true;
OnPropertyChanged(nameof(IsActive));
}
void OnRequestRelease()
{
DeviceDisplay.KeepScreenOn = false;
OnPropertyChanged(nameof(IsActive));
}
}
}
For Xamarin Forms Android.
Renders file I included below code
Window window = (Forms.Context as Activity).Window;
window.AddFlags(WindowManagerFlags.KeepScreenOn);

Can't find a working example of SQLite.Net-PCL in Xamarin Forms

I can't seem to get off dead center with SQLite.Net-PCL; I have a Xamarin forms solution with a PCL proj, Droid proj, iOS proj, and Windows Universal project. I have installed the nuget packages for SQLite.Net-PCL and SQLite.Net.Core-PCL.
So, I go over to the github project to find some awesome examples to get started and none of them work; apparently you have to pass a platform into the database connection, but I get a reference error on them all (such as SQLitePlatformWin32).
Search the web for the references and... nothing. Search nuget for the platforms and... nothing.
What am I missing? (yes, I feel dumb)
An example they have is
public class Database : SQLiteConnection
{
public Database(string path) : base(new SQLitePlatformWin32(), path)
{
CreateTable<Stock>();
CreateTable<Valuation>();
}}
and I get a reference error that I can't resolve on the "new SQLitePlatformWin32" line.
For anyone else struggling, here is what you need to do.
Install the SQLite.Net-PCL, SQLite.Net.Core-PCL and SQLite.Net.Async-PCL nugets
Create an interface for ISQLite in your PCL:
public interface ISQLite
{
SQLiteConnection GetConnection();
}
Call GetConnection via DependencyService
PatientDatabase = DependencyService.Get<ISQLite>().GetConnection();
PatientDatabase.CreateTable<Patient>();
The above will create the connection based on your platform (i.e. android, ios). In each platform's project, you must have a GetConnection that is accessable via DependencyService such as this for Android
[assembly: Xamarin.Forms.Dependency(typeof(SQLite_Android))]
// ...
public class SQLite_Android : ISQLite
{
public SQLite_Android() { }
public SQLite.Net.SQLiteConnection GetConnection()
{
var sqliteFilename = "TodoSQLite.db3";
string documentsPath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal); // Documents folder
var path = Path.Combine(documentsPath, sqliteFilename);
// Create the connection
var conn = new SQLite.Net.SQLiteConnection(new SQLite.Net.Platform.XamarinAndroid.SQLitePlatformAndroid(), path);
// Return the database connection
return conn;
}
}
My problem was I was trying to create the connection in my PCL and I couldn't find the platforms, what you need to do is create the connection in each individual project.

Resources