不管是哪種方式(JS與OC交互調(diào)用原生的方法,H5input標(biāo)簽)打開相機(jī),只要打開相機(jī)的時(shí)候,app項(xiàng)目是橫屏的(在xcode中只支持了橫屏方向)打開相機(jī),發(fā)生崩潰了,用下面的方法都可以解決。
我目前發(fā)生崩了的機(jī)型是x以上機(jī)型,不分iOS系統(tǒng)。 但是我面試的時(shí)候,有個(gè)面試官說他們公司所有機(jī)型在我上述場景中,都會崩潰。
報(bào)錯(cuò)日志:Supported orientations has no common orientation with the application, and [CAMViewfinderViewController shouldAutorotate] is returning YES
報(bào)錯(cuò)截圖:
崩潰分析:由于項(xiàng)目設(shè)置只支持了橫屏,相機(jī)默認(rèn)為豎屏打開。但是相機(jī)類[CAMViewfinderViewController shouldAutorotate] 返回了YES,也就是說:在這個(gè)類中,界面支持旋轉(zhuǎn),但是系統(tǒng)沒有豎屏選項(xiàng),支持旋轉(zhuǎn)就造成沖突,所以崩潰了。那么我們就要將這個(gè)[CAMViewfinderViewController shouldAutorotate] 返回NO.
實(shí)踐以input標(biāo)簽打開為例:(測試了JS調(diào)用原生方法打開相機(jī),直接在原生按鈕點(diǎn)擊事件里面打開相機(jī))
因?yàn)橛胕nput標(biāo)簽打開相機(jī),沒有辦法獲取到打開相機(jī)的點(diǎn)擊事件,所以沒有辦法用通知那種方法來通知AppDelegate的代理方法來改變屏幕支持的旋轉(zhuǎn)方向。所以我就用了分類+方法交換的方式來解決問題。
利用runtime的方法交換,實(shí)現(xiàn)當(dāng)系統(tǒng)調(diào)用[CAMViewfinderViewController shouldAutorotate]這個(gè)方法的時(shí)候,我實(shí)現(xiàn)自己的方法,并且返回NO,就可以達(dá)到不崩潰的目的。
下面是分類代碼:
.h文件。啥都沒有
#import <UIKit/UIKit.h>
@interface UIImagePickerController (custom)
@end
.m文件。如下:
#import "UIImagePickerController+custom.h"
#import <objc/runtime.h>
@implementation UIImagePickerController (custom)
static BOOL isDelegateMethodHooked = false;//防止交換方法的邏輯被多次調(diào)用
-(void)viewDidLoad{
[super viewDidLoad];
if (isDelegateMethodHooked == NO) {
Class vc = NSClassFromString(@"CAMViewfinderViewController");
SEL originalSelector = @selector(shouldAutorotate);
SEL swizzledSelector = @selector(sjx_stringByAppendingString);
Method originalMethod = class_getInstanceMethod(vc, originalSelector);
Method swizzledMethod = class_getInstanceMethod([self class], swizzledSelector);
BOOL didAddMethod = class_addMethod(vc,originalSelector,method_getImplementation(swizzledMethod),method_getTypeEncoding(swizzledMethod));
if(didAddMethod) {
class_replaceMethod([self class],swizzledSelector,method_getImplementation(originalMethod),method_getTypeEncoding(originalMethod));
} else {
method_exchangeImplementations(originalMethod, swizzledMethod);
}
}
}
- (BOOL)sjx_stringByAppendingString{
NSLog(@"2222222");
return YES;
}
-(void)dealloc{
isDelegateMethodHooked = YES;
}
看完代碼你可能會想,為什么交換方法的實(shí)現(xiàn)為什么沒有放到load里面,load里面只會調(diào)用一次,這樣也不用使用一個(gè)boll變量來保證代碼只執(zhí)行一次。
這是因?yàn)槲易铋_始放在load方法里面執(zhí)行,會發(fā)現(xiàn)獲取不到CAMViewfinderViewController這個(gè)類。這個(gè)時(shí)候這個(gè)類還咩有被創(chuàng)建,所以不能放在load方法里面執(zhí)行方法交換了。