How to use camera QR Code Reader on MAUI Blazor Hybrid - qr-code

Has anyone found a working solution on scanning QR Codes from a Blazor MAUI Hybrid App?
I have found number of libraries (e.g. BigIslandBarcoding, ZXing.Net) for "normal" Blazor but nothing speicifc to do this on a mobile device (iOS and Android) from razor page (in BlazorWebView).
I'm looking for a simple action to open the camera reader/scanner on button click but can't find anything like that.

I played with this today because I am porting my Blazor server app to MAUI Blazor and had a same problem.
Edit:
You dont need this part bellow
I managed to fix it by using this project
https://github.com/MackinnonBuck/MauiBlazorPermissionsExample
To get device specific permissions and then I installed
Edit: This library has a problem when you try to publish as Release
https://github.com/Redth/ZXing.Net.Mobile
so use this one instead
https://github.com/g0dpain/ZXing.Net.Mobile
It is made for Xamarin but it works in MAUI just fine. What you need to do is add this code in Android project MainActivity.cs file
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Permission[] grantResults)
{
Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);
base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
Xamarin.Essentials.Platform.Init(Application);
ZXing.Mobile.MobileBarcodeScanner.Initialize(Application);
}
And in your Razor page you can call it like this
async Task ScanBarcode()
{
var scanner = new ZXing.Mobile.MobileBarcodeScanner();
var result = await scanner.Scan();
barcode = result.Text;
}
I tried it in Android emulator and on real device and it works great.

Related

Xamarin.Forms for iOS using SceneDelegate.cs

In iOS 13, UIScene is used. Codes in AppDelegate.cs must be moved into SceneDelegate.cs to support multiple windows of the same app in Split View.
For Xamarin.Forms, AppDelegate.cs uses LoadApplication (new App()) to launch an instance of App.cs in the Xamarin.Forms. LoadApplication is found in Xamarin.Forms.Platform.iOS.FormsApplicationDelegate.
What is the equivalent in SceneDelegate.cs to launch an instance of App.cs in the Xamarin.Forms?
From the app lifecycle of xamrin forms :
iOS – Main method > AppDelegate > App > ContentPage .
Android – MainActivity > App > ContentPage
We will see that Main method invoke App class before , if need a instance of App from iOS , generally will try as follow :
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
global::Xamarin.Forms.Forms.Init();
LoadApplication(new App(app)); // pass app to Forms
return base.FinishedLaunching(app, options);
}
However ,Forms can not using UIKit (error screenshot).
In xamarin forms , there is DependencyService to load navtive method . Therefore, suggest that using DependecyService to call app from iOS native AppDelegate.cs .
About using SceneDelegate.cs in Xamarin Forms , there is no SceneDelegate.cs file in iOS solution now . I will check that whether be possible in Xamarin Forms .
==================================Update==============================
If want to deal with a universal link in AppDelegate.cs , you need to do something in continueUserActivity method as follow :
public override bool ContinueUserActivity(UIApplication application, NSUserActivity userActivity, UIApplicationRestorationHandler completionHandler)
{
//return base.ContinueUserActivity(application, userActivity, completionHandler);
if(userActivity.ActivityType == NSUserActivityType.BrowsingWeb)
{
NSUrl url = userActivity.WebPageUrl;
// other code
}
return true;
}
==================================Update===============================
Finally , found that it is possible to add SceneDelegate to a Xamarin Forms project. A new Xamarin Forms project does not come with the necessary SceneDelegate.cs or .storyboard files, so these need to be added. After adding these files, the info.plist needs to be updated with the UIApplicationSceneManifest key, which will contain more needed keys.
The additions to info.plist are shown here: https://learn.microsoft.com/en-us/xamarin/ios/platform/ios13/multi-window-ipad#project-configuration (just UIApplicationSceneManifest and everything under)
The two things to note are that:
The sample has issues with navigation working properly when having multiple windows of the app running.
This is not an official sample, as Xamarin.Forms does not currently offer official support for using mutiple Scenes with an iOS application.
The unofficial Xamarin.Forms sample is here:https://www.dropbox.com/s/sdxq5me7vcdmuf9/XamFormsiOSMultiWindow.rar?dl=0
It seems this issue has been resolved in MAUI. Just inherit from MauiUISceneDelegate for your SceneDelegate class and the framework will take car of the rest:
[Register("SceneDelegate")]
public class SceneDelegate : MauiUISceneDelegate
{
}
And then in your info.plist file:
<key>UIApplicationSceneManifest</key>
<dict>
<key>UIApplicationSupportsMultipleScenes</key>
<true/>
<key>UISceneConfigurations</key>
<dict>
<key>UIWindowSceneSessionRoleApplication</key>
<array>
<dict>
<key>UISceneConfigurationName</key>
<string>__MAUI_DEFAULT_SCENE_CONFIGURATION__</string>
<key>UISceneDelegateClassName</key>
<string>SceneDelegate</string>
</dict>
</array>
</dict>
</dict>
I wish there was an equally clean solution for Xamarin.Forms as we have not migrated our app to MAUI yet.
Hope this helps!
*Update:
Junior Jiang's solution did work for me, but I had to make a few changes to get it to work:
Uncomment the following lines in SceneDelegate.cs:
//var ad = new AppDelegate();
//ad.GetUI();
...
//Window.RootViewController = ad.Window.RootViewController;
Then add the following line after the uncommented code in SceneDelegate.cs
Window.MakeKeyAndVisible();
I made a few additional changes that are not specifically required, but probably a bit better in terms of resource usage, such as rather resolving appDeleggate as follows:
var appDelegate = (AppDelegate)UIApplication.SharedApplication.Delegate;
And instead returning the created Xamarin.Forms app in GetUI method (in AppDelegate) to be used in SceneDelegate, instead of creating another one in SceneDelegate.
One limitation that I did notice is that I could no longer see iOS alert messages, so I used a custom syncfusion popup instead.

Xamarin Forms: Open downloaded file in default Android/iOS application

I am using Xamarin Forms. I would like to download jpg file (it is done) and then open that jpg in default application on Android/iOS (opening photo browser with this photo). Of course photo is single example, I would like to open any file in default application.
I found several solutions native-only but my application is designed to be cross-platform. I though that I can use Launcher from Xamarin.Essentials package but apparently I can't.
How to achieve this?
You can have a try with Xamarin.Essentials: Launcher:
var fn = "File.txt";
var file = Path.Combine(FileSystem.CacheDirectory, fn);
File.WriteAllText(file, "Hello World");
await Launcher.OpenAsync(new OpenFileRequest
{
File = new ReadOnlyFile(file)
});
I found several solutions native-only
Opening something in another app is quite close to the system for a mobile application and there are some things to consider, which dependend on the platform. Usually, mobile apps run in a sandbox with very limited access to the surrounding system. Particularly this means that, if you downloaded a file to the sandbox of your app, other apps (which native viewers are), aren't allowed to access the file.
On Android, you can copy the file to a shared space (see Application.Context.GetExternalFilesDir(null)) and then open it. This might be possible with Essentials, but I'm not quite sure, but since we're on the Android platform anyway now, you could create an intent now anyway.
On iOS you create controllers from within your app (for example the QLPreviewController to preview the file) that may access items in your sandbox. Depending on the type of controller (e.g. UIActivityViewController) they may open other apps.
How to use this platform-independently?
Since you are programming a platform independent app, you'll have to take care that the correct class is called to the platform dependent work. There are several options how you can achieve this
Use the DependencyService
Use a real dependency injection framework
Use an abstract base class with initialization in the platform dependent projects
DependencyService
To use the Xamarin.Forms DependencyService you need two things
An interface for the functionality you'd like to implement
One implementation per platform
Assuming you hvae a simple interface to share a file
public IShareFile
{
void ShareFile(string fileName);
}
you can implement an implementation of this interface on each platform and add the DependencyAttribute to the assembly. e.g. for iOS:
[assembly: Dependency(typeof(MyApp.iOS.DeviceOrientationService))]
namespace MyApp.iOS
{
public class ShareFile : IShareFile
{
public void Share(string fileName)
{
// implementation goes here
}
}
}
The general scaffold is the same for Android, albeit the implementation differs.
Using a real dependency injection framework
Basically it's pretty much the same. You can skip the DependencyAttribute, though. In order to make the implementation available you'll have to get hold of the DI container from your platform specific code, which might be tricky. This might be an overshoot for a single dependency, but if you're using a DI container anyway and there are X dependencies, it might be worth the effort.
Using an abstract base class
Add an abstract base class to your project
public abstract class ShareFile
{
public static ShareFile Instance { get; protected set; }
public abstract void Share(string fileName);
}
and in your implementation in the platform specific project, you add an Init() method
internal class ShareFileImpl : ShareFile
{
public static void Init()
{
ShareFile.Instance = new ShareFileImpl();
}
public void Share(string fileName)
{
// implementation goes here
}
}
This init method must be called from your platform specific code. Most likely during initialization. The implementation can then be accessed via its abstraction from your platform independent code (of course you'll see only the abstraction, public methods added to ShareFileImpl won't be visible from your platform independent code).
ShareFile.Instance.Share(fileName);
A combination of the abstract class approach and dependency injection is also conceivable. When registering your classes in the DI framework, you could register the platform instance like
container.RegisterInstance<ShareFile>(ShareFile.Instance);
This way you can make use of the DI container features (e.g. constructor injection), while keeping the hassles of using the DI container from your platform specific project away from you. The drawback is, that you'll still have to call ShareFileImpl.Init() from your platform specfic code.

How do you test Firebase Dynamic Links in Unity?

Based on the Firebase Unity documentation, you only need to add Firebase Dynamic Links SDK and then listen for incoming links like this in order to capture Dynamic links:
void Start()
{
DynamicLinks.DynamicLinkReceived += OnDynamicLink;
}
// Display the dynamic link received by the application.
void OnDynamicLink(object sender, EventArgs args)
{
var dynamicLinkEventArgs = args as ReceivedDynamicLinkEventArgs;
Debug.LogFormat("Received dynamic link {0}", dynamicLinkEventArgs.ReceivedDynamicLink.Url.OriginalString);
}
The dynamic link I have previously generated, correctly redirects me to the Google play store where my app exists. When I click on "open" from the play store, my app opens on the device but dynamic link information is not passed at all.
Do I need to create a new alpha version of my app to test this on Play Store?
Some people in Stackoverflow mentioned about Alpha version, but those people don't have an app released, whereas I do.
Also, is there way to test this in Unity editor?
I still need to write the code to parse it and it's kind of ridiculous to blindly code this.
If you are still testing and don't want to release a version with Dynamic Links to production, you can release your build which has Dynamic Links to a beta release so you can be sure it's working as expected.
Otherwise, releasing to production also will work.
The build you are installing from play store needs to have the Dynamic Links library and also the codes anyway.

Xamarin Forms IEventAggregator in iOS class crash the application

I'm using Xamarin.Forms and Prism 6.3.0
I have a class in the iOS project where I want to use the IEventAggregator. When I'm passing the IEventAggregator as a parameter to the constructor of the class, the application crashes.
A clarification, I'm trying to publish from the iOS class, not to subscribe to an event published by Xamarin.Forms.
How can I use the IEventAggregator inside a class in iOS project of Xamarin.Forms?
I don't know if there is a more elegant solution, but there is one that is working. You'll have to add the dependency to your container manually with the correct injection parameters.
In your platform specific project (iOS in this case, but it holds for Android, too) change the following line
this.LoadApplication(new App());
to
var app = new App();
this.LoadApplication();
Given your App is a PrismApplication you can now access the IUnityContainer and register your type manually
var app = new App();
app.Container.RegisterType(typeof(IServiceService),
typeof(MyServiceService),
string.Empty,
new ContainerControlledLifetimeManager(),
new InjectionConstructor(new ResolvedParameter(typeof(IEventAggregator))));
this.LoadApplication(app);
Now Unity should be able to resolve MyServiceService correctly and your app should not crash anymore. Maybe you have to remove
[assembly: Xamarin.Forms.Dependency(typeof(MyServiceService)]
but I have not tried if it crashed if it's not removed.
The answer to the question is here
In short, in the class in the iOS project add the using statement using Microsoft.Practices.Unity; and in the constractor of the class add
var ea = ((App)Xamarin.Forms.Application.Current).Container.Resolve<IEventAggregator>();
in order to get the EventAggregator.
Then you can use it to publish a message i.e.
ea.GetEvent<SomeEvent>().Publish(somePayload);

Launch watch kit app from within another watch kit app

I know on the phone it is possible to launch an application from within another using something along the lines of...
-(IBAction) openYoutube:(id)sender {
UIApplication *ourApplication = [UIApplication sharedApplication];
NSString *ourPath = #"http://www.youtube.com/watch?v=TFFkK2SmPg4";
NSURL *ourURL = [NSURL URLWithString:ourPath];
[ourApplication openURL:ourURL];
}
This will launch the youtube app
My research hasn't led to anything useful and I doubt there is something out there, but what's the harm in asking to be sure. Is there anyway to accomplish this sort of functionality from the apple watch? Like if the user hits a button, I want my watch kit app to launch the instagram or twitter watch kit app
Fortunately, you can. You can ask the iOS app to do this. Use this method
[WKInterfaceController openParentApplication:#{[results firstObject]:[results firstObject]} reply:^(NSDictionary *replyInfo, NSError *error) {
}];
To call your parent iOS app. Within the iOS app, implement this delegate method to achieve what you want (in your AppDelegate).
(void)application:(UIApplication *)application handleWatchKitExtensionRequest:(NSDictionary *)userInfo reply:(void (^)(NSDictionary *))reply{}

Resources