iOS 10.3 应用内更换应用图标的方法

更换图标需要支持以下几点:

1、首先需要确保手机系统是否在10.3以上

2、是否支持更换应用图标

具体代码如下:
if #available(iOS 10.3, *) {
guard UIApplication.shared.supportsAlternateIcons else {
return
}
UIApplication.shared.setAlternateIconName("yellow_logo", completionHandler: { (error) in
if error != nil {
print("没成功")
}
})
}

其次还需要设置Info.plist

接着将logo拖入项目文件中。最终效果如下

null

碎片知识 (1)

1、开发者证书无效:
遇到这种情况需要下载苹果最新证书
然后在钥匙串->显示->显示过期证书下,删除过期的原证书即可,这样就没问题了
2、iOS9 设备上http网页无法加载:
需要在plist里面设置:NSAppTransportSecurity里面的”Allow Arbitrary Loads”这个属性为true。
其次如果想只添加单独网页需要用:Exception Domains这个参数来添加,如下图:
piece 01
其中的属性为:NSIncludesSubdomains(子域名是否也可以加载)、NSExceptionRequiresForwardSecrecy(是否禁用ForwardSecrecy)、NSExceptionAllowInsecureHTTPLoads(是否允许签名过期,或者不匹配等情况)
3、Bitcode:
默认项目是开启的,Bitcode可以帮助App减小包的大小,但有的第三方库不支持,所以凭项目情况来决定是否开启
4、企业App无法安装:
这个是因为iOS9 需要在设置->通用->描述文件中开启信任即可
5、iOS9 字体显示不全:
可以使用:sLabel.sizeToFit() 或者 sizeWithAttributes 来自动拉伸
6、iOS9 无法跳其他App:
需要在plist添加字段:LSApplicationQueriesSchemes,然后在其下面添加要跳转的App scheme

SFSafariViewController

SFSafariViewController 也是iOS9之后,苹果推出的新功能,这个框架使用起来相对比UIWebView简单一些。但是目前感觉仅适用于简单操作,因为SFSafariViewController只提供了两个实例化方法,两个delegate方法。
接下来我们简单看下如何使用这个新框架吧。
首先需要包含框架
[code lang=”Objective-C”]import SafariServices[/code]
其次就是实例化,并跳入到控制器
[code lang=”Objective-C”]// entersReaderIfAvailable参数是是否可以调用阅读模式
let safarivc = SFSafariViewController(URL: NSURL(string: “http://www.baidu.com”)!, entersReaderIfAvailable: true)
self.presentViewController(safarivc, animated: true, completion: nil)[/code]
接下来实现SFSafariViewControllerDelegate
[code lang=”Objective-C”]// 此方式是打开safari加载网页完成之后的方法,打印结果显示是否加载成功
func safariViewController(controller: SFSafariViewController, didCompleteInitialLoad didLoadSuccessfully: Bool) {
print(“\(didLoadSuccessfully)”)
}
// 点击完成后调用此方法
func safariViewControllerDidFinish(controller: SFSafariViewController) {
print(“back”)
}
// 点击分享按钮就能拦截到此方法,在这里可以自定义分享里面的按钮
func safariViewController(controller: SFSafariViewController, activityItemsForURL URL: NSURL, title: String?) -> [UIActivity] {

print(“\(URL),\(title)”)

let ac = UIActivity()
return [ac]
}[/code]
以上就是SFSafariViewController 控制器的简单集成

Replay Kit 使用

Replay Kit 感觉是玩游戏时需要的,可以录制视频,可以语言教学。但是要求在iOS9以上,那么我们来看看如何简单的集成这个框架进行录制自己的小视频吧。
首先需要包含框架

import ReplayKit

其次就是创建一个按钮,来供我们进行录制功能,然后方法名为startRecording

func startRecording(sender :UIButton) {
    if RPScreenRecorder.sharedRecorder().available {
        // true :第一个参数代表是否开启麦克风
        RPScreenRecorder.sharedRecorder().startRecordingWithMicrophoneEnabled(true, handler: { (error :NSError?) -> Void in
            if error == nil {
                sender.removeTarget(self, action: "startRecording:", forControlEvents: .TouchUpInside)
                sender.addTarget(self, action: "stopRecording:", forControlEvents: .TouchUpInside)
                sender.setTitle("停止", forState: .Normal)
            }else{
                print("录像失败")
            }
        })
    }else{
         print("不能录像")
    }
}

接下来我们要实现停止录像的方法

func stopRecording(sender :UIButton){
    RPScreenRecorder.sharedRecorder().stopRecordingWithHandler { (previewController : RPPreviewViewController?, error :NSError?) -> Void in
        if previewController != nil {
            previewController?.previewControllerDelegate = self
            let alertController = UIAlertController(title: "Recording", message: "Do you wish to discard or view your gameplay recording?", preferredStyle: .Alert)
            // 取消按钮
            let discardAction = UIAlertAction(title: "Discard", style: .Default) { (action: UIAlertAction) in
                RPScreenRecorder.sharedRecorder().discardRecordingWithHandler({ () -> Void in
                    // Executed once recording has successfully been discarded
                })
            }
            // 确定按钮
            let viewAction = UIAlertAction(title: "View", style: .Default, handler: { (action: UIAlertAction) -> Void in
                self.presentViewController(previewController!, animated: true, completion: nil)
            })
                
            alertController.addAction(discardAction)
            alertController.addAction(viewAction)
                
            self.presentViewController(alertController, animated: true, completion: nil)
                
            sender.removeTarget(self, action: "stopRecording:", forControlEvents: .TouchUpInside)
            sender.addTarget(self, action: "startRecording:", forControlEvents: .TouchUpInside)
            sender.setTitle("Start Recording", forState: .Normal)
            sender.setTitleColor(UIColor.blueColor(), forState: .Normal)
        }else{
                
        }
    }
}

上面的代码我们还需要实现了replaykit框架的一个delegate。RPPreviewViewControllerDelegate
以下是他的两个delegate方法
// 此方式是点击view之后 弹出视频预览页面,可以直接返回 可以保存 也可以分享 通过activityTypes的返回字段可以拿到相应的状态

func previewController(previewController: RPPreviewViewController, didFinishWithActivityTypes activityTypes: Set) {
    print("\(activityTypes)")
        
    if activityTypes.contains("com.apple.UIKit.activity.SaveToCameraRoll")  {
        print("存储视频")
    }else{
        print("取消")
    }
}
// 这是点击视频预览页面顶部两个按钮之后执行的操作
func previewControllerDidFinish(previewController: RPPreviewViewController) {
    previewController.dismissViewControllerAnimated(true, completion: nil)
}

Swift – UIAlertController

iOS 8 之后苹果出了一个UIAlertController,这个使用起来会比原来的UIAlertView 更加灵活一些,同时也可以集成上拉菜单。可以任意添加textfield,并且通过block来更方便的实现内部方法。
下面写一下简单集成,首先创建一个UIAlertController:
[code lang=”Objective-C”]
let alertController = UIAlertController(title: “标题”, message: “这个是UIAlertController的默认样式”, preferredStyle: UIAlertControllerStyle.Alert)
// 添加两个TextField
alertController.addTextFieldWithConfigurationHandler {
(textField: UITextField!) -> Void in
textField.placeholder = “登录”
// 在此可以添加一个textField的监听,对里面输入的内容可以进行分辨
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector(“alertTextFieldDidChange:”), name: UITextFieldTextDidChangeNotification, object: textField)
}
alertController.addTextFieldWithConfigurationHandler {
(textField: UITextField!) -> Void in
textField.placeholder = “密码”
textField.secureTextEntry = true
}
// 取消按钮
let cancelAction = UIAlertAction(title: “取消”, style: UIAlertActionStyle.Cancel, handler: nil)
alertController.addAction(cancelAction)
// 普通按钮(在此可以直接添加按钮点击的响应事件)
let okAction = UIAlertAction(title: “好的”, style: UIAlertActionStyle.Default) {
(action: UIAlertAction!) -> Void in
let login = (alertController.textFields?.first)! as UITextField
let password = (alertController.textFields?.last)! as UITextField
print(“\(login.text)—\(password.text)”)
// 上一个添加的textField监听可以在此移除
NSNotificationCenter.defaultCenter().removeObserver(self, name: UITextFieldTextDidChangeNotification, object: nil)
}

alertController.addAction(okAction)
// 警告按钮
let resetAction = UIAlertAction(title: “警告”, style: UIAlertActionStyle.Destructive, handler: nil)
alertController.addAction(resetAction)

presentViewController(alertController, animated: true, completion: nil)
然后需要实现textField的监听方法

func alertTextFieldDidChange(notification: NSNotification){
let alertController = presentedViewController as! UIAlertController?
if (alertController != nil) {
let login = (alertController!.textFields?.first)! as UITextField
let okAction = alertController!.actions.last! as UIAlertAction
// 读取字符串长度(1汉字=3长度)
print("\(login.text?.lengthOfBytesUsingEncoding(NSUTF8StringEncoding))")
// 读取字符串长度(1汉字=1长度)
print("\(login.text?.characters.count)")
}
}
[/code]
接下来写下上拉菜单的集成:
[code lang="Objective-C"]
let alert = UIAlertController(title: "title", message: "message", preferredStyle: .ActionSheet)

let cancelAction = UIAlertAction(title: "取消", style: UIAlertActionStyle.Cancel, handler: nil)
let deleteAction = UIAlertAction(title: "删除", style: UIAlertActionStyle.Destructive, handler: nil)
let archiveAction = UIAlertAction(title: "保存", style: UIAlertActionStyle.Default, handler: nil)
alert.addAction(cancelAction)
alert.addAction(deleteAction)
alert.addAction(archiveAction)

self.presentViewController(alert, animated: true, completion: nil)

// 此代码为iPad上运行时所需要,在iPad上不需要写取消按钮,点击其他区域默认取消
let popover = alert.popoverPresentationController
if (popover != nil){
popover?.sourceView = sender
popover?.sourceRect = sender.bounds
popover?.permittedArrowDirections = UIPopoverArrowDirection.Any
}[/code]

Swift 获取iPhone设备相关信息

获取iPhone机器名称:UIDevice.currentDevice().name
获取设备当前版本:UIDevice.currentDevice().systemVersion
获取设备当前系统名称:UIDevice.currentDevice().systemName
获取设备当前系统名称:
UIDevice.currentDevice().identifierForVendor?.UUIDString
获取设备运营商名称:
import CoreTelephony
CTTelephonyNetworkInfo().subscriberCellularProvider?.carrierName
也可以使用:
CTTelephonyNetworkInfo().currentRadioAccessTechnology
是设备震动:
import AudioToolbox
AudioServicesPlaySystemSound(kSystemSoundID_Vibrate)
获取设备电池电量:
UIDevice.currentDevice().batteryMonitoringEnabled = true
// 需要注意在iOS8 之前只能精确到0.05 iOS8之后可以精确到0.01
UIDevice.currentDevice().batteryLevel

iOS 3D Touch 这个技能不白学

随着iOS9和6S的到来,3D Touch已经被人们逐渐熟悉和使用,所以本篇主要讲讲这个新技能如何get,以及如何做的更出色。

首先可以先判断该设备是否支持3D touch:
[code lang=”Objective-C”]if (self.traitCollection.forceTouchCapability == UIForceTouchCapabilityAvailable) {
// UIViewControllerPreviewingDelegate
[self registerForPreviewingWithDelegate:self sourceView:_imageView];
}[/code]
然后实现delegate:
[code lang=”Objective-C”]- (UIViewController *)previewingContext:(id<UIViewControllerPreviewing>)previewingContext viewControllerForLocation:(CGPoint)location
{
    UIButton *imageView = (UIButton *)[previewingContext sourceView];
    [previewingContext setSourceRect:imageView.bounds];

    POPViewController *p = [[POPViewController alloc] init];
    p.preferredContentSize = CGSizeMake(0, 100);
    p.view.backgroundColor = [UIColor blackColor];
    return p;
}[/code]
[code lang=”Objective-C”]- (void)previewingContext:(id<UIViewControllerPreviewing>)previewingContext commitViewController:(UIViewController *)viewControllerToCommit
{
    [self presentViewController:viewControllerToCommit animated:YES completion:nil];
}[/code]
这样可以简单完成一个3D touch Demo,想要实现上拉展示文字可以这样做:
[code lang=”Objective-C”]- (NSArray *)preActions
{
    if (!_preActions) {   
    UIPreviewAction *action0 = [UIPreviewAction actionWithTitle:@”test” style:UIPreviewActionStyleDefault handler:^(UIPreviewAction * _Nonnull action, UIViewController * _Nonnull previewViewController) {
    }];

    UIPreviewAction *action1 = [UIPreviewAction actionWithTitle:@”test1″ style:UIPreviewActionStyleDestructive handler:^(UIPreviewAction * _Nonnull action, UIViewController * _Nonnull previewViewController) {

    }];

    UIPreviewActionGroup *actionGroup = [UIPreviewActionGroup actionGroupWithTitle:@”actionGroup” style:UIPreviewActionStyleSelected actions:@[action0, action1]];

    _preActions = @[action0, action1, actionGroup];
    }

    return _preActions;
}
[/code]
[code lang=”Objective-C”]
// 设置控制器在弹窗时候,下面输出的数组- (NSArray<id<UIPreviewActionItem>> *)previewActionItems
{
    return self.preActions;
}[/code]
以上就是粗略的实现了内部3D touch 的功能

WebView只需要添加
[code lang=”Objective-C”]webView.allowsLinkPreview = YES[/code]
即可实现3D touch 的功能
[code lang=”Objective-C”]UITouch *touch = touches.anyObject;[/code]
touch.force这个可以看到用的按压的力度做出相应的判断

iOS 和H5打交道的那些事 JavaScript & iOS

前言:

现在面试都很流行问的一个问题:H5 和iOS 交互做过吗?

做过?说说具体如何实现。没做过?不好意思我们再考虑一下。

今天就和大家一起分享,探讨这个流行问题的答案,首先我们要有一个自己的H5页面,还要有一个xcode,以及一个大脑。

交互方法一:stringByEvaluatingJavaScriptFromString

这个方法可以传递数据给H5,也可以调用H5的function,拿到返回值到app中,这也需要H5和app做一个相互约束的方法名称才能完成此操作。
[code lang=”Objective-C”]UIWebViewDelegate:- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType[/code]
这个方式可以在点击H5按钮等点击事件时做相应的拦截,截取需要的信息

注:这个方法是放在主线程进行的,所以有时会出现卡顿现象影响用户体验

交互方法二:JavaScriptCore

JavaScriptCore是iOS7之后苹果推出的JS交互方法,交互也相对简单了很多。

首先包含文件:

#import <JavaScriptCore/JavaScriptCore.h>

我们可以在webViewDidFinishLoad 里面获取JS的上下文
[code lang=”Objective-C”]JSContext *context = [webView valueForKeyPath:@”documentView.webView.mainFrame.javaScriptContext”];[/code]
在H5调用app的时:
[code lang=”Objective-C”]// xxxx 是H5中的方法名称,可以通过此方法调用app端做相应操作,可以在JSValue里面获取相应的值做处理
context[@”xxxx”] = ^() {
NSArray *args = [JSContext currentArguments];
for (JSValue *jsVal in args) {
}
}[/code]
app想调用H5则是:
[code lang=”Objective-C”]// xxxx是H5里面的方法名称 yyyyyyy 里面是H5方法里面相对于的一些参数
NSString *textJS = @”xxxx(‘yyyyyyy’)”;
[context evaluateScript:textJS];[/code]
以上就是对H5 和 app 相互交互的理解了,可以多加练习,就会逐渐理解了。
借鉴的文章地址:iOS下JS与原生OC互相调用(总结)

iOS Method Swizzling

Method Swizzling 被称为苹果的黑魔法,简单的来理解就是把你自定义的方法和系统方法通过交换指针地址的办法进行互换。
方法为:method_exchangeImplementations 使用方法如下:

let met1 = class_getInstanceMethod(UIViewController.self, #selector(UIViewController.viewWillAppear))
let met2 = class_getInstanceMethod(UIViewController.self, #selector(UIViewController.myviewWillAppear))
method_exchangeImplementations(met1, met2)

还需要实现此方法的扩展

extension UIViewController {
    func myviewWillAppear() {
        print("这是我的方法")
    }
}

现在把这段放在viewDidLoad 里面看看会发生什么吧。
虽然感觉这个方法很了不得,但是使用起来也要慎重,因为苹果文档上也是说明希望还是调用父类的方法来做某些事情,因为会有一些不安全因素嘛,而且重写毕竟要考虑的也有很多。
其他详细的知识讲解可以去参考官方文档
此外:Method Swizzling 也可以用来实现AOP,Aspects 第三方框架很好的封装了Runtime&Method Swizzling 的一些方法,感兴趣可以下载看看

iOS- Jenkins 自动打包集成

应上面需求,需要搞一个自动打包服务,需求:可供其他人员通过SVN自动生成ipa文件,供他人安装。虽然这个需求起初我是拒绝的,不过。。你懂得

以下适用于CocoaPods&SVN的项目Git稍后会出

自动打包有xcodebuilder,或者xcodetool 直接由命令行生成,但这限于本机,别人使用不方便。

命令行可以这么写:

cd 你的项目路径

/usr/bin/xcodebuild -scheme 项目名称 -workspace 项目名称.xcworkspace clean build CONFIGURATION_BUILD_DIR=你的输出路径

(此步可以生成.app,证书会自动选择的)

/usr/bin/xcrun -sdk iphoneos PackageApplication -v 上一步.app的路径 -o 你的输出路径

(后面写到xxx.ipa)

这样就完成了在命令行打包。

所以我们接下来介绍Jenkins 自动拉取代码打包生成ipa。

第一步:我们需要把jenkins安装在自己的用户下不要去官网上下载,如果已经下载了可以先卸载掉链接

然后输入命令行:

$ ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
brew install jenkins

等待自行安装完即可,此时命令行不要关闭,在浏览器输入http://localhost:8080,并保持命令行是开启的状态如果无法打开页面在终端输入jenkins再试

注:如果打不开,检测一下自己Mac上有没有安装Java环境(jdk:jdk-8u40-macosx-x64.dmg,jre:Java for Mac OS X)

第二步:我们需要下载相关插件:Post-Build Script Plug-in (负责脚本执行)、Xcode integration (负责Xcode相关管理)、Subversion Plug-in(SVN)可根据自己需求来下载相关插件,具体添加可以这样操作:

zidongdabao01

第三步:创建我们的项目,新建 -> Item名称(选择构建一个自由风格的软件项目),进入项目后选择源码管理:我是用的SVN 所以选择Subversion,然后关联项目的SVN 地址,然后添加用户。

zidongdabao04

第四步:下面选择构建:Xcode(提示:这个是CocoaPods版,普通项目参考网上其他帖子)

xcode配置1

xcode配置2

xcode配置3

这样就完成了自动打包的基本程序

接下来可以选择将打好的ipa传到FTP或者发邮件

发送邮件个人推荐使用:Email Extension Plugin可以自定义邮件内容,配置如下

邮件配置1

邮件配置2

第二个比较重要,其他的可以根据自己的需求来自定义添加功能,以上就是jenkins自动打包的步骤