iOS开发进阶观后-下篇(注意问题篇)
简介
- 本篇主要内容是实际开发中的思考总结,分别从安全性、UIWebview/WKWebview、脚本处理、内购、动态字库、其他等方面说,其中其他部分设备比较广,但实际使用相对较小或较基础。还会说说对APP持续化概念。
前言
-
由于篇幅问题,会分三篇描述对应不同内容。辅助工具,底层原理,开发中要注意问题三个方面,谈谈对应的总结。本人觉得书只是一个索引,特别对于技术类书籍,基本都是通过书籍引入一些观点,然后在通过其它第三方途径进行扩展。所以本文描述内容不一定就是书本内容,会与自身实践经验,还有部分内容精简和拓展。有些基础概念第三方描述已足够详细,实例也足够详细,本文仅仅提出一些个人总结理解,不在重复描述具体功能原理。
-
文字不如图片直观,所以先上一张本系列描述的观点的思维导图,梳理脉络。红色部分为本文内容梳理。
安全性
1 网络安全性
-
https 通信协议的加密 《HTTPS连接过程及证书自定义认证》 这篇是之前做ssl加密认证总结的。
-
URL加密,主要针对get/put/del.后端交互可以用aes,h5可以用base64.
-
内容加密,主要针对post.json采用AES加密,app与后端同用一套加密发送前加密,到后端解密。返回过程也是。
-
出于安全性,我是觉得用post代替所有协议更加好,但是效率上post会比get低。《post和get 请求区别+原理》
2 本地安全性
-
还有各种第三库TMDiskCache,FDMB,YYCache,这些都是基于文件的所以当沙盒被破时加密性会大大下降。
-
而Keychain适合存需要加密的信息,如金钱的,账号的,积分的等等。。。。
UIWebview/WKWebview (这里主要是UIWebview)
1 JS语言特性
-
解释性脚本语言,javascript不需要编译,只需要嵌入到html代码中,由浏览器逐行加载解释执行。
-
javascript是一种基于对象的语言,使用已经创建好的对象来,和面向对象的先锋需设计语言不同,javascript并不支持继承和重载。
-
语言简单,弱类型,语法和java,C语言类似,变量不需要声明和指定类型即可使用,是一种弱类型语言。
-
最重要的特点就是只有2点单线程,并且都是异步处理的。
2 同步异步/UI线程阻塞
- UIWebview的stringByEvaluatingJavaScriptFromString是一个同步方法,会等待js方法执行完成,耗时操作建议利用js异步特点,全部使用setTimeout的function中,以加快回调结束。
//oc
NSString *jsStr = [NSString stringWithFormat:@"setLocation('%@')",@"广东省深圳市南山区学府路XXXX号"];
[self.webView stringByEvaluatingJavaScriptFromString:jsStr];
//js
function setLocation(location) {
asyncAlert(location);
document.getElementById("returnValue").value = location;
}
function asyncAlert(content) {
setTimeout(function(){
alert(content);
},1);
}
3 混编原理
- 之前也是用UIWebView + 拦截URL 的方式实现的JS与OC 交互。但是,都会封装一层作为app的调用函数,然后基础基类,然而现在的项目,居然是逐个控制器解析url,再单独处理。我觉得是很不科学的。
// js调用
function loadURL(url) {
var iFrame;
iFrame = document.createElement("iframe");
iFrame.setAttribute("src", url);
iFrame.setAttribute("style", "display:none;");
iFrame.setAttribute("height", "0px");
iFrame.setAttribute("width", "0px");
iFrame.setAttribute("frameborder", "0");
document.body.appendChild(iFrame);
// 发起请求后这个iFrame就没用了,所以把它从dom上移除掉
iFrame.parentNode.removeChild(iFrame);
iFrame = null;
}
// oc拦截
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
NSURL *URL = request.URL;
NSString *scheme = [URL scheme];
if ([scheme isEqualToString:@"haleyaction"]) {
[self handleCustomAction:URL];
return NO;
}
return YES;
}
4 WKWebview
-
其实IOS8后可以使用WKWebview代替,效率更高。
-
这里是我总结的《WKWebView 基本使用及与JS交互》
-
这里是前公司的使用总结 《网页交互框架js》
脚本处理
1 持续化集成
-
《手把手教你利用Jenkins持续集成iOS项目》 文章中的xcrun好似在xcode8就开始被废弃看。
-
持续集成指的是,频繁地(一天多次)将代码集成到主干。持续集成的目的,就是让产品可以快速迭代,同时还能保持高质量。它的核心措施是,代码集成到主干之前,必须通过自动化测试。只要有一个测试用例失败,就不能集成。
-
打包脚本以在上篇xcodebulid简述中提供了。
-
方法一,jenken部署mac服务器上,理由jenken定时任务定时部署。
-
方法二,Jenkins跑远程ssh运行打包脚本,然后发布到第三方(蒲公英之类)。
-
神器fastlane工具,这个以后准备了解一下。
2 动态库分离 参考《自建framework提交审核报错 ERROR ITMS-90087解决办法》
-
动态库分离,架构文件分离。
-
增加 Thinned Run Script
APP_PATH="${TARGET_BUILD_DIR}/${WRAPPER_NAME}"
# This script loops through the frameworks embedded in the application and
# removes unused architectures.
find "$APP_PATH" -name '*.framework' -type d | while read -r FRAMEWORK
do
FRAMEWORK_EXECUTABLE_NAME=$(defaults read "$FRAMEWORK/Info.plist" CFBundleExecutable)
FRAMEWORK_EXECUTABLE_PATH="$FRAMEWORK/$FRAMEWORK_EXECUTABLE_NAME"
echo "Executable is $FRAMEWORK_EXECUTABLE_PATH"
EXTRACTED_ARCHS=()
for ARCH in $ARCHS
do
echo "Extracting $ARCH from $FRAMEWORK_EXECUTABLE_NAME"
lipo -extract "$ARCH" "$FRAMEWORK_EXECUTABLE_PATH" -o "$FRAMEWORK_EXECUTABLE_PATH-$ARCH"
EXTRACTED_ARCHS+=("$FRAMEWORK_EXECUTABLE_PATH-$ARCH")
done
echo "Merging extracted architectures: ${ARCHS}"
lipo -o "$FRAMEWORK_EXECUTABLE_PATH-merged" -create "${EXTRACTED_ARCHS[@]}"
rm "${EXTRACTED_ARCHS[@]}"
echo "Replacing original executable with thinned version"
rm "$FRAMEWORK_EXECUTABLE_PATH"
mv "$FRAMEWORK_EXECUTABLE_PATH-merged" "$FRAMEWORK_EXECUTABLE_PATH"
done
3 其他
- 这个就设计到各种其他处理,如图片去重,图片批量压缩等等,也不详细说了。
内购 (简述一些概念,没有具体开发)
1 基本过程
2 校验环境
- 线上包也是采用沙盒验证的,正式验证服返回21007,在验证一次测试服。
3 安全性
- 这里主要就是凭证的安全性问题,因为苹果只有验证凭证合法不合法,与用户无关,如果凭证被盗了,就会导致其他人用了这个凭证,导致金钱丢失。所有建议用Keychain。
动态字库 《动态下载系统提供的多种中文字体》
1 实现
// 1 假如我们现在要下载娃娃体字体,它的PostScript名称为DFWaWaSC-W5。具体的步骤如下:
- (BOOL)isFontDownloaded:(NSString *)fontName {
//判断是否系统支持某种字体
- (BOOL)isFontDownloaded:(NSString *)fontName {
UIFont* aFont = [UIFont fontWithName:fontName size:12.0];
if (aFont && ([aFont.fontName compare:fontName] == NSOrderedSame
|| [aFont.familyName compare:fontName] == NSOrderedSame)) {
return YES;
} else {
return NO;
}
}
// 3 如果该字体下载过了,则可以直接使用。否则我们需要先准备下载字体API需要的一些参数,如下所示:
// 用字体的PostScript名字创建一个Dictionary
NSMutableDictionary *attrs = [NSMutableDictionary dictionaryWithObjectsAndKeys:fontName, kCTFontNameAttribute, nil];
// 创建一个字体描述对象CTFontDescriptorRef
CTFontDescriptorRef desc = CTFontDescriptorCreateWithAttributes((__bridge CFDictionaryRef)attrs);
// 将字体描述对象放到一个NSMutableArray中
NSMutableArray *descs = [NSMutableArray arrayWithCapacity:0];
[descs addObject:(__bridge id)desc];
CFRelease(desc);
// 4 准备好上面的descs变量后,则可以进行字体的下载了,代码如下:
__block BOOL errorDuringDownload =NO;
CTFontDescriptorMatchFontDescriptorsWithProgressHandler( (__bridge CFArrayRef)descs,NULL, ^(CTFontDescriptorMatchingState state, CFDictionaryRef progressParameter) {
double progressValue = [[(__bridge NSDictionary *)progressParameter objectForKey:(id)kCTFontDescriptorMatchingPercentage] doubleValue];
if (state == kCTFontDescriptorMatchingDidBegin) {
NSLog(@"字体已经匹配");
} elseif (state == kCTFontDescriptorMatchingDidFinish) {
if (!errorDuringDownload) {
NSLog(@"字体%@下载完成", fontName);
}
} elseif (state == kCTFontDescriptorMatchingWillBeginDownloading) {
NSLog(@"字体开始下载");
} elseif (state == kCTFontDescriptorMatchingDidFinishDownloading) {
NSLog(@"字体下载完成");
dispatch_async( dispatch_get_main_queue(), ^ {
// 可以在这里修改UI控件的字体
});
} elseif (state == kCTFontDescriptorMatchingDownloading) {
NSLog(@"下载进度 %.0f%% ", progressValue);
} elseif (state == kCTFontDescriptorMatchingDidFailWithError) {
NSError *error = [(__bridge NSDictionary *)progressParameter objectForKey:(id)kCTFontDescriptorMatchingError];
if (error !=nil) {
_errorMessage = [error description];
} else {
_errorMessage = @"ERROR MESSAGE IS NOT AVAILABLE!";
}
// 设置标志
errorDuringDownload = YES;
NSLog(@"下载错误: %@", _errorMessage);
}
return (BOOL)YES;
});
2 利弊
-
这种下载不是下载到app是二下载到一个系统公共目录(/private/var/mobile/Library/Assets/com_apple_MobileAsset_Font/)所有APP都可以用的。
-
节省空间,一个字符要10-20M以上。
其他
1 CoreText
- 这个书中是类比UIwebview,HybridApp是APP趋势,所以个这部分用UIwebview/WKWebview代替就好,所有也没特别细看这部分。
2 UIwindow
- 《OS开发UI篇—UIWindow简单介绍》
- 其实这部分比较适用之前金币引导功能。
3 开发技巧、调试技巧、审核技巧
- 书中描述的也是比较基础的内容工具使用,基本上几年开发经验都会用到,这里也不细说了。