基于 Mac 的媒体中心

iOS 4.3 新增的一个重要的功能是对 [home sharing](http://support.apple.com/kb/HT4557) 的支持,这样你可以在一台安装了 iTunes 的机器上共享任何视频和音频而不需要同步到对应的 [iDevice](http://en.wikipedia.org/wiki/IDevice) 中。这给打造基于 Mac 的家庭媒体中心带来了很大的便利。先前介绍过用 [XBMC](http://xbmc.org) 构建媒体库的方法,安装了 XBMC 的 Mac mini 是我目前主要使用的视频播放设备,自从 Mac OS X 开放了[视频硬件解码支持](https://developer.apple.com/library/mac/#technotes/tn2267/) 之后,用低配置的 Mac mini 播放高码率的 1080p 视频也完全不是问题了。而且对于 iPad 2 和 iPhone 4S 以后的设备,因为已经支持到 H.264 的 [High Profile 4.1](http://www.apple.com/ipad/ipad-2/specs.html),所以正常情况下,网上所有能下载到的 MKV 封装的视频,都只需要重新封装一下就可以无损地播放了。这里介绍一下我的配置。
Continue reading “基于 Mac 的媒体中心”

阅读器的进度显示与估计


对电子书阅读器来说,提示当前阅读进度是一项很自然的功能,习惯用电脑的人都常看到进度条 (progress bar) 和滚动条 (scroll bar),如右图是 [Textus](http://www.jjgod.org/projects/textus) 中使用的右侧滚动条。

然而在实际实现中,进度计算是一件伤脑筋的事情,比如 Textus 的实现其实很简单:在打开文件时读入整个文件,然后整个交给 [Core Text](http://en.wikipedia.org/wiki/Core_Text) 去排版,将排版后的结果分解为行 (`CTLineRef`) 记录下来,并将所有行总的高度设置为整个文本视图的高度,这样,每当滚动视图 (`NSScrollView`) 移动到某个位置时,重绘函数 (`-drawRect:`) 被调用到,我们根据该位置来判断应该绘制从第几行到第几行的内容,再调用 Core Text 把这些行画出来。

这么做看似很简单直接,结果也很容易保证正确,带来的问题是,每次用户修改设置 (比如调整字体大小、窗口尺寸) 时,就得把整个文件重新排版一遍,即使此时我们只需要看到**当前一页**的内容。为什么这种方法这么低效,我还一直使用它呢?因为这个实现严格依赖滚动视图给出的位置来判断当前阅读进度,所以总的高度估计必须非常精确,不然随便滚动一下就可能出现错位,而一次算给出整个高度的方法最准确,不容易出错。

Continue reading “阅读器的进度显示与估计”

A closer look at Classics.app

A Screenshot of Classics

“[Classics](http://www.classicsapp.com/)” is a great product, it shows us iPhone developers what an *elegant* ebook reader can be, so I bought it almost instantly after it’s released. I’ve been chatting with my friends about this app for a while, now I’d like to give a more closer examination to it from the perspective of a typographer and a programmer. Especially its weaknesses.

Illustrated by my favorite graphic designer, [David Lanham](http://dlanham.com), Classics tries its best to provide a traditional book reading experience (that’s why it’s called “Classics”). It contains the following books, even I’ve read most of them in Chinese long time ago, thanks to Classics, it’s still a fascinating experience to read them again in English:

* *[20,000 Leagues Under the Sea](http://en.wikipedia.org/wiki/Twenty_Thousand_Leagues_Under_the_Sea)* by [Jules Verne](http://en.wikipedia.org/wiki/Jules_Verne)
* *[A Christmas Carol](http://en.wikipedia.org/wiki/A_Christmas_Carol)* by [Charles Dickens](http://en.wikipedia.org/wiki/Charles_Dickens) [Added in version 1.1]
* *[Alice in Wonderland](http://en.wikipedia.org/wiki/Alice_in_Wonderland)* by [Lewis Carroll](http://en.wikipedia.org/wiki/Lewis_Carroll)
* *[Flatland](http://en.wikipedia.org/wiki/Flatland)* by [Edwin Abbott Abbott](http://en.wikipedia.org/wiki/Edwin_Abbott_Abbott)
* *[Gulliver’s Travels](http://en.wikipedia.org/wiki/Gulliver%27s_Travels)* by [Jonathan Swift](http://en.wikipedia.org/wiki/Jonathan_Swift)
* *[The Hound of the Baskervilles](http://en.wikipedia.org/wiki/Hound_of_the_Baskervilles)* by Sir [Arthur Conan Doyle](http://en.wikipedia.org/wiki/Arthur_Conan_Doyle)
* *[Adventures of Huckleberry Finn](http://en.wikipedia.org/wiki/Adventures_of_Huckleberry_Finn)* by [Mark Twain](http://en.wikipedia.org/wiki/Mark_Twain)
* *[Paradise Lost](http://en.wikipedia.org/wiki/Paradise_Lost)* by [John Milton](http://en.wikipedia.org/wiki/John_Milton)
* *[Robinson Crusoe](http://en.wikipedia.org/wiki/Robinson_Crusoe)* by [Daniel Defoe](http://en.wikipedia.org/wiki/Daniel_Defoe)
* *[The Call of the Wild](http://en.wikipedia.org/wiki/The_Call_Of_The_Wild)* by [Jack London](http://en.wikipedia.org/wiki/Jack_London)
* *[The Jungle Book](http://en.wikipedia.org/wiki/The_Jungle_Book)* by [Rudyard Kipling](http://en.wikipedia.org/wiki/Rudyard_Kipling)
* *[The Metamorphosis](http://en.wikipedia.org/wiki/The_Metamorphosis)* by [Franz Kafka](http://en.wikipedia.org/wiki/Franz_Kafka)
* *[The Time Machine](http://en.wikipedia.org/wiki/The_Time_Machine)* by [H. G. Wells](http://en.wikipedia.org/wiki/H._G._Wells)

However, there are still some details to be improved.
Continue reading “A closer look at Classics.app”

State of iPhone Open Application Development (1)

七月关于 iPhone 的消息一直围绕着 2.0 firmware, iPhone 3G, official SDK 1.0 这几个关键词,而非官方关心的也只是 Pwnage Tool 2.0,却对没有 iPhone Developer Program 的开发进展甚少介绍,我想在这里做一点记录。

随着 SDK 1.0 的正式发布 (遗憾的是,因为 NDA 的存在,甚至它都算不上发布..),iPhone 2.0 firmware 和 App Store 的上线,在 Apple 监视下的 iPhone OS/Cocoa Touch 程序开发的局限性暴露得越来越明显,saurik, NerveGas 等开发者坚持开发 Open Toolchain 的重要性也越来越明显。为什么在拥有一个如此完善的 SDK 的情况下我们还需要 Open Toolchain 和相关工具?因为:

  • Apple 严格限制了第三方应用对 API 的使用,非 Apple 自己开发的应用程序不能使用许多极为有用的 Private API,否则就是违反 SDK 的授权协议,所以第三方应用始终只能是“二等公民”。
  • App Store 的发行方式要求每次更新软件都要由 Apple 审核才能出现,而列出应用的页面对于用户 feedback 和开发者交流的功能也非常局限——毕竟这个模式根本就是 iTunes Music Store 改头换面了一点点,Album 到 Application 其实并不能做到一一映射。所以我们需要更自由的 iPhone OS 软件发行方式。
  • 软件分发要求所有只开发 Open Source/Free 应用程序的开发者都必须至少缴纳 $99 年费,这极大打击了 Open Source 开发/移植者的积极性,在 Pwnage Tool 的大环境支持下,我们完全可以跳过这个限制,自行分发软件。

因为上面这些原因,我一直非常关注 open toolchain 的开发,到了 4 月份的时候,有半个月的时间一直在跟踪 saurik 在这方面开发的结果,其结果是这篇 Upgrading the iPhone Toolchain,可惜的是因为 saurik 一直不满意用 git 来跟踪上游代码的修改,所以这篇文章其实相当难付诸实施,不过,考虑到 SDK 1.0 的发布后上游代码应该有一个相对稳定期,所以希望 saurik 能够尽快整理出更新的文档和代码来吧。

不过 saurik 在他的 Cydia repo 里提供了 iPhone 上完整的 toolchain,你可以在自己的 iPhone/iPod Touch 上用 gcc 编译,用 gdb 调试…. 当然考虑到有限的硬件资源,这种方式对很多人来说太 geeky 了,包括我。

然而,目前用官方 SDK 提供的编译器和调试器来给编写在 pwn 过的 iPhone 上免费分发的应用程序已经完全可行了,详情可以参考 saurik 的 Bypassing iPhone Code Signatures246tNt 的说明。未 pwn 的 iPhone 因为目前事实上只有通过 App Store 一条路安装应用程序,所以谈怎么分发也是没有意义的。

简单的说,这种方式是因为 pwn 过的 iPhone 的内核已经被打上了 patch,弱化了签名校验——不再要求非要有 Apple 的签名了,可是签名校验依然存在,要完全去掉不大现实,所以现在你可以通过 Apple 自己提供的 codesign 工具来给应用自行签名,或者在别的平台下用 saurik 开发的 ldid 签名工具来保证通过 iPhone 的签名检查。对于大部分 Mac 开发者而言,这也只是在 Xcode 的项目中,新增一个 Build Phase 的事情,所以不会增加什么工作量。

而 246tNt 进一步延展了 saurik 的工作,分析了 entitlements 文件在签名后的 iPhone App 中对安全控制的作用,使得这种自签名的应用程序也能像有 Dev Program 的应用一样,可以用 Xcode 自带的 gdb 进行远程调试。此外,246tNt 还找出了办法对 iPhone OS 中的 SpringBoard 和 MobileInstallation 打上补丁,使得我们可以直接把应用程序用 Xcode Organizer (或者 Build and Go!) 上传到 iPhone 上,并自动开始调试。

感谢这些开发者的工作,目前我们获得的开发环境和支付了 $99 美元的 Dev Program 开发者毫无二致了。可是,分发环境还是有区别,假定我们的程序并没有做任何逾越 SDK 授权的事情,如果还希望通过 App Store 分发,那还是只能去购买 Dev Program。不过毫无疑问,对于开放的应用程序而言,Cydia 应该是更好的分发方式,考虑到因为 Pwnage Tool 2.0 的包含,Cydia 几乎已经成为了标准的应用分发方式。

(待续)

最近在写的两个东西

这两天写了两个简单的小程序,主要是满足朋友和个人需求的,还在修改中。

第一个叫 apn 的程序是给 Mac OS X 中 Address Book 中的联系人自动生成姓名发音 (Phonetic Name) 的脚本,所以它的名字就是 Assign Phonetic Name 的缩写。

这是一个 Python 写的程序,直接用到了 pyzh 项目提供的汉字拼音转换代码,通过 Scripting Bridge 提供的 API 来访问 Address Book,这样虽然相比直接调用 Objective-C 的 API 有点慢,但好处在于能充分利用 Python 语言的灵活性。

使用起来很简单,从 github 上把代码抓下来 (你可以 git clone git://github.com/jjgod/apn.git 或者下载一个打包的版本),然后执行

$ python AssignPhoneticName.py

就会自动给你 Address Book 中没有分配过 Phonetic Name 的那些联系人分配一遍。注意因为汉字有多音字,这个程序做不到很智能,你最好在分配之后打开 Address Book 校对一遍。

第二个是给 Cocoa 程序员用的一个 NSView 的子类,叫 PYView,其作用很简单,就是在汉字上方同步的显示拼音,不过目前拼音还得自己提供。

调用的 API 很简单,比如这样:

#include "PYView.h"

NSRect viewRect = NSMakeRect(50, 250, 700, 80);
view = [[PYView alloc] initWithFrame: viewRect
                            fontName: @”FZKai-Z03″
                               color: [NSColor whiteColor]];

NSArray *pinyin1 = [NSArray arrayWithObjects: @"nǐ", @"hǎo", nil];
NSArray *pinyin2 = [NSArray arrayWithObjects: @"zhōng", @"huá",
                    @"rén", @"mín", @"gòng", @"hé", @"guó", nil];


[view appendMarkerItem: [PYMarkerItem itemWithHanzi: @"你好"
                                             pinyin: pinyin1
                                               type: 1]];
[view appendMarkerItem: [PYMarkerItem itemWithHanzi: @"中华人民共和国"
                                             pinyin: pinyin2
                                               type: 1]];

就能得到如图所示的输出结果:

PinyinView

可以从 github 上获取代码:

 git clone git://github.com/jjgod/pinyinview.git

然后参考提供的 PYViewTest 代码来使用。注意接口还在修改中。