Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Camera access with Xamarin.Forms

Is anyone able to give a short, self-contained example on how to access the camera with Xamarin.Forms 1.3.x? Simply calling the native camera application and retrieving the resulting picture would be great. Displaying a live view on the Xamarin.Forms page would be awesome!

I already tried to use Xamarin.Mobile and Xamarin.Forms.Labs, but I couldn't get any solution to work on both platforms (focussing on Android and iOS for now). Most code snippets found on the web (including stackoverflow) are incomplete, e.g. not showing the implementation of an IMediaPicker object or where to anchor the method for taking pictures.

like image 753
Falko Avatar asked Jan 29 '15 05:01

Falko


People also ask

How do I use xamarin community toolkit?

Setup Xamarin Community ToolkitOpen an existing project, or create a new project using the Blank Forms App template. In the Solution Explorer panel, right click on your project name and select Manage NuGet Packages. Search for Xamarin. CommunityToolkit, and choose the desired NuGet Package from the list.


2 Answers

I finally created a minimum solution for iOS and Android.

The shared project

First, let's look into the shared code. For an easy interaction between the shared App class and the platform-specific code we store a static Instance within the public static App:

public static App Instance; 

Furthermore, we will display an Image, which will be filled with content later. So we create a member:

readonly Image image = new Image(); 

Within the App constructor we store the Instance and create the page content, which is a simple button and the aforementioned image:

public App() {    Instance = this;     var button = new Button {        Text = "Snap!",        Command = new Command(o => ShouldTakePicture()),    };     MainPage = new ContentPage {        Content = new StackLayout {        VerticalOptions = LayoutOptions.Center,            Children = {                     button,                     image,            },        },    }; } 

The button's click handler calls the event ShouldTakePicture. It is a public member and the platform-specific code parts will assign to it later on.

public event Action ShouldTakePicture = () => {}; 

Finally, we offer a public method for displaying the captured image:

public void ShowImage(string filepath) {     image.Source = ImageSource.FromFile(filepath); } 

The Android project

On Android we modify the MainActivity. First, we define a path for the captured image file:

static readonly File file = new File(Environment.GetExternalStoragePublicDirectory(Environment.DirectoryPictures), "tmp.jpg"); 

At the end of OnCreate we can use the static Instance of the created App and assign an anonymous event handler, which will start a new Intent for capturing an image:

App.Instance.ShouldTakePicture += () => {    var intent = new Intent(MediaStore.ActionImageCapture);    intent.PutExtra(MediaStore.ExtraOutput, Uri.FromFile(file));    StartActivityForResult(intent, 0); }; 

Last but not least, our activity has to react on the resulting image. It will simply push its file path to the shared ShowImage method.

protected override void OnActivityResult(int requestCode, Result resultCode, Intent data) {    base.OnActivityResult(requestCode, resultCode, data);    App.Instance.ShowImage(file.Path); } 

That's about it! Just don't forget to set the "Camera" and the "WriteExternalStorage" permission within "AndroidManifest.xml"!

The iOS project

For the iOS implementation we create a custom renderer. Therefore, we add a new file "CustomContentPageRenderer" and add the corresponding assembly attribute right after the using statements:

[assembly:ExportRenderer(typeof(ContentPage), typeof(CustomContentPageRenderer))] 

The CustomContentPageRenderer inherits from PageRenderer:

public class CustomContentPageRenderer: PageRenderer {     ... } 

We override the ViewDidAppear method and add the following parts.

Create a new image picker controller referring to the camera:

var imagePicker = new UIImagePickerController { SourceType = UIImagePickerControllerSourceType.Camera }; 

Present the image picker controller, as soon as the ShouldTakePicture event is raised:

App.Instance.ShouldTakePicture += () => PresentViewController(imagePicker, true, null); 

After taking the picture, save it to the MyDocuments folder and call the shared ShowImage method:

imagePicker.FinishedPickingMedia += (sender, e) => {             var filepath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "tmp.png"); var image = (UIImage)e.Info.ObjectForKey(new NSString("UIImagePickerControllerOriginalImage"));             InvokeOnMainThread(() => {                 image.AsPNG().Save(filepath, false);                 App.Instance.ShowImage(filepath);             });             DismissViewController(true, null);         }; 

And finally, we need to handle a cancellation of the image taking process:

imagePicker.Canceled += (sender, e) => DismissViewController(true, null); 
like image 108
Falko Avatar answered Sep 21 '22 18:09

Falko


Try out James Montemagno's MediaPlugin.

You can install the plugin using Package Manager Console by simply typing and running Install-Package Xam.Plugin.Media -Version 2.6.2 or else go to Manage NuGet Packages... and type Xam.Plugin.Media and install the plugin. (The plugins has to be installed in all your projects - including the client projects)

A readme.txt will be prompted and follow the instructions there. After that, add the following codes (as required) to your shared project. The instructions to be followed in the above readme.txt file are as follows.

For Android Project

In your BaseActivity or MainActivity (for Xamarin.Forms) add this code:

public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Permission[] grantResults) {     PermissionsImplementation.Current.OnRequestPermissionsResult(requestCode, permissions, grantResults); }   

You must also add a few additional configuration files to adhere to the new strict mode:

  1. Add the following to your AndroidManifest.xml inside the <application> tags:

    <provider android:name="android.support.v4.content.FileProvider"            android:authorities="YOUR_APP_PACKAGE_NAME.fileprovider"            android:exported="false"            android:grantUriPermissions="true">     <meta-data android:name="android.support.FILE_PROVIDER_PATHS"                 android:resource="@xml/file_paths"></meta-data> </provider> 

    YOUR_APP_PACKAGE_NAME must be set to your app package name!

  2. Add a new folder called xml into your Resources folder and add a new XML file called file_paths.xml

    Add the following code:

    <?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android">     <external-path name="my_images" path="Android/data/YOUR_APP_PACKAGE_NAME/files/Pictures" />     <external-path name="my_movies" path="Android/data/YOUR_APP_PACKAGE_NAME/files/Movies" /> </paths> 

    YOUR_APP_PACKAGE_NAME must be set to your app package name!

For iOS Project

Your app is required to have keys in your Info.plist for NSCameraUsageDescription and NSPhotoLibraryUsageDescription in order to access the device's camera and photo/video library. If you are using the Video capabilities of the library then you must also add NSMicrophoneUsageDescription. The string that you provide for each of these keys will be displayed to the user when they are prompted to provide permission to access these device features.

Such as:

<key>NSCameraUsageDescription</key> <string>This app needs access to the camera to take photos.</string> <key>NSPhotoLibraryUsageDescription</key> <string>This app needs access to photos.</string> <key>NSMicrophoneUsageDescription</key> <string>This app needs access to microphone.</string> 

For Shared Project

To simply open camera, save photo and display an alert with the file path, enter the following to the shared project.

if (!CrossMedia.Current.IsCameraAvailable || !CrossMedia.Current.IsTakePhotoSupported) {     await DisplayAlert("No Camera", ":( No camera avaialble.", "OK");     return; }  var file = await CrossMedia.Current.TakePhotoAsync(new Plugin.Media.Abstractions.StoreCameraMediaOptions {     PhotoSize = Plugin.Media.Abstractions.PhotoSize.Medium,     Directory = "Sample",     Name = "test.jpg" });  if (file == null)     return;  await DisplayAlert("File Location", file.Path, "OK");  
like image 29
Curiousity Avatar answered Sep 24 '22 18:09

Curiousity