1.定位问题(在使用之前一定要在info.plist里设置权限哦)
// 导包
#import <CoreLocation/CoreLocation.h>
// 在.m里设置一个变量
/**
定位管理
*/
@property(nonatomic ,strong) CLLocationManager *manager;
定位配置
_manager = [[CLLocationManager alloc] init];
_manager.delegate = self;
// [manager requestAlwaysAuthorization];
[_manager requestWhenInUseAuthorization];
_manager.desiredAccuracy = kCLLocationAccuracyBest;
_manager.distanceFilter = 1.0;
[_manager startUpdatingLocation];
pragma mark -- CLLocationManagerDelegate
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations {
CLLocation *currentLocation = [locations lastObject];
//地理反编码 可以根据坐标(经纬度)确定位置信息(街道 门牌等)
CLGeocoder *geoCoder = [[CLGeocoder alloc]init];
[geoCoder reverseGeocodeLocation:currentLocation completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
if (placemarks.count >0) {
CLPlacemark *placeMark = placemarks[0];
NSString *currentCity = placeMark.locality;
if (!currentCity) {
currentCity = @"无法定位当前城市";
}
// 考虑到定位的频繁性,在一开始没有值的时候才刷新表格
if (self.location.length <= 0) {
// 省 + 市 + 区
self.location = [NSString stringWithFormat:@"%@%@%@",placeMark.administrativeArea,currentCity,placeMark.subLocality];
[self.tableView reloadData];
}
}
}];
}
2.在使用IQKeyboardManager,使用UITableViewController有bug没办法处理,用到tableView,针对输入框键盘弹出挡住了Cell的处理
// 注册通知
- (void)registerForKeyboardNotifications {
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillBeHidden:) name:UIKeyboardWillHideNotification object:nil];
}
// 通知方法
- (void)keyboardWillShow:(NSNotification *)aNotification {
NSDictionary* info = [aNotification userInfo];
// 注意不要用UIKeyboardFrameBeginUserInfoKey,第三方键盘可能会存在高度不准,相差40高度的问题
CGSize kbSize = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
if (_insertIndexPath.section > 0) {
// 修改滚动天和tableView的contentInset
self.tableView.contentInset = UIEdgeInsetsMake(0, 0, kbSize.height, 0);
self.tableView.scrollIndicatorInsets = UIEdgeInsetsMake(0, 0, kbSize.height, 0);
// 跳转到当前点击的输入框所在的cell
[UIView animateWithDuration:0.5 animations:^{
[self.tableView scrollToRowAtIndexPath:_insertIndexPath atScrollPosition:UITableViewScrollPositionTop animated:NO];
}];
}
}
- (void)keyboardWillBeHidden:(NSNotification *)aNotification {
self.tableView.contentInset = UIEdgeInsetsZero;
self.tableView.scrollIndicatorInsets = UIEdgeInsetsZero;
}
3.扫描条形码的方法
1.使用的框架 #import <LBXScanViewController.h>
2.使用这个的注意事项,因为我这边想要扫描二维码条形码都可以的情况,本来想要直接拖项目,但是发现这个项目用了retain,release方法,所以用pod导入的,导入的方式如下:
pod 'LBXScan/LBXZXing','~> 2.3'
pod 'LBXScan/UI','~> 2.3'
3.写了个控制器继承这个方法
#import <LBXScanViewController.h>
@interface DIYScanViewController : LBXScanViewController
@end
4.使用这个控制器
-(void)scannerClick{
[self.view endEditing:YES];
// CocoaPods的版本库是有缓存的, 但在使用pod指令更新版本库时会出现冲突, 导致更新并不能如期完成, 需要手动删除本地缓存, 再进行更新。
//
// 解决方法:
//
// $ sudo rm -fr ~/.cocoapods/repos/master
// $ pod setup
//
// 之后重新 pod install 顺利通过
// Note: as of CocoaPods 1.0, `pod repo update` does not happen on `pod install` by default.
DIYScanViewController *scanVc = [DIYScanViewController new];
// 这个要定义LBXScan_Define_UI才能用
scanVc.style = [self ZhiFuBaoStyle];
scanVc.isOpenInterestRect = YES;
scanVc.libraryType = SLT_ZXing;
WK(weakSelf);
scanVc.scannerCallBack = ^(NSString *scanStr) {
weakSelf.express = scanStr;
weakSelf.inputF.text = weakSelf.express;
[weakSelf pipeiExpress:self.pipeiBtn];
};
[self.navigationController pushViewController:scanVc animated:YES];
}
- (LBXScanViewStyle*)ZhiFuBaoStyle
{
//设置扫码区域参数
LBXScanViewStyle *style = [[LBXScanViewStyle alloc]init];
style.centerUpOffset = 60;
style.xScanRetangleOffset = 30;
if ([UIScreen mainScreen].bounds.size.height <= 480 )
{
//3.5inch 显示的扫码缩小
style.centerUpOffset = 40;
style.xScanRetangleOffset = 20;
}
style.photoframeAngleStyle = LBXScanViewPhotoframeAngleStyle_Inner;
style.photoframeLineW = 2.0;
style.photoframeAngleW = 16;
style.photoframeAngleH = 16;
style.isNeedShowRetangle = NO;
style.anmiationStyle = LBXScanViewAnimationStyle_NetGrid;
style.notRecoginitonArea = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.6];
//使用的支付宝里面网格图片
UIImage *imgFullNet = [UIImage imageNamed:@"CodeScan.bundle/qrcode_scan_full_net"];
style.animationImage = imgFullNet;
return style;
}
5.这里提到一个"定义",所以要在一个通用的文件里进行定义:
#define LBXScan_Define_ZXing //下载了ZXing模块
#define LBXScan_Define_UI //下载了界面模块
4.分享里如果跳转的是自己app的配置
要在info里配置scheme
配置scheme.png
然后测试的话,就在浏览器里输入paproperty://,看是否能进入即可
这是在测试分享点击的时候我进行的调试,如果不能,就跳到苹果商店这样子的分析
5.针对图片比较大,我如何获取图片的高度
图片尺寸配置.png由于我这里有个类似商城的项目,详情展示的是商品的大图,由于大图是网络图片,只有一个链接,我参考之前做百思不得姐的demo的时候,它有一个高度值,但是这里却没有,我问后端有没有获取,没有的时候,我不知道该怎么办,我求助师父,它的代码告诉我,sd_webImage这个框架是真的很强力:
// 设置照片view
UIView *photoView = [[UIView alloc] init];
CGFloat tempH = 100;
NSInteger i = 0;
for (PALMPicturePicList *picList in self.pics) {
UIImageView *imageView = [[UIImageView alloc] init];
imageView.backgroundColor = [UIColor colorWithWhite:0 alpha:0.6];
imageView.frame = CGRectMake(0, i * tempH, [UIScreen mainScreen].bounds.size.width, tempH);
imageView.contentMode = UIViewContentModeScaleAspectFill;
imageView.clipsToBounds = YES;
[photoView addSubview:imageView];
[imageView sd_setImageWithURL:[NSURL URLWithString:picList.picUrl] completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
if (image) {
CGRect imageViewF = imageView.frame;
CGFloat whScale = image.size.width / image.size.height;
imageViewF.size.height = imageViewF.size.width / whScale;
imageView.frame = imageViewF;
[self updatePhotoView];
}
}];
i ++;
}
[self.scrollView addSubview:photoView];
self.photoView = photoView;
6.附上我常写的展示图片的方法
// 导包
#import <UIImageView+WebCache.h>
#import "MJPhotoBrowser.h"
#import "MJPhoto.h"
配置
#pragma mark -- 商品详情的评价区域
-(void)setupImageView:(NSInteger)count{
for (UIImageView *imgView in self.picView.subviews) {
[imgView removeFromSuperview];
}
int maxColumns = 3;
CGFloat IWPhotoMargin = 10;
CGFloat IWPhotoW = (kScreenW - IWPhotoMargin * 2 - 13 - 59)/3;
CGFloat IWPhotoH = IWPhotoW;
// 初始化9个子控件
for (int i = 0; i<count; i++) {
UIImageView *photoView = [[UIImageView alloc] init];
photoView.userInteractionEnabled = YES;
photoView.tag = i + 100;
// 设置图片链接(这里可能传的是一个模型,不一定是个简单的url字符串)
PALMCommentsPicList *picList = self.pics[i];
NSURL *url = [NSURL URLWithString:picList.picUrl];
[photoView sd_setImageWithURL:url placeholderImage:[UIImage imageNamed:@"shequdefault"]];
[photoView addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(photoTap:)]];
// 设置子控件的frame
int col = i % maxColumns;
int row = i / maxColumns;
CGFloat photoX = col * (IWPhotoW + IWPhotoMargin);
CGFloat photoY = row * (IWPhotoH + IWPhotoMargin);
photoView.frame = CGRectMake(photoX, photoY, IWPhotoW, IWPhotoH);
[self.picView addSubview:photoView];
}
}
- (void)photoTap:(UITapGestureRecognizer *)recognizer
{
//确定photo的张数
NSInteger count = self.pics.count;
// 1.封装图片数据
NSMutableArray *myphotos = [NSMutableArray arrayWithCapacity:count];
for (int i = 0; i<count; i++)
{
// 一个MJPhoto对应一张显示的图片
MJPhoto *mjphoto = [[MJPhoto alloc] init];
// 告诉URL,来源于哪个UIImageView(目的:点击这个图片变大之后,再点击要还原到那个位置)
mjphoto.srcImageView = self.picView.subviews[i];
// 设置图片链接(这里可能传的是一个模型,不一定是个简单的url字符串)
PALMCommentsPicList *picList = self.pics[i];
mjphoto.url = [NSURL URLWithString:picList.picUrl]; // 图片路径
[myphotos addObject:mjphoto];
}
// 2.显示相册
MJPhotoBrowser *browser = [[MJPhotoBrowser alloc] init];
browser.currentPhotoIndex = recognizer.view.tag - 100; // 弹出相册时显示的第一张图片是?
browser.photos = myphotos; // 设置所有的图片
[browser show];
}
7.上线遇到的麻烦
上线的屏幕尺寸.jpg遇到过,就是苹果开发者里显示的可供销售,但是app商城就是查不到,此时可以考虑修改价格和销售范围,然后再改回来,如果还是不行,那就只能干等,至于等待多久,我暂时找不到答案了。
8.内购(待续)
注意点.png这里需要注意的是,CNAPS代码里,进行银行搜索的时候,银行,所在地址,都要输入英文,然后银行的地址也写的比较麻烦,我也是搜索了很久才搜索到,特别是用邮编定位的时候,大家虽然都知道武汉的邮编是430000,但是集合太大,可以搜索到很多的银行,然而开户的位置就只有那一家,所以在这里花费了不少功夫,所以目前情况,要么问银行工作人员,要么就是找到一个比较精确的地址,然后去分析,由于地址列表都是英文,所以得借助下翻译,要搞清楚自己在哪个地区,毕竟武汉那么大,硚口区,武昌区,东西湖区。。。。
然后账户持有人姓名,这里是要输入英文的,输入中文是不作数的
报税表什么的,其实就没什么了,就是按照苹果的协议,选择公司所需求的即可,然后工作人员的信息的话,可以全部只填写一个人,也没什么大问题,然后后续就是价格的配置
通过appstoreConnect->我的app,找到需要写价格的app,如图
项目.png
点击加号即可增加商品,下方的列表就是我配置的商品,其中产品ID要设计明确,这个id根据后续自己的设计的产品的id息息相关的,要注意,设计的办法可以"xxxxx_产品的价格",比方说10元的爱心豆,即"lovebean_10"
这里的参考名称相当于标记,没有什么可以参考的
点击添加按钮展示的菜单,要注意的:
appStore信息.png
这里本地化版本就是,要展示给用户看的,描述的是到后来你在布置模型里一个叫skproduct的模型里的一个参数,显示名称这个是给用户看的,很有必要
审核图片标准.png这里就需要美工切一张图片给我们了,审核的备注的话,写一些备注信息就可以了,然后提交只有只有是“准备提交”,那才算是设置好,不然就去查看下为何设置错误了
添加沙箱测试人员.png在这里添加沙箱测试人员,注意里面的邮箱是没有在苹果里注册的,密码也需要牢牢记住,后续内购支付里派上用场的,因为不可能一直用自己的账户进行测试,这钱流的杠杠的,也不能在配置金额里手动输入一毛钱,所以得配置一个沙盒的账号进行内购测试
此时前奏配置已经完成,后续就是打开xcode把这个打开
purchase.png
导包#import <StoreKit/StoreKit.h>
然后就是要注意的细节了
细节1,就是要跟后端配合,后端准备的价格和商品,要跟我在苹果里设置的要一一对应,一一添加,比方说我配置了“1,3,6,12,18,30”元的商品,后端也要这么配置,而且按价格顺序配置,我这边需要做的就是根据价格,然后设计一个数组依次添加,我们之前不是设置了一个商品id么?这时候作用就出来了
前缀是我们的“xxx_” 后缀是价格,""这么一拼接,就是添加的id了
值得注意的是,即便这么添加然后发送请求的时候
// 能够销售的商品
NSSet *set = [[NSSet alloc] initWithArray:products];
// "异步"询问苹果能否销售
SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:set];
request.delegate = weakSelf;
// 启动请求
[request start];
会发现产品的数组是个乱序,所以要在代理方法里进行一次排序,保证顺序是产品需求的样式,跟后端进行一一比对
#pragma mark -- SKProductsRequestDelegate
/**
获取内购商品的请求(请求苹果服务器,所以会很慢)
*/
-(void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response{
// 获取内购商品的请求
if (self.productDict == nil) {
self.productDict = [NSMutableDictionary dictionaryWithCapacity:response.products.count];
}
NSMutableArray *productArray = [NSMutableArray array];
// 按照价格进行排序
NSArray *sorctProducts = [response.products sortedArrayUsingComparator:^NSComparisonResult(SKProduct *obj1, SKProduct *obj2) {
return [obj1.price compare:obj2.price];//升序
}];
for (SKProduct *product in sorctProducts) {
[self.productDict setObject:product forKey:product.productIdentifier];
// 按照价格进行排序
[productArray addObject:product];
}
if ([self.delegate respondsToSelector:@selector(IAPToolGotProducts:ChargeData:)]) {
[self.delegate IAPToolGotProducts:productArray ChargeData:self.chargeData];
}
}
最后就是逻辑上的注意了,因为内购是给苹果服务器发送内购消息,所以请求的时间上会很卡,而且内购成功之后也需要跟后端进行订单校验,只有成功了才会把爱心豆加到用户的账户。。
所以会出现一些漏单操作(比方说用户第一次绑定支付宝,可能会默认内购失败,比方说在拿着内购验签的时候,内购成功了,但是服务器请求失败了的操作)
处理的方式的话,就要在这个代理方法里分析,到底漏单的环节在哪里
#pragma mark -- SKPaymentTransactionObserver
/**
* 监测购买队列的变化(订单的成功,失败与取消都会在这里产生)
*
* @param queue 队列
* @param transactions 交易
*/
-(void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(nonnull NSArray<SKPaymentTransaction *> *)transactions{
// 处理结果
for (SKPaymentTransaction *transaction in transactions) {
ZRLog(@"队列状态变化 %@", transaction);
// 队列状态发生了错误
if (transaction.error) {
[self showErrorTipWith:transaction.error.localizedDescription andStyle:SVProgressHUDStyleDark];
return ;
}
// 如果小票状态是购买完成
if (transaction.transactionState == SKPaymentTransactionStatePurchased) { // 购买完成(销毁交易)
[self showLoadingWihtBlackBackgroundAndString:@"加载中..." andMaskType:SVProgressHUDMaskTypeBlack];
if (self.CheckAfterPay) {// 需要向苹果验证凭据
// 验证购买凭据
[self verifyPruchaseWithID:transaction];
}else{// 不需要向苹果服务器验证
}
[self showDisminss];
// 将交易从交易队列中删除
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
} else if (transaction.transactionState == SKPaymentTransactionStateRestored) { // 恢复购买(销毁交易)
[self showDisminss];
// 恢复已经完成的所有交易.(仅限永久有效商品)
// 将交易从交易队列中删除
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}else if (transaction.transactionState == SKPaymentTransactionStateFailed){ // 购买失败(销毁交易)
[self showErrorTipWith:@"购买失败" andStyle:SVProgressHUDStyleDark];
// 将交易从交易队列中删除
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
[self showDisminss];
#pragma mark -- 由于目前只监听支付成功然后我校验的回调,所以这里没有接口处理
// 删除本地订单数据
[PAInPurchaseTool successConsumptionOfGoodsWithOrderNo:transaction.transactionIdentifier];
}else if (transaction.transactionState == SKPaymentTransactionStatePurchasing){ // 正在购买
[self showLoadingWihtBlackBackgroundAndString:@"正在购买中..." andMaskType:SVProgressHUDMaskTypeBlack];
ZRLog(@"商品正在准备购买中...");
}else if (transaction.transactionState == SKPaymentTransactionStateDeferred){ // 交易延迟
ZRLog(@"购买交易延迟");
[self showDisminss];
// 将交易从交易队列中删除
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}
}
}
在这里找到购买的逻辑,以上代码都是只展示逻辑,不能用在自己其他项目直接拷贝的
我这里也做了标记,就是监听成功回调,其他的都不会请求后端了
所以就放在购买成功里的服务器校验
目前的方法是:
我在请求之前,我先跟苹果端的校验一次,然后成了之后,把这个订单根据一个重要的主键(我这里选择的是账单的订单号),保存到本地,然后再请求服务器进行校验,如果请求成功,且结果返回是需要的,那么就刷新爱心豆,反之都算漏单,然后再次启动app的时候调用恢复单据的接口,我设置的是每20秒调用一次
就是这样子的设计方法
网友评论