使用 Xamarin.Forms 访问相机
Camera access with Xamarin.Forms
有没有人能给出一个简短的、独立的例子来说明如何使用 Xamarin.Forms 1.3.x 访问相机?只需调用本机相机应用程序并检索生成的图片就可以了。在 Xamarin.Forms 页面上显示实时视图太棒了!
我已经尝试使用 Xamarin.Mobile 和 Xamarin.Forms.Labs,但是我无法找到在两个平台上都可以工作的解决方案(重点是 Android 和 iOS 目前)。在网络上找到的大多数代码片段(包括 Whosebug)都不完整,例如没有显示 IMediaPicker 对象的实现或锚定拍照方法的位置。
我终于为 iOS 和 Android 创建了一个最小解。
共享项目
首先,让我们看一下共享代码。为了共享 App
class 和平台特定代码之间的简单交互,我们在 public static App
:
中存储了一个静态 Instance
public static App Instance;
另外,我们会显示一个Image
,后面会填充内容。所以我们创建一个成员:
readonly Image image = new Image();
在 App
构造函数中,我们存储 Instance
并创建页面内容,这是一个简单的 button
和前面提到的 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,
},
},
};
}
按钮的点击处理程序调用事件 ShouldTakePicture
。
它是一个 public 成员,特定于平台的代码部分稍后将分配给它。
public event Action ShouldTakePicture = () => {};
最后,我们提供一种public方法来显示捕获的图像:
public void ShowImage(string filepath)
{
image.Source = ImageSource.FromFile(filepath);
}
Android 项目
在 Android 我们修改 MainActivity
。
首先,我们为抓取的图片文件定义一个路径:
static readonly File file = new File(Environment.GetExternalStoragePublicDirectory(Environment.DirectoryPictures), "tmp.jpg");
在OnCreate
的末尾我们可以使用创建的App
的静态Instance
并分配一个匿名事件处理程序,它将启动一个新的Intent
捕获图像:
App.Instance.ShouldTakePicture += () => {
var intent = new Intent(MediaStore.ActionImageCapture);
intent.PutExtra(MediaStore.ExtraOutput, Uri.FromFile(file));
StartActivityForResult(intent, 0);
};
最后但同样重要的是,我们的 activity 必须对生成的图像做出反应。它只会将其文件路径推送到共享 ShowImage
方法。
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
base.OnActivityResult(requestCode, resultCode, data);
App.Instance.ShowImage(file.Path);
}
就是这样!
只是不要忘记在 "AndroidManifest.xml"!
中设置 "Camera" 和 "WriteExternalStorage" 权限
iOS 项目
对于 iOS 实现,我们创建了一个自定义渲染器。
因此,我们添加一个新文件"CustomContentPageRenderer",并在using语句后添加相应的程序集属性:
[assembly:ExportRenderer(typeof(ContentPage), typeof(CustomContentPageRenderer))]
CustomContentPageRenderer
继承自PageRenderer
:
public class CustomContentPageRenderer: PageRenderer
{
...
}
我们覆盖ViewDidAppear
方法并添加以下部分。
创建一个引用相机的新图像选择器控制器:
var imagePicker = new UIImagePickerController { SourceType = UIImagePickerControllerSourceType.Camera };
一旦引发 ShouldTakePicture
事件,就显示图像选择器控制器:
App.Instance.ShouldTakePicture += () => PresentViewController(imagePicker, true, null);
拍照后,保存到MyDocuments
文件夹,调用共享ShowImage
方法:
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);
};
最后,我们需要处理图像拍摄过程的取消:
imagePicker.Canceled += (sender, e) => DismissViewController(true, null);
这是在 Xamarin Forms cross Xamarin 上的操作方法 iOS。
这是一个很好的起点,但它需要先呈现一个页面,您可以在其中指定 UIApplication 来为相机/照片选择器控制器提供 UIView。
便携式项目
public interface ICameraProvider
{
Task<CameraResult> TakePhotoAsync();
Task<CameraResult> PickPhotoAsync();
}
private Command AttachImage
{
var camera = await DependencyService.Get<ICameraProvider>().TakePhotoAsync();
}
iOS 项目
[assembly: Xamarin.Forms.Dependency(typeof(CameraProvider))]
public class CameraProvider : ICameraProvider
{
private UIImagePickerController _imagePicker;
private CameraResult _result;
private static TaskCompletionSource<CameraResult> _tcs;
public async Task<CameraResult> TakePhotoAsync()
{
_tcs = new TaskCompletionSource<CameraResult>();
_imagePicker = new UIImagePickerController { SourceType = UIImagePickerControllerSourceType.Camera };
_imagePicker.FinishedPickingMedia += (sender, e) =>
{
_result = new CameraResult();
var filepath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "tmp.png");
var image = (UIImage)e.Info.ObjectForKey(new NSString("UIImagePickerControllerOriginalImage"));
_result.ImageSource = ImageSource.FromStream(() => new MemoryStream(image.AsPNG().ToArray()));
_result.ImageBytes = image.AsPNG().ToArray();
_result.FilePath = filepath;
_tcs.TrySetResult(_result);
_imagePicker.DismissViewController(true, null);
};
_imagePicker.Canceled += (sender, e) =>
{
UIApplication.SharedApplication.KeyWindow.RootViewController.DismissViewController(true, null);
};
await UIApplication.SharedApplication.KeyWindow.RootViewController.PresentViewControllerAsync(_imagePicker, true);
return await _tcs.Task;
}
public async Task<CameraResult> PickPhotoAsync()
{
_tcs = new TaskCompletionSource<CameraResult>();
_imagePicker = new UIImagePickerController
{
SourceType = UIImagePickerControllerSourceType.PhotoLibrary,
MediaTypes = UIImagePickerController.AvailableMediaTypes(UIImagePickerControllerSourceType.PhotoLibrary)
};
_imagePicker.FinishedPickingMedia += (sender, e) =>
{
if (e.Info[UIImagePickerController.MediaType].ToString() == "public.image")
{
var filepath = (e.Info[new NSString("UIImagePickerControllerReferenceUrl")] as NSUrl);
var image = (UIImage)e.Info.ObjectForKey(new NSString("UIImagePickerControllerOriginalImage"));
//var image = e.Info[UIImagePickerController.OriginalImage] as UIImage;
_result.ImageSource = ImageSource.FromStream(() => new MemoryStream(image.AsPNG().ToArray()));
_result.ImageBytes = image.AsPNG().ToArray();
_result.FilePath = filepath?.Path;
}
_tcs.TrySetResult(_result);
_imagePicker.DismissViewController(true, null);
};
_imagePicker.Canceled += (sender, e) =>
{
UIApplication.SharedApplication.KeyWindow.RootViewController.DismissViewController(true, null);
};
await UIApplication.SharedApplication.KeyWindow.RootViewController.PresentViewControllerAsync(_imagePicker, true);
return await _tcs.Task;
}
}
这是我在我的应用程序中获取异步摄像头捕获 运行 所需要的:
在iOS中:
public async Task<string> TakePicture()
{
if (await AuthorizeCameraUse())
{
var imagePicker = new UIImagePickerController { SourceType = UIImagePickerControllerSourceType.Camera };
TaskCompletionSource<string> FinishedCamera = new TaskCompletionSource<string>();
// When user has taken picture
imagePicker.FinishedPickingMedia += (sender, e) => {
// Save the file
var filepath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "tmp.png");
var image = (UIImage)e.Info.ObjectForKey(new NSString("UIImagePickerControllerOriginalImage"));
image.AsPNG().Save(filepath, false);
// Close the window
UIApplication.SharedApplication.KeyWindow.RootViewController.DismissViewController(true, null);
// Stop awaiting
FinishedCamera.SetResult(filepath);
};
// When user clicks cancel
imagePicker.Canceled += (sender, e) =>
{
UIApplication.SharedApplication.KeyWindow.RootViewController.DismissViewController(true, null);
FinishedCamera.TrySetCanceled();
};
// Show the camera-capture window
UIApplication.SharedApplication.KeyWindow.RootViewController.PresentViewController(imagePicker, true, null);
// Now await for the task to complete or be cancelled
try
{
// Return the path we've saved the image in
return await FinishedCamera.Task;
}
catch (TaskCanceledException)
{
// handle if the user clicks cancel
}
}
return null;
}
如果你需要授权例程,请确保你也填写info.plist
中的相机用途,这是获得授权的功能:
public static async Task<bool> AuthorizeCameraUse()
{
var authorizationStatus = AVCaptureDevice.GetAuthorizationStatus(AVMediaType.Video);
if (authorizationStatus != AVAuthorizationStatus.Authorized)
{
return await AVCaptureDevice.RequestAccessForMediaTypeAsync(AVMediaType.Video);
}
else
return true;
}
在Android中:
private TaskCompletionSource<bool> _tcs_NativeCamera;
public async Task<string> TakePicture()
{
_tcs_NativeCamera = new TaskCompletionSource<bool>();
// Launch the camera activity
var intent = new Intent(MediaStore.ActionImageCapture);
intent.PutExtra(MediaStore.ExtraOutput, Android.Net.Uri.FromFile(cameraCaptureFilePath));
NextCaptureType = stype;
StartActivityForResult(intent, SCAN_NATIVE_CAMERA_CAPTURE_ASYNC);
// Wait here for the activity return (through OnActivityResult)
var Result = await _tcs_NativeCamera.Task;
// Return the camera capture file path
return Result != Result.Canceled ? cameraCaptureFilePath : null;
}
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
base.OnActivityResult(requestCode, resultCode, data);
switch (requestCode)
{
case SCAN_NATIVE_CAMERA_CAPTURE_ASYNC:
_tcs_NativeCamera.SetResult(resultCode);
break;
}
}
试试 James Montemagno 的 MediaPlugin。
您可以使用 Package Manager Console by simply typing and running Install-Package Xam.Plugin.Media -Version 2.6.2
or else go to Manage NuGet Packages... 安装插件并键入 Xam.Plugin.Media
并安装插件。 (必须在您的所有项目中安装插件 - 包括客户端项目)
A readme.txt 将出现提示并按照那里的说明进行操作。之后,add the following codes(根据需要)到您的共享项目。上述readme.txt文件中需要遵循的说明如下
对于 Android 项目
在您的 BaseActivity 或 MainActivity(对于 Xamarin.Forms)中添加此代码:
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Permission[] grantResults)
{
PermissionsImplementation.Current.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}
您还必须添加一些额外的配置文件以遵守新的严格模式:
将以下内容添加到 <application> 标签内的 AndroidManifest.xml:
<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必须设置为你的应用包名!
将名为 xml 的新文件夹添加到资源文件夹中,并添加名为 file_paths.xml
的新 XML 文件
添加以下代码:
<?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必须设置为你的应用包名!
对于 iOS 项目
您的应用程序需要在您的 Info.plist 中包含 NSCameraUsageDescription
和 NSPhotoLibraryUsageDescription
的密钥,以便访问设备的相机和 photo/video 库。如果您使用库的视频功能,则还必须添加 NSMicrophoneUsageDescription
。当提示用户提供访问这些设备功能的权限时,您为每个密钥提供的字符串将显示给用户。
如:
<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>
对于共享项目
要简单地打开相机、保存照片并显示带文件路径的警报,请在共享项目中输入以下内容。
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");
有没有人能给出一个简短的、独立的例子来说明如何使用 Xamarin.Forms 1.3.x 访问相机?只需调用本机相机应用程序并检索生成的图片就可以了。在 Xamarin.Forms 页面上显示实时视图太棒了!
我已经尝试使用 Xamarin.Mobile 和 Xamarin.Forms.Labs,但是我无法找到在两个平台上都可以工作的解决方案(重点是 Android 和 iOS 目前)。在网络上找到的大多数代码片段(包括 Whosebug)都不完整,例如没有显示 IMediaPicker 对象的实现或锚定拍照方法的位置。
我终于为 iOS 和 Android 创建了一个最小解。
共享项目
首先,让我们看一下共享代码。为了共享 App
class 和平台特定代码之间的简单交互,我们在 public static App
:
Instance
public static App Instance;
另外,我们会显示一个Image
,后面会填充内容。所以我们创建一个成员:
readonly Image image = new Image();
在 App
构造函数中,我们存储 Instance
并创建页面内容,这是一个简单的 button
和前面提到的 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,
},
},
};
}
按钮的点击处理程序调用事件 ShouldTakePicture
。
它是一个 public 成员,特定于平台的代码部分稍后将分配给它。
public event Action ShouldTakePicture = () => {};
最后,我们提供一种public方法来显示捕获的图像:
public void ShowImage(string filepath)
{
image.Source = ImageSource.FromFile(filepath);
}
Android 项目
在 Android 我们修改 MainActivity
。
首先,我们为抓取的图片文件定义一个路径:
static readonly File file = new File(Environment.GetExternalStoragePublicDirectory(Environment.DirectoryPictures), "tmp.jpg");
在OnCreate
的末尾我们可以使用创建的App
的静态Instance
并分配一个匿名事件处理程序,它将启动一个新的Intent
捕获图像:
App.Instance.ShouldTakePicture += () => {
var intent = new Intent(MediaStore.ActionImageCapture);
intent.PutExtra(MediaStore.ExtraOutput, Uri.FromFile(file));
StartActivityForResult(intent, 0);
};
最后但同样重要的是,我们的 activity 必须对生成的图像做出反应。它只会将其文件路径推送到共享 ShowImage
方法。
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
base.OnActivityResult(requestCode, resultCode, data);
App.Instance.ShowImage(file.Path);
}
就是这样! 只是不要忘记在 "AndroidManifest.xml"!
中设置 "Camera" 和 "WriteExternalStorage" 权限iOS 项目
对于 iOS 实现,我们创建了一个自定义渲染器。 因此,我们添加一个新文件"CustomContentPageRenderer",并在using语句后添加相应的程序集属性:
[assembly:ExportRenderer(typeof(ContentPage), typeof(CustomContentPageRenderer))]
CustomContentPageRenderer
继承自PageRenderer
:
public class CustomContentPageRenderer: PageRenderer
{
...
}
我们覆盖ViewDidAppear
方法并添加以下部分。
创建一个引用相机的新图像选择器控制器:
var imagePicker = new UIImagePickerController { SourceType = UIImagePickerControllerSourceType.Camera };
一旦引发 ShouldTakePicture
事件,就显示图像选择器控制器:
App.Instance.ShouldTakePicture += () => PresentViewController(imagePicker, true, null);
拍照后,保存到MyDocuments
文件夹,调用共享ShowImage
方法:
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);
};
最后,我们需要处理图像拍摄过程的取消:
imagePicker.Canceled += (sender, e) => DismissViewController(true, null);
这是在 Xamarin Forms cross Xamarin 上的操作方法 iOS。
这是一个很好的起点,但它需要先呈现一个页面,您可以在其中指定 UIApplication 来为相机/照片选择器控制器提供 UIView。
便携式项目
public interface ICameraProvider
{
Task<CameraResult> TakePhotoAsync();
Task<CameraResult> PickPhotoAsync();
}
private Command AttachImage
{
var camera = await DependencyService.Get<ICameraProvider>().TakePhotoAsync();
}
iOS 项目
[assembly: Xamarin.Forms.Dependency(typeof(CameraProvider))]
public class CameraProvider : ICameraProvider
{
private UIImagePickerController _imagePicker;
private CameraResult _result;
private static TaskCompletionSource<CameraResult> _tcs;
public async Task<CameraResult> TakePhotoAsync()
{
_tcs = new TaskCompletionSource<CameraResult>();
_imagePicker = new UIImagePickerController { SourceType = UIImagePickerControllerSourceType.Camera };
_imagePicker.FinishedPickingMedia += (sender, e) =>
{
_result = new CameraResult();
var filepath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "tmp.png");
var image = (UIImage)e.Info.ObjectForKey(new NSString("UIImagePickerControllerOriginalImage"));
_result.ImageSource = ImageSource.FromStream(() => new MemoryStream(image.AsPNG().ToArray()));
_result.ImageBytes = image.AsPNG().ToArray();
_result.FilePath = filepath;
_tcs.TrySetResult(_result);
_imagePicker.DismissViewController(true, null);
};
_imagePicker.Canceled += (sender, e) =>
{
UIApplication.SharedApplication.KeyWindow.RootViewController.DismissViewController(true, null);
};
await UIApplication.SharedApplication.KeyWindow.RootViewController.PresentViewControllerAsync(_imagePicker, true);
return await _tcs.Task;
}
public async Task<CameraResult> PickPhotoAsync()
{
_tcs = new TaskCompletionSource<CameraResult>();
_imagePicker = new UIImagePickerController
{
SourceType = UIImagePickerControllerSourceType.PhotoLibrary,
MediaTypes = UIImagePickerController.AvailableMediaTypes(UIImagePickerControllerSourceType.PhotoLibrary)
};
_imagePicker.FinishedPickingMedia += (sender, e) =>
{
if (e.Info[UIImagePickerController.MediaType].ToString() == "public.image")
{
var filepath = (e.Info[new NSString("UIImagePickerControllerReferenceUrl")] as NSUrl);
var image = (UIImage)e.Info.ObjectForKey(new NSString("UIImagePickerControllerOriginalImage"));
//var image = e.Info[UIImagePickerController.OriginalImage] as UIImage;
_result.ImageSource = ImageSource.FromStream(() => new MemoryStream(image.AsPNG().ToArray()));
_result.ImageBytes = image.AsPNG().ToArray();
_result.FilePath = filepath?.Path;
}
_tcs.TrySetResult(_result);
_imagePicker.DismissViewController(true, null);
};
_imagePicker.Canceled += (sender, e) =>
{
UIApplication.SharedApplication.KeyWindow.RootViewController.DismissViewController(true, null);
};
await UIApplication.SharedApplication.KeyWindow.RootViewController.PresentViewControllerAsync(_imagePicker, true);
return await _tcs.Task;
}
}
这是我在我的应用程序中获取异步摄像头捕获 运行 所需要的:
在iOS中:
public async Task<string> TakePicture()
{
if (await AuthorizeCameraUse())
{
var imagePicker = new UIImagePickerController { SourceType = UIImagePickerControllerSourceType.Camera };
TaskCompletionSource<string> FinishedCamera = new TaskCompletionSource<string>();
// When user has taken picture
imagePicker.FinishedPickingMedia += (sender, e) => {
// Save the file
var filepath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "tmp.png");
var image = (UIImage)e.Info.ObjectForKey(new NSString("UIImagePickerControllerOriginalImage"));
image.AsPNG().Save(filepath, false);
// Close the window
UIApplication.SharedApplication.KeyWindow.RootViewController.DismissViewController(true, null);
// Stop awaiting
FinishedCamera.SetResult(filepath);
};
// When user clicks cancel
imagePicker.Canceled += (sender, e) =>
{
UIApplication.SharedApplication.KeyWindow.RootViewController.DismissViewController(true, null);
FinishedCamera.TrySetCanceled();
};
// Show the camera-capture window
UIApplication.SharedApplication.KeyWindow.RootViewController.PresentViewController(imagePicker, true, null);
// Now await for the task to complete or be cancelled
try
{
// Return the path we've saved the image in
return await FinishedCamera.Task;
}
catch (TaskCanceledException)
{
// handle if the user clicks cancel
}
}
return null;
}
如果你需要授权例程,请确保你也填写info.plist
中的相机用途,这是获得授权的功能:
public static async Task<bool> AuthorizeCameraUse()
{
var authorizationStatus = AVCaptureDevice.GetAuthorizationStatus(AVMediaType.Video);
if (authorizationStatus != AVAuthorizationStatus.Authorized)
{
return await AVCaptureDevice.RequestAccessForMediaTypeAsync(AVMediaType.Video);
}
else
return true;
}
在Android中:
private TaskCompletionSource<bool> _tcs_NativeCamera;
public async Task<string> TakePicture()
{
_tcs_NativeCamera = new TaskCompletionSource<bool>();
// Launch the camera activity
var intent = new Intent(MediaStore.ActionImageCapture);
intent.PutExtra(MediaStore.ExtraOutput, Android.Net.Uri.FromFile(cameraCaptureFilePath));
NextCaptureType = stype;
StartActivityForResult(intent, SCAN_NATIVE_CAMERA_CAPTURE_ASYNC);
// Wait here for the activity return (through OnActivityResult)
var Result = await _tcs_NativeCamera.Task;
// Return the camera capture file path
return Result != Result.Canceled ? cameraCaptureFilePath : null;
}
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
base.OnActivityResult(requestCode, resultCode, data);
switch (requestCode)
{
case SCAN_NATIVE_CAMERA_CAPTURE_ASYNC:
_tcs_NativeCamera.SetResult(resultCode);
break;
}
}
试试 James Montemagno 的 MediaPlugin。
您可以使用 Package Manager Console by simply typing and running Install-Package Xam.Plugin.Media -Version 2.6.2
or else go to Manage NuGet Packages... 安装插件并键入 Xam.Plugin.Media
并安装插件。 (必须在您的所有项目中安装插件 - 包括客户端项目)
A readme.txt 将出现提示并按照那里的说明进行操作。之后,add the following codes(根据需要)到您的共享项目。上述readme.txt文件中需要遵循的说明如下
对于 Android 项目
在您的 BaseActivity 或 MainActivity(对于 Xamarin.Forms)中添加此代码:
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Permission[] grantResults)
{
PermissionsImplementation.Current.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}
您还必须添加一些额外的配置文件以遵守新的严格模式:
将以下内容添加到 <application> 标签内的 AndroidManifest.xml:
<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必须设置为你的应用包名!
将名为 xml 的新文件夹添加到资源文件夹中,并添加名为
的新 XML 文件file_paths.xml
添加以下代码:
<?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必须设置为你的应用包名!
对于 iOS 项目
您的应用程序需要在您的 Info.plist 中包含 NSCameraUsageDescription
和 NSPhotoLibraryUsageDescription
的密钥,以便访问设备的相机和 photo/video 库。如果您使用库的视频功能,则还必须添加 NSMicrophoneUsageDescription
。当提示用户提供访问这些设备功能的权限时,您为每个密钥提供的字符串将显示给用户。
如:
<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>
对于共享项目
要简单地打开相机、保存照片并显示带文件路径的警报,请在共享项目中输入以下内容。
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");