在app开发过程中,会有很多需要调取摄像头的地方,例如上传头像,上传图片等,并且又的是会包含直接拍照或者是从相册取图片来完成上传的,这里我就大概给大家说说如何调用手机的相机和相册。
需要用到的库:
#import <AVFoundation/AVFoundation.h>
#import <MobileCoreServices/MobileCoreServices.h>
#import <MediaPlayer/MediaPlayer.h>
#import <AVKit/AVKit.h>
一、UIImagePickerController:
在我们使用代码来完成调取摄像头之前我们还需要了解了解UIImagePickerController
,它是OC中一种视图控制器,用于管理用于拍照、录制电影和从用户媒体库中选择项目的系统界面。
1.UIImagePickerController常见用途:
- 调用摄像头拍照
- 从相册中选择
- 从图库中选择
2.UIImagePickerController回调方法:
(1)成功获得相片或视频后的回调
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info;
info中包括选取的照片,视频的主要信息
NSString *const UIImagePickerControllerMediaType; 选取的类型 public.image public.movie
NSString *const UIImagePickerControllerOriginalImage; 修改前的UIImage object.
NSString *const UIImagePickerControllerEditedImage; 修改后的UIImage object.
NSString *const UIImagePickerControllerCropRect; 原始图片的尺寸NSValue object containing a CGRect data type
NSString *const UIImagePickerControllerMediaURL; 视频在文件系统中 的 NSURL地址
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
//通过UIImagePickerControllerMediaType判断返回的是照片还是视频
NSString* type = [info objectForKey:UIImagePickerControllerMediaType];
//如果返回的type等于kUTTypeImage,代表返回的是照片,并且需要判断当前相机使用的sourcetype是拍照还是相册
if ([type isEqualToString:(NSString*)kUTTypeImage] && picker.sourceType == UIImagePickerControllerSourceTypeCamera) {
//获取照片的原图
UIImage *original = [info
objectForKey:UIImagePickerControllerOriginalImage];
//获取图片裁剪的图
UIImage *edit = [info objectForKey:UIImagePickerControllerEditedImage];
//获取图片裁剪后,剩下的图
UIImage *crop = [info objectForKey:UIImagePickerControllerCropRect];
//获取图片的url
NSURL *url = [info objectForKey:UIImagePickerControllerMediaURL];
//获取图片的metaData数据信息
NSDictionary *metaData = [info objectForKey:UIImagePickerControllerMediaMetadata];
//如果是拍照的照片,则需要手动保存到本地,系统不会自动保存拍照成功后的照片
UIImageWriteToSavedPhotosAlbum(edit, self, @selector(image:didFinishSavingWithError:contextInfo:), nil);
} else {
}
//模态方式退出uiimagepickercontroller
[imagepicker dismissModalViewControllerAnimated:YES];
}
(2)取消照相机的回调
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker;
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {
//模态方式退出UIImagePickerController
[imagePicker dismissModalViewControllerAnimated:YES];
}
3.使用UIImagePickerController类来获取图片视频的步骤:
(1)初始化UIImagePickerController 类;
UIImagePickerController *cameraPicker = [[UIImagePickerController alloc] init];
(2)设置UIImagePickerController 实例的数据来源类型;
数据来源一共三种:
enum {
UIImagePickerControllerSourceTypePhotoLibrary,//来自图库
UIImagePickerControllerSourceTypeCamera,//来自相机
UIImagePickerControllerSourceTypeSavedPhotosAlbum,//来自相册
};
cameraPicker.sourceType = UIImagePickerControllerSourceTypeCamera; //设置数据来源为相机
这里我设置的数据来源是相机,在用这些数据来源的时候最好检测一下设备是否支持:
if([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
NSLog(@"支持相机");
}
if([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary]) {
NSLog(@"支持图库");
}
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeSavedPhotosAlbum]) {
NSLog(@"支持相片库");
}
(3)设置设置代理;
通过代理来获取我们选中的图片。
cameraPicker.delegate = self;
(4) 其他小功能:
-
BOOL showsCameraControls
设置拍照时的下方的工具栏是否显示,如果需要自定义拍摄界面,则可把该工具栏隐藏。 -
BOOL allowsEditing
设置当拍照完或在相册选完照片后,是否跳到编辑模式进行图片剪裁。
showsCameraControls=Yes时才有效果。
-
cameraDevice
判断设备是否支持前置摄像头/后置摄像头。
enum {
UIImagePickerControllerCameraDeviceRear,
UIImagePickerControllerCameraDeviceFront
};
-
cameraFlashMode
设置闪光灯模式。
enum {
UIImagePickerControllerCameraFlashModeOff = -1,
UIImagePickerControllerCameraFlashModeAuto = 0,
UIImagePickerControllerCameraFlashModeOn = 1
};
-
mediaTypes
设置相机支持的类型,拍照和录像。
如果你只是想要上传图像的话可以不用设置该属性,但是如果你要上传视频的话你就要单独设置一次:
cameraPicker.mediaTypes = @[(NSString *)kUTTypeMovie, (NSString *)kUTTypeImage];
但是如果上传视频的话,还得需要学习:
#import <AVFoundation/AVFoundation.h>
该框架中有视频的播放器用来播放视频。
-
setVideoQuality
设置拍摄的分辨率。
[cameraPicker setVideoQuality:UIImagePickerControllerQualityTypeIFrame1280x720];
-
cameraViewTransform
设置拍摄时屏幕的view的transform属性,可以实现旋转,缩放功能。
enum{
CGAffineTransformMakeRotation;
CGAffineTransformMakeScale;
}
(5)将UIImagePickerController推出;
[self presentViewController:cameraPicker animated:YES completion:nil];
另外,如果觉得自己不太能理解的可以去看其他的解释:
苹果给的解释:UIImagePickerController讲解
二、AVPlayerViewController视频播放:
1.优缺点:
- 优点:
(1)自带的播放控制UI,不需要手动添加。
(2)此控制器是视图控制器,可以弹出,可以压栈。
(3)可以手动调整视图大小, 添加到其他视图上。 - 缺点: 不能自定义UI。
2.视频播放实现步骤:
(1)导入框架:
#import <AVFoundation/AVFoundation.h>
#import <AVKit/AVKit.h>
(2)根据URL创建AVPlayer:
NSURL *remoteUrl = [NSURL URLWithString:@"http://v1.mukewang.com/57de8272-38a2-4cae-b734-ac55ab528aa8/L.mp4"];
AVPlayer *player = [AVPlayer playerWithURL:remoteUrl];
(3)根据AVPlayer, 创建AVPlayerViewController控制器:
_playerVc = [[AVPlayerViewController alloc] init];
_playerVc.player = player;
(4)设置播放视图frame, 添加到需要展示的视图上:
self.playerVc.view.frame = CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height * 9 / 16);
[self.view addSubview:self.playerVc.view];
(5)播放:
[self.playerVc.player play];
三、调用手机摄像头的步骤:
步骤一:添加协议和控件
首先我们需要用到一个类:UIImagePickerController
,这个是用来调用相机的类,在使用之前,需要先遵守UIImagePickerControllerDelegate
协议和UINavigationControllerDelegate
协议。
#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
#import <MobileCoreServices/MobileCoreServices.h>
#import <MediaPlayer/MediaPlayer.h>
@interface ViewController : UIViewController<UIImagePickerControllerDelegate, UINavigationControllerDelegate>
//响应点击事件的Button
@property (nonatomic, strong) UIButton *headButton;
//通过这个imageView来返回你选中或者拍摄的图片
@property (nonatomic, strong) UIImageView *headImageView;
@end
在这里,我定义了一个Button
用来响应点击事件来调用摄像头或者相册,而imageView
是用来展示你选中或者拍摄的照片的。
步骤二:初始化控件
初始化控件,并且为Button
添加上点击事件,来调用手机的摄像头和相册。
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
//创建一个按钮,点击出现选项
self.headButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[self.headButton setTitle:@"选取头像" forState:UIControlStateNormal];
self.headButton.frame = CGRectMake(100, 100, 100, 30);
[self.headButton addTarget:self action:@selector(catchImage:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:self.headButton];
//选取的图片将展示在该imageview上
self.headImageView = [[UIImageView alloc] initWithFrame:CGRectMake(100, 250, 150, 150)];
self.headImageView.backgroundColor = [UIColor yellowColor];
[self.view addSubview:self.headImageView];
}
步骤三:添加按钮的点击事件
- (void)catchImage:(UIButton *)button {
//调用摄像头
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"请选择" message:@"选取照片" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *actionOne = [UIAlertAction actionWithTitle:@"相机" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
UIImagePickerController *cameraPicker = [[UIImagePickerController alloc] init];
cameraPicker.sourceType = UIImagePickerControllerSourceTypeCamera;
cameraPicker.delegate = self;
cameraPicker.allowsEditing = YES;
[self presentViewController:cameraPicker animated:YES completion:nil];
} else {
UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"没有摄像头" message:nil preferredStyle:UIAlertControllerStyleActionSheet];
UIAlertAction *action = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDestructive handler:nil];
[controller addAction:action];
[self presentViewController:controller animated:YES completion:nil];
}
}];
[alert addAction:actionOne];
//调用相册
UIAlertAction *actionTwo = [UIAlertAction actionWithTitle:@"相册" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
UIImagePickerController *picker = [[UIImagePickerController alloc] init];
picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
picker.delegate = self;
picker.allowsEditing = YES;
[self presentViewController:picker animated:YES completion:nil];
}];
[alert addAction:actionTwo];
[self presentViewController:alert animated:YES completion:nil];
}
步骤四:设置选取图片后执行的方法
//选取图片之后执行的方法,该方法是你图片选取完成后对进行的操作
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<UIImagePickerControllerInfoKey,id> *)info {
UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage];
self.headImageView.image = image;
[picker dismissViewControllerAnimated:YES completion:nil];
}
四.写程序时遇到的问题:
1.真机调试时出现问题导致调试崩溃:
问题:
调用摄像头[13132:2173412] [access] This app has crashed because it attempted to access privacy-sensitive data without a usage description. The app’s Info.plist must contain an NSCameraUsageDescription key with a string value explaining to the user how the app uses this data.
解决:
只需要在你 xcode 工程目录下的 info.plist 添加权限申请描述文件就如下:
<key>NSCameraUsageDescription</key>
<string>请允许APP访问您的相机</string>
<key>NSPhotoLibraryAddUsageDescription</key>
<string>请允许APP保存图片到相册</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>请允许APP访问您的相册</string>
<key>NSMicrophoneUsageDescription</key>
<string>需要麦克风访问才能上传视频</string>
<key>NSLocationUsageDescription<key>
<string>需要位置访问以更新附近的朋友<string>
<key>NSLocationWhenInUseUsageDescription<key>
<string>此应用程序将使用您的位置显示您附近的酷东西<string>
2.照片和视频存储问题:
问题:
在拍摄存储视频时经常出现存储完后没有在视图上显示的问题,并且在选取照片展示时,会出现多张相同的照片在相册。
解决:
在存储拍摄的视频时,我索性将原来的UIImageView改为了UIView在这个基础上判断是视频还是照片,然后进行相应的添加控件,并且为了不出现重叠的情况,在每次添加之前都会清除该View上的控件:
[self.headView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
在选取照片出现多张相同照片的问题上,我发现拍摄的照片和相册中本来就有的照片有所不同,那就是它存储的info
的key
不同,拍照是5个key,相册是7个key,所以我通过key的个数来判断是否需要进行保存处理:
if (info.count == 5) { //这里通过key的个数来判断是否需要保存在手机
//将照片保存在相册
UIImageWriteToSavedPhotosAlbum(showImage, self, @selector(image:didFinishSavingWithError:contextInfo:), nil);
}