开始学习Nodejs了,在这里记录一些轨迹吧。

工欲善其事,必先利其器。在开始之前,先搭好顺手的工具。 Nodejs的安装网上有很多教程了,这里着重介绍开发工具vscode的安装和配置。 vscode是挺不错的nodejs编辑工具,支持代码提示、自动完成和debug,并且它本身也是nodejs编写的。 当然如果你发现有更好用的工具,也请告诉我。

nodejs安装

安装Nodejs,我是从这里看的:七天学会nodejs, 还有官网.

下载和安装

下载地址:http://code.visualstudio.com/

配置命令行

配置命令行,使其可以用命令行这样启动:(仅限MacOS)

1
vscode .

MacOS系统:

在.bash_profile文件中加入下面代码:

1
function vscode () { VSCODE_CWD="$PWD" open -n -b "com.microsoft.VSCode" --args $*; }

上面代码中的com.microsoft.VSCode是应用的bundle identifier。查看方法: 1. 在应用上点击右键,选择“显示包内容”。 2. 打开Contents目录中的info.plist 3. 其中CFBundleIdentifier键下面的值就是应用的bundle identifier。 其实这种方式适用于大多数Mac应用,比如你可以参考我的文件

其他系统:

请参考https://code.visualstudio.com/docs/editor/setup

配置代码提示和自动完成

(2016.4.5勘误)

发现有时候vscode不能正确的进行代码提示,到vscode官网一看,代码提示的安装方法更新了,以下是最新内容:

添加jsconfig.json

在工程目录下新建一个文件jsconfig.json,填入以下内容:

1
2
3
4
5
6
{
    "compilerOptions": {
        "target": "es5",
        "module": "commonjs"
    }
}

这告诉vscode你正在使用ES5的javascript标准写代码,下面一行表示支持使用commonjs导出的模块(来进行代码提示)。

添加TypeScript定义文件

vscode使用TypeScript定义文件(比如node.d.ts)来提供代码提示和自动完成功能。 vscode推荐使用typings安装和管理TypeScript文件。 首先使用下面代码安装typings:

1
npm install -g typings

这将在全局安装typings。

然后,在你的工程目录下,安装你需要的TypeScript文件:

1
2
typings install node --ambient
typings install express serve-static express-serve-static-core --ambient

安装完之后,应该就可以看到代码提示了。

验证代码提示功能

有一个简单的方法验证vscode代码提示功能是否正常了: 新起一行输入

1
__dirname

鼠标移到__dirname上,如果提示类型是Any,说明代码提示功能还不正常。 如果能提示类型是string,那么说明代码提示工作正常了。

注:__dirname是nodejs内置全局变量。

Read on →

前言

ReactiveCocoa源码的时候,被RACSwizzleClass卡住了,做了以下研究,并把注释后的代码放在文章最后,如果不想看过程可以直接跳到最后。

RACSwizzleClass中通过判断[obj class]object_getClass(obj)是否相同来执行不同的逻辑。 然而[obj class]object_getClass(obj)有什么区别?他们不同到底意味着什么?

class和object_getClass

为此查阅了objc runtime的源代码,并整理了相关代码:get class 相关代码

结论:

  • 对于一个普通的obj(不是class),[obj class]object_getClass(obj)会返回一样的结果,就是该对象所属的类。
  • 对于一个class,[aclass class]还是会返回该class,而object_getClass(aclass)会溯本归源返回aclass的isa,一般是返回该类的meta class

对象的isa链会一直指向哪里?见下图:

objc 关系图

(图片来自http://blog.devtang.com/2013/10/15/objective-c-object-model/)

图中的Root class一般是NSObject,当你不停的调用object_getClass,你最终会获取到NSObjectmeta class

isa-swizzling

既然对于一个普通的obj(不是class),[obj class]object_getClass(obj)会返回一样的结果,那么RACSwizzleClass为什么要做相等性判断?

在苹果的文档中稍稍提到了一些: Key-Value Observing Implementation Details

简单的说:

  • 系统的KVO,是用isa-swizzling实现的。
  • isa指针,指向对象所属的类,类里面存储的是方法列表及其他一些信息。
  • 当你给一个对象添加了observer之后,系统会修改该对象的isa指针,使其指向一个中间类(中间类重写了setting方法以实现KVO),这时的isa,就不是指向对象实际的类了。

所以,你应该用class方法(因为系统同时重写了class方法使其返回对象原来的类),而不是isa(object_getClass)来取得对象所属的类。

Read on →

关于OC runtime、消息转发网上已经有很多文章,这里就不重复了,只是将一下不常见的、容易遗漏的列一下。

动态添加类

我们通过objc_allocateClassPairclass_addIvarclass_addMethodobjc_registerClassPair来动态添加类。

objc_registerClassPair 其中除了设置类状态,做的最重要的事是生成ivar_layout(在支持GC的情况下,所以ios中是没有这一步的),ivar_layout保存了类strong变量的内存视图,runtime依赖他来管理strong变量。

ivar_layout的结构阳神的博客里有描述,这里就不重复了。

objc_registerClassPair之后,类的instanceSize已经确定,这个新类已经可以投入使用,这时就不允许调用class_addIvar了。

class_addIvar主要是对ivar_list链表的操作,并相应的增加instanceSize

参考: Apple 源码

动态方法解析

一个OC方法的实现本质上就是一个简单的c函数,这个c函数至少要有self和_cmd两个参数。比如下面这个c函数:

1
2
3
void dynamicMethodIMP(id self, SEL _cmd) {
    // implementation ....
}

可以用class_addMethod来添加到现有的类中:

1
2
3
4
5
6
7
8
9
10
@implementation MyClass
+ (BOOL)resolveInstanceMethod:(SEL)aSEL
{
    if (aSEL == @selector(resolveThisMethodDynamically)) {
          class_addMethod([self class], aSEL, (IMP) dynamicMethodIMP, "v@:");
          return YES;
    }
    return [super resolveInstanceMethod:aSEL];
}
@end

resolveInstanceMethodresolveClassMethod可以用来动态提供一个方法实现。

OC runtime做消息转发(Message Forwarding)时,在调用respondsToSelector:instancesRespondToSelector:之前,会先调用上面两个方法,让你有机会来动态添加方法实现。

OC支持一种动态属性允许你动态提供它的实现方法。

1
@dynamic propertyName;

参考

Read on →

折腾了几天,搞定一个tweak(FPSCounter),把一些重要步骤记录一下。

关于这个插件

这是个帧速计数器(FPSCounter),方便我们查看应用的帧速,从而做出相应优化。这里不仅可以看自己的应用,也可以看系统中其他应用。

截图:

preview1 preview2

如何安装

  • 在Cydia中搜索FPSCounter.(你的Cydia中必须有BigBoss源)
  • 或者到source code下载后自行编译安装。

前提条件

一个越狱的iOS设备。

需要越狱的设备来获取可用的CydiaSubstrate, 同时也需要越狱设备来安装和测试。

安装和配置Theos

Theos大大简化了tweak的编写,建议大家从Theos开始编写tweak。

按照《iOS应用逆向工程》中所述,将Theos下载下来之后,还有一系列的配置。

我将这些配置工作写成了一个脚本,省去每次都做这些繁琐的配置。

这个脚本默认Theos是下载到“个人目录/jailbreak/Opensource”,如果不想修改脚本,可用使用与脚本相同的目录。

配置默认路径

修改.bash_profile文件,将~/jailbreak/Opensource/theos/bin加入到PATH中。

保存之后重新启动一下终端。

获取iOS系统头文件

按照《iOS应用逆向工程》的介绍,正规的获取方式是用dyld_decache从iOS设备中/System/Library/Caches/com.apple.dyld/dyld_shared_cache_armXX将二进制文件提取出来,然后用class-dump去把头文件提取出来。

为了方便起见,这里采用第二种方法,就是直接用rpetrich的头文件

将这些头文件放到Theos的include目录下。

开始编写tweak!

Read on →

2019.11.12更新

关于系统更新到MacOS 10.14之后ruby环境的调整,以及多说关闭之后评论系统的选择。

系统更新到10.14之后

gem install工具会出错:

1
2
3
4
5
$ sudo gem install bundler
Password:
Fetching: bundler-2.0.2.gem (100%)
ERROR:  While executing gem ... (Gem::FilePermissionError)
    You don't have write permissions for the /usr/bin directory.

这是因为Apple在OS X El Capitan中全面启用了名为System Integrity Protection (SIP)的系统完整性保护技术。大部分系统文件禁止直接修改。

要退出SIP需要重启到recovery模式下进行(重启按住command+r),这里采取另一个办法: /usr/bin禁止写入后,一般都用/usr/local/bin目录替代。gem install可以使用 -n install_path指定安装路径:

1
sudo gem install xxx -n /usr/local/bin

bundle install的时候还会出错:

1
2
3
4
5
6
7
8
9
10
11
$ bundle install --path vendor/bundle
Fetching gem metadata from https://rubygems.org/..........
Using rake 10.5.0
Fetching RedCloth 4.2.9
Installing RedCloth 4.2.9 with native extensions
Gem::Ext::BuildError: ERROR: Failed to build gem native extension.
  ...
mkmf.rb can't find header files for ruby at
/System/Library/Frameworks/Ruby.framework/Versions/2.3/usr/lib/ruby/include/ruby.h

extconf failed, exit code 1

因为macos10.14之后xcode11内置了macos10.15的SDK,预装了ruby2.6,没有ruby2.3的目录

1
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/include/ruby-2.6.0

但是CommandLineTools里面还有macos10.14的SDK:

1
/Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/System/Library/Frameworks/Ruby.framework/Versions/2.3/usr/include/ruby-2.3.0

通过

1
sudo xcode-select --switch /Library/Developer/CommandLineTools

来切换SDK路径

1
ruby -rrbconfig -e 'puts RbConfig::CONFIG["rubyhdrdir"]'

可以看到路径正确。

之后bundle install可以正常安装。

需要切换回xode11的sdk时:

1
sudo xcode-select --switch /Applications/Xcode.app

评论系统的选择

博客之前采用多说作为评论系统,可是多说关闭了,类似的友言、网易云跟帖等国内评论系统也相继停止服务。Disqus在国内一直被墙,需要重新选择一个评论系统。

看了几天,基本瞄中了基于github issue的评论系统,如果blog也host在github上,那么就很相得益彰。它的数据也没那么容易丢失,除非github倒闭。。。

一开始选择了名气较大的gitment,试用用了一下发现目前已不可用了: 由于采用github API操作issue,因此带来了跨站(CORS)问题,而github禁止跨站,无法直接访问。

解决办法是加一个中间代理服务器,给服务器返回头上添加跨站运行标志。 gitment作者本来自己搭了个代理服务器给大家使用,可是现在已经停服了,如果自己搭代理服务器代价还是颇高的。 而作者已经弃坑,两年多没有更新了,无奈弃之。

后来发现了类似的评论系统:gitalk,最近一年还在更新,试了下目前可用。 它是怎么解决跨站问题呢?抓包看了下,发现它采用了Heroku提供的API,专门用于转发请求并允许CORS访问:https://cors-anywhere.herokuapp.com

看来允许跨站请求头是个比较常见的问题。 gitalk的接入方式类似gitment:

  • 首先要在github中新建一个OAuth Application,记下Client ID和Client Secret
  • 修改_layouts下面的post.html,在最下面添加:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<section id="comment">
    <h1 class="title">Comments</h1>
    <div id="gitalk-container"></div>
    <link rel="stylesheet" href="https://unpkg.com/gitalk/dist/gitalk.css">
    <script src="https://unpkg.com/gitalk/dist/gitalk.min.js"></script>
    <script>
    const gitalk = new Gitalk({
      clientID: 'GitHub Application Client ID',
      clientSecret: 'GitHub Application Client Secret',
      repo: 'GitHub repo',
      owner: 'GitHub repo owner',
      admin: ['GitHub repo owner and collaborators, only these guys can initialize github issues'],
      id: location.pathname,      // Ensure uniqueness and length less than 50
      distractionFreeMode: false  // Facebook-like distraction free mode
    })
    gitalk.render('gitalk-container')
    </script>
</section>

GitHub repo可以直接填blog所在的repo,方便集中管理。

博客发出之后需要自己先浏览并登录github账号,以初始化issue page,之后就可以正常评论了。

Read on →

  • 原理:

OC调用javascript是通过

1
[webView stringByEvaluatingJavaScriptFromString:@"document.title"];

javascript调用OC一般是通过在页面中发起一个特定的url请求,然后在OC中响应

1
-(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType

在响应中判断此url,并做相应的动作。

开源库:https://github.com/marcuswestin/WebViewJavascriptBridge

Read on →

Hybrid开发就是native和web混合开发。他有两方面的优势:跨平台和更新快。 他同时涉及到web开发和native开发。 这里简单讲讲web开发。

  • Web常用目录结构:

[name].html 页面文件

style.css 主样式文件

m-style.css 移动平台主样式文件

img/ 图片目录

js/ javascript文件目录

css/ css文件目录

Read on →
Copyright © 2019 zhidong
Powered by Octopress. Design credit: Shashank Mehta