好久没有写博客了,原因有三:
1.使用了马克飞象+印象笔记使用,使用前者markdown
写东西,直接上传到后者。看起来非常的舒服。
2.最近40天比较忙。一直开发公司项目
3.最近忙里偷闲,一直在做iOS逆向开发,也就没有去将逆向的事情记录博客供大家分享~
这段时间确实遇到了好多问题。很幸运是过去没有开发过的东西,虽然自己已经记录在了印象笔记上了。但是感觉还是应该分享一下,供其他人使用
tap:
- 1.手机拍照之后,获取照片方向旋转 90度,使用了分类不好使的原因.
- 2.获取照片或者相机的权限问题详解
- 3.位置权限未开启,如何跳转到正确的设置页面(系统级别和自己的app级别)
- 4.导航栏设置背景及导航栏滑动透明的功能实现
- 5.
statusBar
的两种隐藏方式和区别 - 6.使用NSBundle获取不到照片的问题
- 7.弱约束
- 8.适配ios11的位置权限以及坑,提交的坑
1.手机拍照使用分类不好使问题(裁剪方形照片)
话说项目中经常有自定义相机的功能.那么可定会获取到一个偏移90度的问题。这个网上说的都有点烂大街了.
具体原因可以参照这篇博客.讲述的非常的详细.
但是我在项目中用的时候,使用了文章里面提供的分类---也就是所有人提供的同一份分类不起作用!!!
最后发现是我获取手机方向出了错误。获取到的手机方向UIDevice.currentDevice.orientation
永远是.portrait
(上).我就给特别的那么。无论如何去移动自己的手机,方向都是(上)。
后来问题前辈,才知道,原因是因为手机的方向锁定设置成了“锁定状态”,所以获取的数据永远是.portrait
.

问题是手机屏幕锁定打开了。只要关闭即可
PS:如果想监听手机方向。应该去添加通知,
注意: 必须保证手机屏幕锁定是关闭的,否则方向改变,通知也不会发送
//1.当前的摄像的方向
fileprivate var crtOri:UIDeviceOrientation = UIDevice.current.orientation
//2.添加通知
fileprivate func setupNotification(){
NotificationCenter.default.addObserver(self,
selector: #selector(receiveScreenOrientationChange(_:)),
name: NSNotification.Name.UIDeviceOrientationDidChange,
object: nil)
}
//实时更新具体的方向
@objc fileprivate func receiveScreenOrientationChange(_ noti:Notification){
crtOri = UIDevice.current.orientation
}
//3.移除通知
deinit {
NotificationCenter.default.removeObserver(self)
}
2.获取照片或者相机的权限问题详解
获取照片这个应该是比较常见的话题。但是还是值得在说一下
请求AVCaptureDevice
相机的权限的两个方法
@available(iOS 7.0, *)
open class func authorizationStatus(forMediaType mediaType: String!) -> AVAuthorizationStatus
open class func requestAccess(forMediaType mediaType: String!, completionHandler handler: ((Bool) -> Swift.Void)!)
相机的授权状态分为以下几种
public enum AVAuthorizationStatus : Int {
//用户未决定,也就是还没有弹出来系统的alert.还没有询问过用户是否授权
case notDetermined
//受限制
case restricted
//用户不允许
case denied
//用户同意
case authorized
}

获取授权有上边两个方法。也是有一定区别的。
前者是可以获取到具体的状态类型的。是枚举值,但是当第一次处理alert的时候,我们获取的结果是未决定,当我们点击了不允许或者是好。无法获取到点击了那一个。这很尴尬.
但是如果使用了第二种发生请求,就可以获取到成功还是失败,他的返回值是bool,非常的方便使用。
当系统第一次询问的时候,我们给出了选择之后,他才会打印结果,授权或者不
AVCaptureDevice.requestAccess(forMediaType: AVMediaTypeVideo) { (result) in
print("权限= \(result)")
if result == true{
let imgPickerVC = UIImagePickerController.init()
imgPickerVC.sourceType = .camera
self.present(imgPickerVC, animated: true, completion: nil)
}
}
}
//打印结果
权限= true
PS:相册授权,和位置授权同理
3.位置权限未开启,如何跳转到正确的设置页面(系统级别和自己的app级别)
如果发现定位没有授权,也就是denied
状态.那么我们应该进入设置页面去设置
其实定位为授权,分为两种:
1.这个系统都未授权 let enable = CLLocationManager.locationServicesEnabled()
2.对该app未授权 .denied
所以处理定位的未授权的时候,应该注意一下。根据不同的情况跳转到不同的设置页面去,一个是系统级的设置页面,一个是app级别的设置页面
fileprivate func checkLocationAuthor(){
let enable = CLLocationManager.locationServicesEnabled()
guard enable == true else {
//弹出一个咨询框
showOpenSystemLocationAlert()
return
}
let state = CLLocationManager.authorizationStatus()
switch state {
case .notDetermined:
//弹出决定框
self.locMgr.requestWhenInUseAuthorization()
return
case .restricted:
buttonState = .failed
//弹出一个咨询框
showGetAuthAlert()
return
case .denied:
buttonState = .failed
//弹出一个咨询框
showGetAuthAlert()
return
default:
buttonState = .loading
//去定位当前位置
self.locMgr.startUpdatingLocation()
}
}
fileprivate func showOpenSystemLocationAlert(){
let alertView = LRAlertView.init(frame: LRScreenBounds)
alertView.show(with: .doubleButton,
title: "温馨提示",
subTitle: nil,
content: LROpenSystemLocationNoticeKey,
buttonBlock: { (index) in
if index == 1{
if #available(iOS 10.0, *) {
let string = "App-Prefs:root=Privacy&path=LOCATION"
let url = URL.init(string:string)
UIApplication.shared.open(url!, options: [:], completionHandler: { (comp) in
print("打开成功")
})
} else {
let string = "prefs:root=LOCATION_SERVICES"
let url = URL.init(string:string)
if UIApplication.shared.canOpenURL(url!) {
UIApplication.shared.openURL(url!)
}
}
}else{
print("取消选中")
}
}, btnStrs: "取消#查看设置")
}
fileprivate func showGetAuthAlert(){
let alertView = LRAlertView.init(frame: LRScreenBounds)
alertView.show(with: .doubleButton,
title: "温馨提示",
subTitle: nil,
content: LROpenLemonRunLocationNoticeKey,
buttonBlock: { (index) in
if index == 1{
let string = UIApplicationOpenSettingsURLString
let url = URL.init(string:string)
UIApplication.shared.openURL(url!)
}else{
print("取消选中")
}
}, btnStrs: "取消#查看设置")
}
iOS10以上的使用"App-Prefs:root=Privacy&path=LOCATION"
跳转到系统级别的设置页面,打开之后,所有的app都可以使用位置权限了
iOS10以下,使用"prefs:root=LOCATION_SERVICES
跳转到系统级别的设置页面
如果是跳转到自己的项目中的设置页面,只要传递UIApplicationOpenSettingsURLString
字符串即可
4.导航栏设置背景及导航栏滑动透明的功能实现
导航栏比较特殊,所以直接设置他的背景颜色啥的。也是有一层毛玻璃,这个问题,在很多博客中都有讲述,然后使用runtime
就可以解决这些问题。但是现在要说的是滑动效果~
参考的是这个参考github
//viewWillAppear的时候,设置导航栏的背景
self.automaticallyAdjustsScrollViewInsets = NO;
//设置导航条空间的透明度是没有效果的 但是可以设置透明的背景图
//设置为nil系统自动给你设置半透明图片
//下面三句话,让导航栏透明了
self.navigationController.navigationBar.alpha = 0;
[self.navigationController.navigationBar setBackgroundImage:[[UIImage alloc]init] forBarMetrics:UIBarMetricsDefault];
[self.navigationController.navigationBar setShadowImage:[[UIImage alloc]init]];//导航条图片下面的线
//根据色值生成一张图片
- (UIImage *)imageWithColor:(UIColor *)color
{
// 描述矩形
CGRect rect = CGRectMake(0.0f, 0.0f, 1.0f, 1.0f);
// 开启位图上下文
UIGraphicsBeginImageContext(rect.size);
// 获取位图上下文
CGContextRef context = UIGraphicsGetCurrentContext();
// 使用color演示填充上下文
CGContextSetFillColorWithColor(context, [color CGColor]);
// 渲染上下文
CGContextFillRect(context, rect);
// 从上下文中获取图片
UIImage *theImage = UIGraphicsGetImageFromCurrentImageContext();
// 结束上下文
UIGraphicsEndImageContext();
return theImage;
}
通过scrollview的偏移量修改背景的透明度
- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
CGFloat offset = scrollView.contentOffset.y - originY;
CGFloat h = originH - offset;
if (h<64) {
h = 64;
}
self.topViewHeight.constant = h;
CGFloat alpha = offset * 1 / 136.0;
if (alpha >=1) {
alpha = 0.99;
}
//拿到标题
UILabel *titleL = (UILabel *)self.navigationItem.titleView;
titleL.textColor = [UIColor colorWithWhite:0 alpha:alpha];
//修改导航栏的背景图片
//把颜色生成图片
UIColor *alphaColor = [UIColor colorWithWhite:1 alpha:alpha];
//把颜色生成图片
UIImage *alphaImage = [self imageWithColor:alphaColor];
//修改导航条背景图片
[self.navigationController.navigationBar setBackgroundImage:alphaImage forBarMetrics:UIBarMetricsDefault];
}
5.statusBar
的两种隐藏方式和区别
文章参考
总结:
- ①.
View controller-based status bar appearance
表示控制App状态栏显隐接受全局配置(NO)或者各控制器各自配置(YES),iOS9
之后,建议配置成YES,各自控制器控制状态的隐藏或显示. - ②.
[[UIApplication sharedApplication] setStatusBarHidden:YES]
,必须在View controller-based status bar appearance == NO
条件下才能生效 - ③.通过
prefersStatusBarHidden
为局部配置项,控制对应控制器状态栏显隐,必须在View controller-based status bar appearance == YES
才生效。 - ④.在启动页面应该是隐藏的状态,在plist中设置
Status bar is initially hidden = YES
即可. - ⑤.如果我们打算使用
[[UIApplication sharedApplication] setStatusBarHidden:hidden]
全局来控制状态栏的隐藏或显示,如果M页面要去隐藏状态栏,我们就应该在M页面做好控制.M消失的时候,应该还原,避免对其他页面的影响
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
UIApplication.shared.setStatusBarHidden(true, with: .none)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
UIApplication.shared.setStatusBarHidden(false, with: .none)
}
- ⑥.
[[UIApplication sharedApplication] setStatusBarHidden:hidden]
方法在iOS9
之后,已经不建议使用了。建议使用prefersStatusBarHidden
控制。切记.
6.使用NSBundle获取不到照片的问题
同事直接将.png
图片拖到了项目中,但是使用NSBundle
获取不到照片。尴尬.但是用一个干净的demo测试没有问题,也不知道这个大哥是如何拖进来的。反正获取的是nil路径.

filePath = [[NSBundle mainBundle] pathForResource:@"LevelGif11" ofType:@"gif"];
问题是没有将图片加载到资源文件中
//解决
在项目设置中Build Phases > Copy Bundle Resources
中可以查看已经添加进去的资源文件,如果里面没有,那就需要在这里手动添加了。
7.弱约束
项目中经常使用到布局。

很多人非要用xib去做,然后那,又做不好~
我们要求vipicon距离“接收”按钮15dx。
其实只要去给vipIcon添加一个约束,>=15即可,这样就是“弱约束”,到时候系统自己检测即可

8.适配ios11的位置权限以及坑,提交的坑
ios11之后,位置的设置权限有了很重要的改变,就是必须有三个选项
1.永不
2.使用期间
3.永远使用
但是在ios10之前可以将使用期间省略。
昨天做了适配ios11,ios上的永不,降级为使用期间,添加一个新的字段即可Privacy - Location Always and When In Use Usage Description
,然后就行了,别的我没处理,保证的是在ios10上还是两个,但是在ios11上是三个。
我的是Xcode8.3.3
,多哥的是Xcode9
,上线之后还是不好使。
我就懵逼了,我的xcode运行就没有任何问题,但是多哥的就不好使。
区老师问我有什么思路吗?我说没有,他说,你的好事,ipa上的就不好使,说明是包出来问题,让我去看看多哥打包出来的ipa好使不好使,然后再去看其他的问题。给了我这个好的思路,然后才发现,确实是多哥xcode的问题,所以很尴尬,出问题,先想原因,然后在去做会更好一些。
网友评论