DragonFly的博客

我曾七次鄙视自己的灵魂


  • 首页

  • 分类

  • 标签

  • 归档

我的2017年年终总结

发表于 2017-12-31 |

2017年的最后一天,想说的很多,下笔却感觉很是惶恐,一年从头到尾,开始的时候信心满满,到年终却又感觉很多想做的事没有完成。细细回想起来,年年如此。
不过一年里也算完成了一部分自己的规划,且学且行,不管从工作上还是个人成长,都有一些收获。

工作方面
作为一只程序猿,本职工作就是完成产品需求,当然不能局限自己在简单的完成工作上,还需要在业务层面帮助优化产品体验和产品流程,在技术层面提出可行性的方案,解决、跟踪和预防未来可能存在的问题,这需要从产品的规划以及公司的角度来思考,并且在技术层也要多维度思考,比如产品性能、所需资源、后续维护成本等,在本职工作的基础上,提供最合适的解决方案。这一年的工作里,慢慢的学习、思考了很多,发现自己在面对问题的时候还是有很多欠缺,不过在逐步学习中进步,不再仅仅从纯技术角度来考虑一个问题的解决方法了。

技术方面
这一年从iOS端逐渐向大前端以及全栈方向发展,学习研究和使用了Swift、ReactNative、ES5、Node.js、python等不同的语言框架,前后端都有不同成都的了解和熟悉。目前看来移动端慢慢会趋向于统一、融合,当然iOS不可能完全消失,偏底层、基础的架构还是要用objectiveC、Swift或者C++来实现。但是快速迭代的业务层肯定慢慢向可以快速迭代的前端靠拢,例如新的ReactNative、Weex等技术框架是很好的解决方案,同时旧有的Hybrid的架构还会在很长一段时间内用于拉新、推广、运营等活动。通过学习,目前Swift已经能熟悉使用,ReactNative、Weex前端框架也有一些研究和发掘,还对前端项目的架构和脚手架也做了研究和实践,发现语言和框架很多原则、原理是一致的,重要的是活学活用,不同的场景要考虑不同的方式来应对解决。
此外还研究了一些新技术的应用,包括AR、CoreML等,新技术的出现蕴含的新的机会,面对新技术不能浅尝辄止,需要通过使用、体验来发掘其外来可能性,并与现有业务结合,来创造出新的机会。

个人成长方面
开了博客以来,经常会有一些内容记录下来要总结,但是有时候拖延症犯了,很多文章就被堆积在草稿箱。今年慢慢的把自己之前列好的未完成的一些文章补完,发现欠的债有点多,不过在慢慢填补。总结到记录再到分享是一个循环持续的过程,通过这一个个循环,不仅能沉淀知识,也可以
发现自己一个很大的问题是,很多事情小有成绩就开始沾沾自喜,然后导致后续问题频出。现在都会时时自省,发现问题及时改正,不然会导致虎头蛇尾。

下一年的计划
明天开始,新的一年到来,计划要学习很多知识,技术方面重点有Swift的深入研究、深度学习,还有产品、运营等方向的学习。要把自己持续放在不断学习不断进步的环境中,才不会懈怠。
以前年末,总会暗自总结一番,封案待查,结果发现并不会回去翻看。现在总结发到博客,可以时时翻看,以待后验。逝者如斯夫,不舍昼夜,年终岁末,给过去的一年里的自己点个赞,下一年里继续加油,把握机会,不要犹豫,去努力追求自己想要的。

iOS中的日志同步获取-NSLog重定向及其他

发表于 2017-12-08 |

我们在真机测试时经常会发现一个难题是无法查看真机的NSLog类型的实时日志,这时候需要RD复现问题来定位当时的日志,以方便查找问题。这个问题在测试中是非常常见的,也是功能测试会花费比较长时间的一个原因。以下我们讨论下能即时查看日志的几种方案。

NSLog输出到哪里?

在iOS开发中,我们经常会用到NSLog调试,但是我们却不太了解它。在NSLog本质是一个C函数,它的函数声明如下:
FOUNDATION_EXPORT void NSLog(NSString *format, ...)
系统对它的说明是:Logs an error message to the Apple System Log facility.。他是用来输出信息到标准Error控制台上去的,其内部其实是使用Apple System Log的API。在调试阶段,日志会输出到到Xcode中,而在iOS真机上,它会输出到系统的/var/log/syslog这个文件中。

在iOS中,把日志输出到文件中的句柄在unistd.h文件中有定义:

1
2
3
#define	 STDIN_FILENO	0	/* standard input file descriptor */
#define STDOUT_FILENO 1 /* standard output file descriptor */
#define STDERR_FILENO 2 /* standard error file descriptor */

NSLog输出的是到STDERR_FILENO上,我们可以在iOS中使用c语言输出到的文件的fprintf来验证:

1
2
NSLog(@"iOS NSLog");
fprintf (stderr, "%s\n", "fprintf log");

由于fprintf并不会像NSLog那样,在内部调用ASL接口,所以只是单纯的输出信息,并没有添加日期、进程名、进程id等,也不会自动换行。

阅读全文 »

快速创建ARKit模型-使用MagicaVoxel创建3D模型

发表于 2017-09-30 | 分类于 Tool |

iOS APP尤其是游戏中,还有新发布的ARKit中,2D/3D模型需要花费大量的时间来创建,然而我们开发者开没有那么长时间。
最近发现一款及其简单的模型创建工具-MagicaVoxel,虽然他只能创建体素(Voxel)模型,但是生成的模型可以在ARKit中使用,而且它还是免费的。
下面我们介绍下该软件。

Voxel模型

开始使用

可能你会疑惑体素是什么意思,其实体素类似与像素,像素英文为Pixel,是图片pictures(pix)与元素element(el)俩词组合而来,而体素Voxel则由体积Volumes(vox)与元素element(el)组成。尤其是当你玩过我的世界的话,很快就能理解,里面的模型其实由一个个体素构成,它是一种极其简单、快速创建3D模型的方式。而MagicaVoxel就是一种创建Voxel模型的工具。

你可以从该地址下载MagicaVoxel: https://ephtracy.github.io,然后解压它。
当你在Mac上运行APP发现黑屏时,你需要把MagicaVoxel-mac.app文件移出当前目录,再移动回来,就可以解决黑屏问题。

阅读全文 »

iOS11 DeviceCheck-苹果的微型云服务?

发表于 2017-09-27 | 分类于 iOS |

iOS系统一致以来都致力于保护用户的隐私安全,从UUID到VenderId,再到Mac地址,每个开发者都在探索能跟踪用户和设备的唯一标志符,可惜自从UUID别限制使用以后,到现在还没有一个类似当初UUID的标志符。

不过在iOS11中新增了DeviceCheck的framework,可以允许你通过自己的服务器与Apple服务器通讯,并为单个设备设置(per Device、per Developer)两个bit的数据(bit是计算机表示信息的最小单元,吐槽下真的很小,相当于只能保存两个bool值)。该framework为追踪用户提供了更好的选择,不过目前看来只能存储类似用户是否使用过优惠码的信息,或者当前设备是否涉嫌刷单等欺诈行为。

DeviceCheck 2bits

iOS集成介绍

DeviceCheck使用的基本流程如下:
1.在App内使用DeviceCheck APIs获取一个临时的token来标志该设备(很快会失效)
2.将token传递给后端服务器,随后后端服务器使用该token和认证后的key值(来自Apple的证书请求模块)请求Apple服务器,来更新或查询该设备的值
3.Apple服务器返回后端服务器信息,获取该设备之前存储的信息,包含bits信息和最后一次修改的时间戳

DeviceCheck 流程

在服务端,需要使用Http Post请求来查询和更新信息,每个请求对应的header应该包含认证后的来自Apple的key值(JWT,JSON web token)。要获取该token,可以使用类似Apple推送服务(APNs)的类似流程来操作,具体流程可以参考Communicate with APNs using authentication tokens。

服务端请求的API请参照Accessing and modifying Per-Device Data,数据payload的格式如下图示例:

服务端请求payLoad

Apple API地址:
开发环境: https://api.development.devicecheck.apple.com
线上环境: https://api.devicecheck.apple.com.

请求完整后就可以获取/更新最新的设备信息了,之后可以使用该信息进行业务操作。

API使用

目前发现该API在Swift中无法使用,可能是目前的一个bug。不过可以通过桥oc代码的方式运行在Swift项目中。代码示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
+ (NSString *)getNewDeviceId {
if ([DCDevice.currentDevice isSupported]) {
[DCDevice.currentDevice generateTokenWithCompletionHandler:^(NSData * _Nullable token, NSError * _Nullable error) {
if (error) {
NSLog(@"%@", error.description);
} else {
// upload token to APP server
NSString *deviceToken = [token base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
NSLog(@"%lu %@", token.length, deviceToken);
}
}];
}
return @"";
}
参考
  1. https://developer.apple.com/documentation/devicecheck
  2. https://developer.apple.com/documentation/devicecheck/accessing_and_modifying_per_device_data?changes=latest_minor

iOS混淆-ollvm中添加对String的混淆

发表于 2017-09-18 | 分类于 LLVM |

之前研究ollvm的时候,发现开源的ollvm库中没有对字符串混淆的部分,但是很多APP中都可能会有一些需要加密的字符串。机缘巧合发现上海交大的GoSSIP小组开源了他们设计的基于LLVM4.0的混淆框架,功能包含常量字符串混淆以及ollvm原有的一些功能。该页面有关于他们项目的简介👍。
简单分析发现字符串混淆的部分主要由字符串加密的Pass完成,之后我们考虑把字符串混淆的功能加入ollvm中,所以本文简单介绍下如何将字符串加密的Pass继承到ollvm中。Pass其实可以简单的理解为LLVM优化/转换工作的一个最小单元,可以把所有的混淆工作都是由一个一个Pass组成的,想要做具体的了解,可以看下以下专栏的文章。

Pass集成

首先提取字符串加密文件对应pass文件,该文件所在目录为lib/Transform/Obfuscation。
pass文件目录

阅读全文 »

ARKit中的坐标转化

发表于 2017-09-17 | 分类于 iOS |

多年不摸,线性代数中的矩阵变换早已忘的一干二净,参考网上的资料,做个总结。下面先简单列下图形学的矩阵转化基础,再看它们在ARKit中的应用。

图形学矩阵变换基础

ARKit坐标系

iOS11/iPhoneX最新适配指南

发表于 2017-09-14 | 分类于 iOS |

iPhone发布会前,就隐隐感觉到一波适配工作要袭来的赶脚,果然不出所料。
新版iPhone的适配工作主要集中在iPhoneX上,相信大家已经对iPhoneX的刘海记忆深刻了,除了吐槽,留给我们的还有比较麻烦的适配工作。下面简单分享下在整理过程中发现的适配注意点。(适配工作主要在UI方面,后续发现的适配点会陆续补充到该文档中)

iPhoneX 375x812尺寸图

上下黑边问题

运行新版Xcode的iPhoneX模拟器,你可能发现之前的APP在iPhoneX屏幕没填充满,上下有黑色区域,应该是你的app之前未用LaunchScreen.Storyboard作为启动页面,可以使用LaunchScreen来当做入场页面,这样APP才会自动适配为iPhoneX的大小。或者修改Assets中的LaunchImage,添加iPhoneX的Launch图如下(1125*2436)。

LaunchImage适配

iOS11新增版本判断API

iOS11版本现在有了简单的API,OC也开始支持swfit的@available语法,不用再手写iOS版本判断了。

1
2
3
4
5
6
if (@available(iOS 11.0, *)) {
// 版本适配
}
// 或者
#ifdef __IPHONE_11_0
#endif

目前没发现有iPhoneX的机型判断API,暂时可以使用size来做代替判断。

1
2
3
4
5
#define kDevice_iPhoneX CGSizeEqualToSize(CGSizeMake(375, 812), [[UIScreen mainScreen] bounds].size)
// 或者
if (UIScreen.mainScreen.bounds.size.height == 812) {
NSLog(@"this is iPhone X");
}
阅读全文 »

ARKit-基于Face的AR体验

发表于 2017-09-13 | 分类于 iOS |

Apple昨晚发布了强大但是死贵无比的iPhoneX,惊呆了我们。然后只能默默去刷了下API,发现ARKit新添了基于Face的API。
之前的版本中前置摄像头是不支持AKKit模块的,幸而新发布的版本中添加了对Face识别的支持,然而新的API需要原前置深感摄像头(TrueDepth Camera)的支持,所以看来还得入手一台iPhone X呐。

iPhoneX

新增API

首先新增了ARFaceTrackingConfiguration,以用于追踪用户脸部的运动和表情,并在界面中渲染虚拟内容。此外你还可以设置lightEstimationEnabled为true,来启用脸部扫描并提供预估的定向/环境光。

其次还新增了ARFaceAnchor,这两个新API与之前的ARWorldTrackingConfiguration和ARPlaneAnchor类似,只是基于平面的检测改为了基于Face的检测,恶趣味下Apple会不会继续扩展他的检测API。。。当使用ARFaceTrackingConfiguration时,ARSession会检测用户面部并且用ARFaceAnchor保存面部信息,包括位置、方向、拓扑结构以及表情特征点。

ARFaceAnchor的transform属性描述了面部在世界坐标系中的所在位置和方向,该世界坐标系可以在ARSessionConfiguration的wordlAlignment中设置。可以使用该transform在ARScene检测到的面部上添加虚拟物体。坐标系如下图所示:

ARKit Face coordinate

该坐标系为右手坐标系,x轴只想观察者的右边(即face自己的左边),y轴指向上边(与face绑定),z轴指向了观察者。

ARFaceAnchor的blendShapes属性提供了当前面部表情的高级数据,通过一系列表示面部特征的系数来描述面部表情。你可以使用这些系数跟随用户的面部表情来做2D/3D动画。

阅读全文 »

ARKit 上手指南 02 平面检测

发表于 2017-09-12 | 分类于 iOS |

上一小节中,我们在ARKit虚拟世界中添加了3D物体,接下来我们会使用ARKit检测现实世界的平面。这样我们才能在平面上放置物体以及进行其他操作。

检测平面

如果要在ARKit空间里检测水平面,需要设置ARSessionConfiguration的planeDetection属性为ARPlaneDetectionHorizontal。设置完后,ARSceneView的delegate方法会收到回调。

1
2
3
4
5
6
7
func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
DispatchQueue.main.async {
if let planeAnchor = anchor as? ARPlaneAnchor {
self.addPlane(node: node, anchor: planeAnchor)
}
}
}

每次ARKit认为检测到平面时都会调用该方法,并且返回一个ARAnchor对象,包含当前检测平面锚点,其真正类型是ARPlaneAnchor,拥有extent(范围)、center(中心)等属性信息。

1
2
3
4
5
6
7
8
9
10
open class ARPlaneAnchor : ARAnchor {
// The alignment of the plane.
open var alignment: ARPlaneAnchor.Alignment { get }

// The center of the plane in the anchor’s coordinate space.
open var center: vector_float3 { get }

// The extent of the plane in the anchor’s coordinate space.
open var extent: vector_float3 { get }
}

渲染平面

根据第一步得到的锚点信息,我们可以在ARKit的空间中绘制一个3D平面。创建一个Plance类,继承自SCNNode来管理需要渲染的平面,然后创建SCNGeometry子类SCNPlane的对象,可以用该对象创建平面对应的SCNNode。在构造方法中创建平面并调整其大小:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
init(_ anchor: ARPlaneAnchor) {
...
// 用ARPlaneAnchor的尺寸来创建3D平面几何体
let plane = SCNPlane(width: CGFloat(anchor.extent.x - 0.05), height: CGFloat(anchor.extent.z - 0.05))
let material = SCNMaterial()
material.colorBufferWriteMask = []
material.isDoubleSided = true
plane.materials = [material]

planeNode = SCNNode()
planeNode!.geometry = plane
// SceneKit 里的平面默认是垂直的,所以需要旋转90度来匹配 ARKit 中的平面
planeNode!.transform = SCNMatrix4MakeRotation(-Float.pi / 2.0, 1, 0, 0)
// 将平面plane移动到ARKit对应的位置
planeNode!.position = SCNVector3Make(anchor.center.x, -0.01, anchor.center.z)
}

然后在ARSCNViewDelegate的回调方法中,每次扫描到新的ARAnchor时都可以创建新的平面。

1
2
3
4
5
6
7
8
func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
DispatchQueue.main.async {
if let planeAnchor = anchor as? ARPlaneAnchor {
let plane = Plane(anchor)
node.addChildNode(plane)
}
}
}

更新平面

上述创建渲染的平面只会保持创建时的大小,然后现实世界的平面可能比创建初始化的大很多,若需要更新平面的大小,需要更新平面的extent(范围)值。

可以从ARSCNViewDelegate的代理方法中获取到更新的信息:

1
2
3
4
5
6
7
func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) {
DispatchQueue.main.async {
if let planeAnchor = anchor as? ARPlaneAnchor {
plane.update(anchor)
}
}
}

然后在Plane类的update方法里,更新plane的宽高:

1
2
3
4
5
6
func update(_ anchor: ARPlaneAnchor) {
plane.width = CGFloat(anchor.extent.x - 0.05)
plane.height = CGFloat(anchor.extent.z - 0.05)
// 更新位置
plane.position = SCNVector3Make(anchor.center.x, -0.01, anchor.center.z)
}

ARKit上手指南 01 添加3D物体

发表于 2017-09-08 | 分类于 iOS |

ARKit是2017年6月6日,苹果发布的iOS11系统所新增的框架,它能够帮助我们以最简单快捷的方式实现AR技术功能。而且ARKit框架对基于3D场景(SceneKit)和2D场景(SpriteKit)的增强现实都提供了支持。

开发环境

  1. Xcode版本: Xcode9以上
    Xcode 9 Beta:https://developer.apple.com/download/
    下载最新的beta版本就可以了,不过Xcode需要Mac 10.12.4及以上的版本。
  2. iOS系统: iOS11以上
  3. iOS设备: A9/A10处理器的iOS设备,即iPhone6s、iPad2017及以上的设备

创建项目

首先打开Xcode,选择ARKit模板,如下所示:

AR项目创建

之后,填写完项目信息后,选择Content Technology为SceneKit,当然也可以选择SpriteKit,不过在3D空间中就不是那么立体了。
开发语言选择Swift,Swift天然亲和ARKit,很多网上的Demo都是用Swift写的,这样也方便移植和借鉴。

阅读全文 »
123
DragonFly

DragonFly

iOS开发、ReactNative开发、AR

21 日志
5 分类
17 标签
GitHub E-Mail 微博 Twitter FB Page JianShu
© 2018 DragonFly
由 Hexo 强力驱动
|
主题 — NexT.Muse v5.1.2
总访问量 次