Haisheng Wu's Tech Blog

Docker 使用

通过 Docker 命令行工具与 Docker Daemon 进程通讯使用。 使用步骤 安装 Docker 到宿主机(物理机) 到仓库拉取镜像 https://hub.docker.com 运行镜像产生容器(实例,一个镜像可以运行多个) 镜像操作 搜索镜像 docker search imageName 拉取镜像 docker pull imageName:tag tag 版本号,如不指定默认是 latest 查看本地镜像 docker images 删除镜像 docker rmi imageID docker rmi [repositoryname]:[tag] 删除所有未加标签的镜像(untagged) docker rmi $(docker images | grep "^<none>" | awk "{print $3}") 重命名镜像 docker tag imageId imageName:tag 通过本地 Dockerfile 文件编译镜像文件 docker build -t mop:latest - < mopDockerfile 容器操作 进入容器 sudo docker exec -it ubuntu bash docker exec -it ardupilot bash 查看容器 docker ps -a -a:所有容器,包括停止的 -q:查看停止的容器,不加选项默认查看运行中的容器 保存容器 sudo docker save ubuntu > ubuntu_save.

Lombok

介绍 Lombok 是提升 Java 编码效率常用的工具,借助它开发人员可以使用注解来自动生成一些模版代码。比如 getter、setter、equals、toString 等方法。 安装 在 maven 中添加依赖 <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.4</version> <scope>provided</scope> </dependency> 在编辑器中添加插件 如:Intellij Idea,在 setting 的 plugin 里搜索lombok plugin,安装插件 使用 常用的几个注解 @Data :注在类上,自动生成类的 get、set、equals、hashCode、canEqual、toString 方法 @AllArgsConstructor :注在类上,自动生成类的全参构造方法 @NoArgsConstructor :注在类上,自动生成类的无参构造 @Setter :注在属性上,自动生成 set 方法 @Getter :注在属性上,自动生成 get 方法 @EqualsAndHashCode :注在类上,自动生成对应的 equals 和 hashCode 方法 @Log4j/@Slf4j :注在类上,自动生成对应的 Logger 对象,变量名为 log @Cleanup(“close”):注在本地变量上,自动释放资源(如:关闭 InputStream) @Synchronized:注在方法上,自动生成一个私有锁变量 @SneakyThrows:自动生成异常处理语句 注意继承关系中使用 Lombok @EqualsAndHashCode 与 @ToString 注解默认情况下忽略父类的成员变量。譬如打印时 toString 返回的结果中缺少父类的成员变量,解决办法是在注解中设置 callSuper 属性为 true, @ToString(callSuper = true) 、@EqualsAndHashCode(callsuper = true)。

WebViewJavascriptBridge 源码剖析

WebViewJavascriptBridge 是一个可以让 OC 与 JS 进行交互通信的第三方开源库。相比其他热门的第三方库,WebViewJavascriptBridge 代码量比较少,并且设计优雅巧妙,可以说是 “小而美”。 WebViewJavascriptBridge 库在 OC 端和 JS 端都有对等的逻辑实现,事先注册 handler,内部维护一个消息队列。透明的 iframe HTML 元素和 webview 的 stringByEvaluatingJavaScriptFromString 是通信的关键。OC 端发消息给 JS 端比较直观,调起 stringByEvaluatingJavaScriptFromString 执行脚本传入消息即可。JS 端发消息给 OC 端,需要事先把消息存到队列中,然后借助 iframe 发起一个伪请求,伪请求会被 webview 的代理方法拦截下来,OC 端因此得知 JS 端消息队列中有消息,最后调起 stringByEvaluatingJavaScriptFromString 方法解析 JS 方法拿到队列中的消息并处理。交互流程见下图: 整个库只有以下几个文件: WebViewJavascriptBridge.h WebViewJavascriptBridge.m WKWebViewJavascriptBridge.h WKWebViewJavascriptBridge.m WebViewJavascriptBridgeBase.h WebViewJavascriptBridgeBase.m WebViewJavascriptBridge_JS.h WebViewJavascriptBridge_JS.m 一般使用只需要关注 WebViewJavascriptBridge 类提供的接口,这个类的主要职责是用来做 Mac 和 iOS webview 的适配(包括 WKWebView,但是这部分代理出去给 WKWebViewJavaScriptBridge 类)并为客户端提供便利的使用接口。WebViewJavascriptBridgeBase 类负责有关数据加工、消息队列管理、消息派发及回调的处理工作。WebViewJavascriptBridge_JS 类包含 JS 端的实现代码,通过宏处理返回 JS 端实现代码的一个 OC 字符串,便于在适当时机将其注入到文档模型中完成 bridge 的初始化。

iOS 远程打包脚本制作

在 iOS 开发中,一般打发布包都是在本地打包,也就是工程师在自己开发电脑上使用 Xcode 编译并导出安装包来进行发布,为了提高效率可能会制作一些自动化打包脚本。本文聊的是远程打包的内容,通过资源拷贝及参数替换然后编译完成打包。 由于 HTML5 跨平台的特点,很多技术团队考虑到代码复用,在部分模块中会采用 h5 来描述界面。甚至有些不需要太复杂交互的 app,全部界面采用 h5 来编写,也就是一个 web 工程。对于大部分现有的 web 工程,能打包成 app 就已经满足了业务诉求。DCloud 团队开发的 HBuilder(IDE)工具中提供了云打包的功能,用起来很方便,简单的说,就是把 web 工程上传到云打包服务器,最后打包生成 app,点击下载即可安装使用。 虽然云打包服务很方便,但上传源码总感觉不太妥当,总有些秘密不想让别人看见,并且其他同事也有打包的需求,但不一定会使用 HBuilder。因此,搭建一个自己的打包服务很有必要。 按照 HBuilder 提供的云打包功能,先定一个初步的需求: 支持修改应用 id、版本号 、icon、启动图 支持导入签名文件 开工!!! 准备工作 首先,需要一台安装了 MacOS 的电脑(当做服务器使用)。 笔者手头上刚好有台闲置的电脑就拿来当服务器使用了,装了 WMWare,然后装了 MacOS 虚拟机(问题较多,不建议使用虚拟机)。 物理机 windows7,内存 4G;虚拟机 MacOS,内存 3G。 其次,在服务器上部署一个 web 服务,提供打包交互界面方便客户端上传资源文件及下载安装包。我们的界面只提供了一个 www zip 包的上传入口,所有应用资源及打包相关的配置文件都在里面。www 目录结构如下: appConfig.json 文件内容 { "id":"com.domain.pack", "appName":"我的应用", "debug":true, "launchPath": "index.html", "version": { "name": "1.0.0", "code": "100" }, ... } launchPath 对应 web 应用入口文件,iOS 工程使用这个文件路径作为 webview 的加载入口。

Android Gradle 注入编译变量

最近为了制作 Android 应用打包脚本,学习了一下 gradle。Gradle 构建系统语法简洁、功能强大、配置灵活,笔者只是把它当作一个构建工具来使用,基于它所提供的便利制作可以修改版本号、编译号、id 及导入证书的脚本。 对于一个项目或者一个工程,Gradle 可以定义多个构建任务,debug 和 release 是常见的两个构建任务,用户还可以根据需要自定义自己的构建任务,如测试构建任务和预发布构建任务,甚至是针对不同发布渠道的构建任务。这里只用到 debug 任务。 gradle 命令行支持传入自定义参数,并在编译过程注入这些参数。 修改 appid 及 版本号 修改 build.gradle 文件 android { compileSdkVersion 21 buildToolsVersion '26.0.2' defaultConfig { applicationId project.hasProperty('applicationId') ? applicationId : "com.domain.myApp" minSdkVersion 14 targetSdkVersion 21 versionCode project.hasProperty('versionCode') ? versionCode.toInteger() : 100 versionName project.hasProperty('versionName') ? versionName : "1.0.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } 命令行中传入对应 key 的参数 gradle assembleDebug -PversionCode="200" -PversionName="2.0.0" -PapplicationId="com.domain.myApp.debug" 修改应用 id 的最好同时修改包名,不然会有包名冲突,修改包名需要修改 AndroidManifest.xml 文件,先在 build.gradle 文件中使用 manifestPlaceholders 属性定义一个键:

Core Bluetooth Programming Guide 译文

介绍 关于 Core Bluetooth Core Bluetooth 框架提供 iOS 应用和 Mac 应用与设备(配备了蓝牙低能耗无线技术的设备)通信的类。例如,应用可以发现、探测并与低能耗外围设备(比如心率监听器和数字恒温器)交互。从 macOS 10.9 和 iOS 6 开始,Mac 和 iOS 设备还可以当做蓝牙低能耗外设来使用,为其它设备提供数据,包括其他 Mac 和 iOS 设备。 一览 蓝牙低能耗无线技术基于蓝牙 4.0 规范,规范中除了别的之外,定义了与低能耗设备通信的一套协议。Core Bluetooth 框架是蓝牙低能耗协议栈的一个抽象,也就是说,它为开发者隐藏了许多规范中的底层细节,让开发者更加容易开发应用(与蓝牙低能耗设备交互的应用)。 中央和外围是 Core Bluetooth 的核心成员 在蓝牙低能耗通信中,有两个核心成员:中央(central)和外围(peripheral)。每个成员扮演不同的角色。外围通常拥有其他设备需要的数据,中央通常使用外围提供的信息来完成一些任务。例如,一个配备了蓝牙低能耗技术的数字恒温器可能为一个 iOS 应用提供房间的温度信息,然后该应用采用用户友好的方式来显示温度。 每个成员在扮演它的角色时都会执行一组不同的任务。外围通过在空中广播持有的数据来让自身的存在被感知,中央设备扫描附近的外围设备(可能包含中央设备感兴趣的数据)。当中央设备发现外围设备,中央设备就请求与外围设备连接并开始探测和交互外围设备的数据。外围设备负责以适当的方式来响应中央设备。 相关章节:Core Bluetooth Overview Core Bluetooth 简化了一般的蓝牙任务 Core Bluetooth 框架抽离了蓝牙 4.0 规范中的底层细节。因此,应用中需要实现的一般蓝牙低能耗任务被简化了。如果开发实现中央角色的应用,Core Bluetooth 使得发现、连接外围设备和探测、交互外围数据变得简单。另外,Core Bluetooth 还让本地设备实现外围角色变得简单。 相关章节:Performing Commmon Central Role Tasks,Performing Common Peripheral Role Tasks iOS 应用的状态影响蓝牙的表现 当应用处于后台或挂起状态时,蓝牙相关的特性会受到影响。在这两种状态下,默认是应用无法执行蓝牙低能耗任务。也就是说,如果应用需要在后台执行蓝牙低能耗任务,可以声明支持 Core Bluetooth 后台运行模式中的一个或两个(一个属于中央角色,另一个属于外围角色)。即使在你指定了一个后台运行模式或两个都指定,当应用处于后台时,某些蓝牙任务的执行依然会有所不同,设计应用时,需要考虑到这些差异。 即使应用支持后台处理,应用仍然可能在任意时刻被系统终止以清空内存给当前前台应用使用。在 iOS 7之后,Core Bluetooth 支持保存中央和外围管理者对象的状态信息并在应用启动的时候恢复该状态,可以使用这个特性来支持涉及蓝牙设备的长期活动(long-term actions)。

Difference between authentication, authorization,verification, validation

verification, validation, authentication, authorization 这几个术语很常用,也经常被误用,这里做一次对比总结。 identity A security principal (you or a computer, typically) wants to access a system. Because the system doesn’t know you yet, you need to make a declaration of who you are. Your answer to the question “Who are you” is the first thing you present to a system when you want to use it. Some common examples of identity are user IDs, digital certificates (which include public keys), and ATM cards.

Local and Remote Notification Programming Guide 译文

原文地址:本地和远程通知编程指南 应用中的通知 本地和远程通知概览 重要 这篇文档包含开发中有关 API 或技术的初步信息,这些信息可能会改变,并且根据这篇文档来实现的软件应当在最终的操作系统软件中进行测试。 本地通知和远程通知是在应用有新数据可用时通知用户的两种方式,即使此时应用不在前台运行。例如,短信应用可能会让用户知道有新的短信来了,日历应用可能会通知用户即将到来的约会。本地通知和远程通知的区别很简单: 对于本地通知,应用在本地配置通知的细节并把这些细节传给系统,然后由系统来处理通知的传递(当应用不在前台时)。iOS、tvOS、watchOS 都支持本地通知。 对于远程通知,使用公司服务器中的一个通过苹果推送通知服务把数据推送到用户的设备。iOS、tvOS、watchOS、macOS 都支持远程通知。 本地通知和远程通知都需要添加代码来支持应用中的通知的调度和处理。对于远程通知,必须提供一个服务器环境,该环境能够接收来自用户设备的数据和发送通知相关的数据到 苹果推送消息服务 (简称 APNs,由苹果提供的用来处理远程通知传递的服务)。 User Notifications 和 User Notifications UI 框架 从 iOS 10、watchOS 3、tvOS 10 开始,User Notifications 框架提供一致的方式来和处理本地通知。除了管理本地通知,该框架也支持远程通知的处理,然而远程通知的配置仍然需要一些平台特有的 API。因为这是一个独立的框架,所以可以在应用中或者扩展中使用,比如 WatchKit 扩展。 注意 macOS 上远程通知的配置和处理需要使用平台特有的方法(在 AppKit 框架中找) User Notifications 框架也支持创建 通知服务应用扩展 (notification service app extension),它可以让你在远程通知传递之前修改通知的内容。如果在应用中包含通知服务应用扩展,系统会把收到的通知在传递给用户之前先传递给扩展。可以使用这类扩展来给应用的通知实现端到端的加密、在通知传递前修改其内容,又或者下载与通知相关的额外的图片或媒体文件。 User Notifications UI 框架是 User Notifications 的配套,它可以让你自定义系统的通知界面的外观。使用User Notifications UI 框架来定义 通知内容应用扩展(notification content app extension),它的任务就是提供一个包含自定义内容的视图控制器来显示在通知界面中。系统会显示自定义视图控制器而不是默认的系统界面。可以使用这种扩展在通知界面中加入多媒体或动态内容。 更多有关 User Notifications 框架的类的信息,请看 User Notifications Framework Reference。关于创建通知内容应用扩展的类的信息,请看 User Notifications UI Framework Reference。

《第一行代码》

最近为了学习 Android,找从事 Android 开发的朋友推荐些书,最后他推荐了《第一行代码》(第 2 版)和《Android 开发艺术探索》两本书。本文是在阅读了《第一行代码》之后所做的笔记,主要记录 Android 平台上的一些比较有趣的特性以及它和 iOS 的不同之处。 Android 全貌 2008 年 9 月,Google 正式发布 Android 1.0 系统 2014 年 Google I/O 大会上发布号称史上版本改动最大的 Android 5.0 系统,这版本使用 ART 运行环境替换 Dalvik 虚拟机,同时推出 Wear、Auto、TV 系统 2016 年 Google I/O 大会推出 Android 7.0,加入多窗口模式 Android 系统架构 Android 系统架构分为四层:Linux 内核层、系统运行库层、应用架构层、应用层。 Linux 内核层:主要包含一些硬件的底层驱动。 系统运行库层:包含 C/C++ 的底层支持库,例如:支持 3D 绘图的 OpenGL|ES 库、浏览器内核 Webkit 库和 SQLite 数据库支持库。另外还包含 Android 运行时库。 应用架构层:包含构建应用程序用到的 API,开发人员主要使用这层提供的 API 来构建应用。 应用层:包含手机上安装的应用,联系人、短信等。 Android 系统为开发人员提供了: 四大组件,活动(Activity)、服务(Service)、广播接收器(Broadcast Receiver) 和内容提供器(Content Provider) 系统控件 SQLite 数据库 多媒体,音乐、视频、图片、拍照、闹铃等 地理位置定位 Android 开发环境及工具 环境:JDK + Android SDK