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自动打包的步骤

iOS Apple Pay 功能集成(OC)

Apple Pay 这个功能想必大家也不陌生,现在也已经有app逐渐支持apple pay了,所以我在此写一篇OC集成的文章,供大家分享。

因为涉及到支付,所以要在项目中把相关功能打开

apple pay 01

第一次打开可能会报错:没有有效的Merchant ID。这时候你需要去开发者中心创建Merchant ID。如下:

apple pay 02

创建好就会是这样:

apple pay 03

然后回到你项目中刷新一下就会出现对应的证书。选中即可。

接下来我们回到代码中,首先包含#import <PassKit/PassKit.h>

然后集成PKPaymentAuthorizationViewControllerDelegate,因为需要接受支付后的回调信息。

我们在新项目中可以先创建一个支付按钮:PKPaymentButton,它有很多类型,依据各人喜好来展示。然后添加一个支付方法,接下来就是核心代码了:

在方法里我们要先支付该设备是否支持apple pay 支持哪几种支付:

[PKPaymentAuthorizationViewController canMakePaymentsUsingNetworks:]

判断用户的硬件是否支持Apple Pay或者是否因为家长控制而不能支付,请使用canMakePayments 方法。

注:在支付之前要注意是否支持该网络支付还是要用canMakePaymentsUsingNetworks来判断一下,如果不支持就换其他支付吧。

可以进行支付后我们要创建一个支付请求:

PKPaymentRequest *request = [[PKPaymentRequest alloc] init];
// merchantIdentifier需要与你之前创建的Merchant ID相匹配
request.merchantIdentifier = @"merchant.com.paydemo.appleplay";
// 国家代码
request.countryCode = @"CN";
// 货币代码
request.currencyCode = @"CHW";
// 能支付的币种
request.supportedNetworks = @[PKPaymentNetworkChinaUnionPay];
// 询问你的付款处理器 (PKMerchantCapabilityCredit 信用卡,PKMerchantCapabilityDebit 借记卡)
request.merchantCapabilities = PKMerchantCapabilityCredit; 
// 要显示的表单信息 
PKPaymentSummaryItem *testSummaryItem1 = [PKPaymentSummaryItem summaryItemWithLabel:@"PaymentSummaryItem1" amount:[NSDecimalNumber decimalNumberWithString:@"22.99"] type:PKPaymentSummaryItemTypeFinal]; PKPaymentSummaryItem *testSummaryItem2 = [PKPaymentSummaryItem summaryItemWithLabel:@"PaymentSummaryItem2" amount:[NSDecimalNumber decimalNumberWithString:@"2.99"] type:PKPaymentSummaryItemTypeFinal]; PKPaymentSummaryItem *testSummaryItem3 = [PKPaymentSummaryItem summaryItemWithLabel:@"PaymentSummaryItem3" amount:[NSDecimalNumber decimalNumberWithString:@"3.99"] type:PKPaymentSummaryItemTypeFinal]; 
// 需要计算总价 
PKPaymentSummaryItem *total = [PKPaymentSummaryItem summaryItemWithLabel:@"total" amount:[NSDecimalNumber decimalNumberWithString:@"29.97"] type:PKPaymentSummaryItemTypeFinal]; request.paymentSummaryItems = @[testSummaryItem1,testSummaryItem2,testSummaryItem3,total];
//增加联系邮箱及送货地址信息
request.requiredShippingAddressFields = PKAddressFieldAll;

接下来我们直接创建出支付的页面

PKPaymentAuthorizationViewController *author = [[PKPaymentAuthorizationViewController alloc] initWithPaymentRequest:request];

author.delegate = self;
if (author) {
    [self presentViewController:author animated:YES completion:nil];
}

以上代码就是进行apple pay 支付的代码,期间还可以加入自己想添加的售价信息,例如折扣等。剩下就是回调处理部分了

#prama mark 此方法是用户确认付款方式后通过此方法我们来进一步连接服务器并上传支付令牌和用户的付款信息,我们可以在completion里面来判断是是否成功
- (void)paymentAuthorizationViewController:(PKPaymentAuthorizationViewController *)controller didAuthorizePayment:(PKPayment *)payment completion:(void (^)(PKPaymentAuthorizationStatus))completion
#prama mark 此方法是支付回调后需要进行的操作
- (void)paymentAuthorizationViewControllerDidFinish:(PKPaymentAuthorizationViewController *)controller
{
    [controller dismissViewControllerAnimated:YES completion:nil];
}

以上就是个人理解的apple pay ,希望能和大家一起讨论

iOS 微信支付集成

首先需要去微信开放平台下载ios 所需SDK

然后导入,在AppDelegate里面注册微信:

#import "WXApi.h"
[WXApi registerApp:@"xxxxxx" withDescription:@"xxxxx"];

其次包含微信delegate :WXApiDelegate

关键部分调用微信支付功能:

PayReq *request = [[PayReq alloc] init];
request.partnerId = @"10000100";
request.prepayId= @"1101000000140415649af9fc314aa427";
request.package = @"Sign=WXPay";
request.nonceStr= @"a462b76e7436e98e0ed6e13c64b4fd1c";
request.timeStamp= 1270147801;
request.sign= @"582282D72DD2B03AD892830965F428CB16E7A256";
[WXApi sendReq:request];

在设置delegate的地方写出回调方法(微信支付回到app调用此方法判断是否支付成功):

-(void) onResp:(BaseResp*)resp

核心代码基本就是这些。

注:我们可能会遇到一个很棘手的问题就是调用微信支付时,跳转到微信只要一个确定按钮,然后点击就调回自己的app,可能因为:appid尚未开通支付功能,服务器返回的时间戳是12位(出现几率较大,因为安卓是12位的,我们这必须要10位),服务器sign拼接错误。

以上就是微信支付相关的功能,与问题总结

学会制怒

我们来看那些号称“哎呦,我这暴脾气!”的人,他们是这么想的,你惹我了,我就要冲你发火,否则我就是懦弱的,好欺负的,只有把火发出来了,我才舒服,至于那个“受气包”,活该,谁让你惹我的。

有这样的一对情侣,一起去看电影,期间一个工作人员去倒垃圾的时候,不小心让垃圾桶碰到了女主,女主当场发飙,注意,不是冲着工作人员,而是她的男友,因为她认为男友没有为她出头责问那个工作人员,甚至没有表现出来一点愤怒,你真是一个窝囊废,骂完男友,她找到那个工作人员继续发火,恰好,那个工作人员也不是一个省油的灯,他们互相对骂,女友脸色通红,呼吸急促,最后就差没有扭打起来,后来的事情是影院经理出面调停道歉,然后女主“得胜而回”,路上对着男友一阵数落,男友忍不住回了句,电影也没看成,衣服还是要洗,就这么吵一架有必要么?这下可好,刚刚平息怒气的女主再次当街发飙…… 继续阅读“学会制怒”

git 常用命令

查看、添加、提交、删除、找回,重置修改文件

git help <command> # 显示command的help

git show # 显示某次提交的内容 git show $id

git co — <file> # 抛弃工作区修改

git co . # 抛弃工作区修改

git add <file> # 将工作文件修改提交到本地暂存区

git add . # 将所有修改过的工作文件提交暂存区

git rm <file> # 从版本库中删除文件

git rm <file> –cached # 从版本库中删除文件,但不删除文件

git reset <file> # 从暂存区恢复到工作文件

git reset — . # 从暂存区恢复到工作文件 继续阅读“git 常用命令”

iOS-自带二维码集成

关于苹果自带二维码扫描和生成代码如下:

// 以下为二维码读取部分(github):

#import <AVFoundation/AVFoundation.h>
@property (strong, nonatomic) AVCaptureSession *session;
@property (strong, nonatomic) AVCaptureVideoPreviewLayer *previewLayer;
#pragma mark - 读取二维码
- (void)readQRCoder
{
    // 1. 摄像头设备
    AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
    // 2. 设置输入
    // 因为模拟器是没有摄像头的,因此在此最好做一个判断
    NSError *error = nil;
    AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:device error:&error];
    if (error) {
        NSLog(@"没有摄像头-%@", error.localizedDescription);
        return;
    }
    // 3. 设置输出(Metadata元数据)
    AVCaptureMetadataOutput *output = [[AVCaptureMetadataOutput alloc] init];
    // 3.1 设置输出的代理
    // 说明:使用主线程队列,相应比较同步,使用其他队列,相应不同步,容易让用户产生不好的体验
    [output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
    // 4. 拍摄会话
    AVCaptureSession *session = [[AVCaptureSession alloc] init];
    // 添加session的输入和输出
    [session addInput:input];
    [session addOutput:output];
    // 4.1 设置输出的格式
    // 提示:一定要先设置会话的输出为output之后,再指定输出的元数据类型!
    [output setMetadataObjectTypes:@[AVMetadataObjectTypeQRCode]];
    // 5. 设置预览图层(用来让用户能够看到扫描情况)
    AVCaptureVideoPreviewLayer *preview = [AVCaptureVideoPreviewLayer layerWithSession:session];
    // 5.1 设置preview图层的属性
    [preview setVideoGravity:AVLayerVideoGravityResizeAspectFill];
    // 5.2 设置preview图层的大小
    [preview setFrame:self.view.bounds];
    // 5.3 将图层添加到视图的图层
    [self.view.layer insertSublayer:preview atIndex:0];
    self.previewLayer = preview;

    // 6. 启动会话
    [session startRunning];
    self.session = session;
}
#pragma mark - 输出代理方法
// 此方法是在识别到QRCode,并且完成转换
// 如果QRCode的内容越大,转换需要的时间就越长
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection
{
    // 会频繁的扫描,调用代理方法
    // 1. 如果扫描完成,停止会话
    [self.session stopRunning];
    // 2. 删除预览图层
    [self.previewLayer removeFromSuperlayer];
    NSLog(@"%@", metadataObjects);
    // 3. 设置界面显示扫描结果
    if (metadataObjects.count > 0) {
        AVMetadataMachineReadableCodeObject *obj = metadataObjects[0];
        // 提示:如果需要对url或者名片等信息进行扫描,可以在此进行扩展!
        _label.text = obj.stringValue;
    }
}

// 以下为二维码生成部分(github)

#import <CoreImage/CoreImage.h>
// 1. 实例化一个滤镜
CIFilter *filter = [CIFilter filterWithName:@"CIQRCodeGenerator"];
// 1.1 设置filter的默认值
// 因为之前如果使用过滤镜,输入有可能会被保留,因此,在使用滤镜之前,最好设置恢复默认值
[filter setDefaults];
// 2. 将传入的字符串转换为NSData
NSData *data = [@"http://www.baidu.com" dataUsingEncoding:NSUTF8StringEncoding];
// 3. 将NSData传递给滤镜(通过KVC的方式,设置inputMessage)
[filter setValue:data forKey:@"inputMessage"];
// 4. 由filter输出图像
CIImage *outputImage = [filter outputImage];
// 5. 将CIImage转换为UIImage
UIImage *qrImage = [UIImage imageWithCIImage:outputImage];