在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)];

在选取照片出现多张相同照片的问题上,我发现拍摄的照片和相册中本来就有的照片有所不同,那就是它存储的infokey不同,拍照是5个key,相册是7个key,所以我通过key的个数来判断是否需要进行保存处理:

if (info.count == 5) {  //这里通过key的个数来判断是否需要保存在手机
            //将照片保存在相册
            UIImageWriteToSavedPhotosAlbum(showImage, self, @selector(image:didFinishSavingWithError:contextInfo:), nil);
        }