<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Architecting Life &#187; Develop</title>
	<atom:link href="http://xujiwei.com/blog/posts/develop/feed/" rel="self" type="application/rss+xml" />
	<link>http://xujiwei.com/blog</link>
	<description>Just do it</description>
	<lastBuildDate>Wed, 28 Dec 2011 02:06:05 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>推开窗户看世界 — Objective-C之外</title>
		<link>http://xujiwei.com/blog/besides-objective-c/</link>
		<comments>http://xujiwei.com/blog/besides-objective-c/#comments</comments>
		<pubDate>Mon, 12 Dec 2011 10:03:45 +0000</pubDate>
		<dc:creator>Xu Jiwei</dc:creator>
				<category><![CDATA[Web]]></category>
		<category><![CDATA[iOS]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Mono]]></category>
		<category><![CDATA[PhoneGap]]></category>
		<category><![CDATA[Titanium]]></category>

		<guid isPermaLink="false">http://xujiwei.com/blog/?p=527</guid>
		<description><![CDATA[<a href="http://xujiwei.com/blog/besides-objective-c/" title="推开窗户看世界 — Objective-C之外"></a>Besides Objective-C View more presentations from Jiwei Xu 引子 App Store 如今正风靡世界，许多人都想尝试去自己开发一个 iOS App，不过苹果官方推荐使用的是 Objective-C 这个语言。而 Objective-C 与 C、Java 之类的语言风格差异有些大，短时间并不容易掌握，又或者许多人只是想尝试开发一个可以运行在 iOS 上的程序而已，不想再去额外去学一门新的语言，那这个时候就可以考虑另外的一些技术来开发 iOS App。 在移动开发领域，得益于现在手机的性能越来越好，浏览器的功能越来越强大，JavaScript 也成为一门很流行的程序开发语言，而对应到 iOS 平台上，也有多种使用 JavaScript 来开发 iOS App 的技术。这次要介绍的三种技术之中，就有两种使用了 JavaScript。 另外，许多开发跨平台移动应用开发的解决方案，首选要支持的就是 iOS，因此在 iOS 这个平台上可以看到很多种不使用 Objective-C 去开发 &#8230;<p class="read-more"><a href="http://xujiwei.com/blog/besides-objective-c/">Read more &#187;</a>]]></description>
			<content:encoded><![CDATA[<a href="http://xujiwei.com/blog/besides-objective-c/" title="推开窗户看世界 — Objective-C之外"></a><div style="width:425px" id="__ss_10556901"> <strong style="display:block;margin:12px 0 4px"><a href="http://www.slideshare.net/ohdarling88/besides-objectivec" title="Besides Objective-C" target="_blank">Besides Objective-C</a></strong> <iframe src="http://www.slideshare.net/slideshow/embed_code/10556901" width="425" height="355" frameborder="0" marginwidth="0" marginheight="0" scrolling="no"></iframe> <div style="padding:5px 0 12px"> View more <a href="http://www.slideshare.net/" target="_blank">presentations</a> from <a href="http://www.slideshare.net/ohdarling88" target="_blank">Jiwei Xu</a> </div> </div>

<h2>引子</h2>

<p>App Store 如今正风靡世界，许多人都想尝试去自己开发一个 iOS App，不过苹果官方推荐使用的是 Objective-C 这个语言。而 Objective-C 与 C、Java 之类的语言风格差异有些大，短时间并不容易掌握，又或者许多人只是想尝试开发一个可以运行在 iOS 上的程序而已，不想再去额外去学一门新的语言，那这个时候就可以考虑另外的一些技术来开发 iOS App。</p>

<p>在移动开发领域，得益于现在手机的性能越来越好，浏览器的功能越来越强大，JavaScript 也成为一门很流行的程序开发语言，而对应到 iOS 平台上，也有多种使用 JavaScript 来开发 iOS App 的技术。这次要介绍的三种技术之中，就有两种使用了 JavaScript。</p>

<p>另外，许多开发跨平台移动应用开发的解决方案，首选要支持的就是 iOS，因此在 iOS 这个平台上可以看到很多种不使用 Objective-C 去开发 iOS App 的技术，而且其中技术所编写出来的程序，除了可以在 iOS 上运行之外，还可以运行在 Android 以及其他系统平台上。能少写一份代码，何乐而不为呢～</p>

<h2>不使用 Objective-C</h2>

<p>这次要介绍的是三个不使用 Objective-C 来开发 iOS App 的解决方案：</p>

<ul>
<li><a href="http://www.appcelerator.com/products/titanium-mobile-application-development/">Titanium Mobile</a></li>
<li>PhoneGap(http://phonegap.com)</li>
<li>Mono Touch(http://xamarin.com/monotouch)</li>
</ul>

<p>这三个解决方案各有特点，它们的运行机制也有所不同，至于在开发 iOS App 时选用何种方案，可以根据每种方案不同的特点去选择适合自己的。</p>

<h2>Titanium Mobile</h2>

<p>Titanium Mobile 是 AppCelerator 推出的一个基于 JavaScript 的跨平台移动应用开发技术。通过 Titanium Mobile，可以直接使用 JavaScript 开发能运行于 iOS 和 Android 平台的应用程序，而代码只需要写一次。</p>

<p>Titanium Mobile 是通过将 JavaScript 代码映射到对应平台的 Native Code，在 Titanium Mobile 中操作某一个 UI 对象，或者是其他对象时，实时上是在操作对应平台中实际的 UI 对象，例如使用 Ti.UI.createView() 创建一个视图，它在 iOS 中运行时会实际对应到 UIView，使用 Ti.UI.createTabGroup() 就会对应到 iOS 中的 UITabBarController。这样做的好处就是，可以直接使用 JavaScript 来创建出原生的 UI，而不需要使用额外的代码来让程序 UI 更像系统的 UI。</p>

<p>另外，AppCelerator 在收购了 <a href="http://aptana.com/">Apatna</a> 之后，推出了适用于 Titanium 的 IDE <a href="http://www.appcelerator.com/products/titanium-studio/">Titanium Studio</a>，通过使用 Titanium Studio，可以很方便的创建项目、带智能提示的编辑器，以及很方便的调试项目。</p>

<p>在 Titanium Studio 中调试 iOS 项目时，可以做到单步调试，也就意味着，可以拥有不弱于使用 Xcode 开发项目的体验。断点、单步、变量查看功能一应具全。如果需要发布到 App Store，也可以很方便的通过图形化界面来打包。</p>

<p>当然，使用 Titanium Studio 也需要配合 Xcode 来使用，必须要在安装了 Xcode 的情况下，才可以使用 Titanium Studio 来调试和测试项目。</p>

<p>在 Titanium Studio 推出之前，Titanium Mobile 是靠一个 Developer Tool 来进行打包等操作的，相对比较繁琐，而有了 Titanium Studio 之后，让一切变得简单，我也是从那时开始关注 Titanium Mobile。</p>

<p>对于前端开发工程师来说，只需要理解了 iOS 开发中的一些概念，就可以使用 Titanium Mobile 来开发一个像模像样的 iOS App。并且 Titanium Mobile 实现了 CommonJS 规范，可以很方便来模块化程序代码。</p>

<h2>PhoneGap</h2>

<p>PhoneGap 是一个使用 HTML+CSS+JavaScript 来开发移动 App 的解决方案，使用它来开发 App 只需要有 Web 开发基础即可。它在今年10月份被 Adobe 收购了，然后加入到 Apache Software Foundation 进行孵化。</p>

<p>目前 PhoneGap 已经支持了市面上大多数的智能手机平台，其中就有 iOS。</p>

<p>在我看来，PhoneGap 其实只是提供了一个运行于各种智能手机平台的浏览器的壳，通过这个壳，PhoneGap 的 JavaScript 库可以和系统进行沟通，从而实现在 Web 页面中与系统交互的功能。</p>

<p>因为 PhoneGap 只提供了系统功能的 API 调用，而没有提供任何和界面相关的 API，那么界面就只能自己来折腾了。</p>

<p>幸好开源的世界是强大的，已经有了一堆这样的界面库来供我们选择，像 <a href="http://jqtouch.com/">jQTouch</a>、<a href="http://jquerymobile.com/">jQuery Mobile</a>、<a href="http://www.sencha.com/products/touch">Sencha Touch</a> 之类，都提供了类似于 iOS 的界面组件，可以让我们省去许多界面上的编码工作。</p>

<p>使用浏览器来运行 App 的一个坏处就是：慢。因为整个 App 就是一个网页，如果编码不当，整个程序使用起来体验会比较差，和原生的应用会有很大区别。</p>

<p>在上面提到的几个 UI 框架之中，我比较喜欢的是 jQTouch，它只提供了基本 UI 框架和一些视图切换效果，做出来的程序是一个单页面 App，在整个程序的反应速度上会感觉比较好。不过 jQTouch 也缺少一些常用的组件像对话框，而这些在 jQuery Mobile 和 Sencha Touch 之中又有提供。选择使用哪个框架就要看个人喜好了，它们的网站都提供了在线预览功能</p>

<p>其实，如果用不到系统的 API，只是想把自己的程序包装成一个很像 App 的 App 的话，只要用一用 PhoneGap 提供的壳就行了，它的 API 几乎可以不用看，配合一些 UI 框架可以快速的产出一个 iOS App 来。</p>

<p>当然了，PhoneGap 最大的好处就是，几乎跨了几乎所有的主流智能手机平台，这对于初创团队来说，是迅速推出各个平台客户端的一个好方法。另外 PhoneGap 官方网站也提供了一系列配套服务，例如使用 PhoneGap Build 可以直接编译各个平台的程序安装包，而不需要开发者自己在本地配置每个平台的编译环境。</p>

<h2>Mono Touch</h2>

<p>Mono Touch 是一个使用 C# 来编写跨平台应用的框架，同样支持了 iOS 和 Android 两大平台。</p>

<p>Mono Touch 对于 .NET 程序员来说应该是一个好消息，除了调试，其他的都可以在 Windows 中搞定，调试的时候可以通过在虚拟机里运行 Mac OS X 来解决。Mono Touch 因为是基于 Mono 的，也有个配套的 IDE 可以用：Mono Develop。因为都是 .NET，当然也可以用 Vistual Studio 这个更强大的工具了。</p>

<p>与 Titanium Mobile 和 PhoneGap 不同的是，Mono Touch 如果要编译到设备，或者发布到 App Store 的话，是需要收费的。</p>

<p>另外，因为 Mono Touch 也是编译成可执行代码再部署到设备上的，因此运行速度相对于 PhoneGap 所制作的应用来说，应该会快上一些。</p>

<p>不过 Mono Touch 要收费，并且收费还不是很便宜，可能会影响到它的普及率。</p>

<h2>小结</h2>

<p>在上面讲的三个解决方案之外，还有其他好多大大小小的移动应用开发解决方案，但是用于 iOS 上的解决方案，主要也就是映射代码、或者是包装的形式了，对于应用而不是游戏类型来说，一般都是够用的，在具体选择的时候，也可以根据自己更为熟悉哪种语言，或者框架来挑选。</p>

<p>如果你发现了其他有意思的移动应用开发技术，也可以和我分享一下 :)</p>

<h2>参考资料</h2>

<ol>
<li><a href="http://www.appcelerator.com/products/titanium-mobile-application-development/">http://www.appcelerator.com/products/titanium-mobile-application-development/</a></li>
<li><a href="http://developer.appcelerator.com/apidoc/mobile/latest">http://developer.appcelerator.com/apidoc/mobile/latest</a></li>
<li><a href="http://phonegap.com/about">http://phonegap.com/about</a></li>
<li><a href="https://build.phonegap.com/">https://build.phonegap.com/</a></li>
<li><a href="http://www.mono-project.com/Main_Page">http://www.mono-project.com/Main_Page</a></li>
<li><a href="http://xamarin.com/monotouch">http://xamarin.com/monotouch</a></li>
<li><a href="https://github.com/xamarin/monotouch-samples">https://github.com/xamarin/monotouch-samples</a></li>
<li><a href="http://blog.zhaojie.me/2010/09/develop-ios-app-with-monotouch-in-visual-studio-1.html">http://blog.zhaojie.me/2010/09/develop-ios-app-with-monotouch-in-visual-studio-1.html</a></li>
</ol>

<p>&#8211;EOF&#8211;</p>
]]></content:encoded>
			<wfw:commentRss>http://xujiwei.com/blog/besides-objective-c/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>使用 node.js + nginx 建设网站</title>
		<link>http://xujiwei.com/blog/build-site-with-nodejs-and-nginx/</link>
		<comments>http://xujiwei.com/blog/build-site-with-nodejs-and-nginx/#comments</comments>
		<pubDate>Sun, 11 Dec 2011 09:41:49 +0000</pubDate>
		<dc:creator>Xu Jiwei</dc:creator>
				<category><![CDATA[Web]]></category>
		<category><![CDATA[cluster]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[nginx]]></category>
		<category><![CDATA[nodejs]]></category>

		<guid isPermaLink="false">http://xujiwei.com/blog/?p=525</guid>
		<description><![CDATA[<a href="http://xujiwei.com/blog/build-site-with-nodejs-and-nginx/" title="使用 node.js + nginx 建设网站"></a>昨天搞定了一个小网站的搭建，用了 node.js，另外为了能在一个 VPS 上搭建多个网站，用了 nginx 作为反向代理。 软件介绍 嗯，从维基上复制了一下～ node.js Node.js是一个事件驱动I/O伺服端JavaScript环境，基于V8。目的是为了提供撰写可扩充网络程式，如web服务。第一个版本由Ryan Dahl于2009年释出，后来，Joyent雇用了Dahl，并协助发展Node.js。 nginx nginx（发音同engine x）是一款由俄罗斯程序员Igor Sysoev所开发轻量级的网页服务器、反向代理服务器以及电子邮件（IMAP/POP3）代理服务器。 cluster 在 node.js 0.6.0 之前，有一个第三方的 node.js 模块 cluster，用来进行多核服务器上运行 node.js，以及提供扩展的支持。但是在 node.js 0.6.0 之后，node.js 本身就提供了 cluster 的支持，另外，第三方的 cluster 也与 node.js 0.6 有兼容性问题。目前 node.js 的稳定版本是 0.6.5，因此需要使用原生的 cluster 来代替第三方的 &#8230;<p class="read-more"><a href="http://xujiwei.com/blog/build-site-with-nodejs-and-nginx/">Read more &#187;</a>]]></description>
			<content:encoded><![CDATA[<a href="http://xujiwei.com/blog/build-site-with-nodejs-and-nginx/" title="使用 node.js + nginx 建设网站"></a><p>昨天搞定了一个小网站的搭建，用了 node.js，另外为了能在一个 VPS 上搭建多个网站，用了 nginx 作为反向代理。</p>

<h2>软件介绍</h2>

<p>嗯，从维基上复制了一下～</p>

<p><strong>node.js</strong></p>

<blockquote>
  <p>Node.js是一个事件驱动I/O伺服端JavaScript环境，基于V8。目的是为了提供撰写可扩充网络程式，如web服务。第一个版本由Ryan Dahl于2009年释出，后来，Joyent雇用了Dahl，并协助发展Node.js。</p>
</blockquote>

<p><strong>nginx</strong></p>

<blockquote>
  <p>nginx（发音同engine x）是一款由俄罗斯程序员Igor Sysoev所开发轻量级的网页服务器、反向代理服务器以及电子邮件（IMAP/POP3）代理服务器。</p>
</blockquote>

<h2>cluster</h2>

<p>在 node.js 0.6.0 之前，有一个第三方的 node.js 模块 cluster，用来进行多核服务器上运行 node.js，以及提供扩展的支持。但是在 node.js 0.6.0 之后，node.js 本身就提供了 cluster 的支持，另外，第三方的 cluster 也与 node.js 0.6 有兼容性问题。目前 node.js 的稳定版本是 0.6.5，因此需要使用原生的 cluster 来代替第三方的 cluster。</p>

<p>幸好内置的 cluster 也足够简单，如果只是为了多核负载均衡，以及支持即时服务重启的话，只需要写一点的代码就可以完成这些功能了。</p>

<p><strong>server.js</strong></p>

<pre><code>var path = require('path');
var http = require('http');
var cluster = require('cluster');

var NODE_ENV = process.env.NODE_ENV || 'production';
var appName = path.basename(__dirname);
var appPort = 9000;

var numCPUs = require('os').cpus().length;

if (cluster.isMaster) {
    process.title = appName + ' master';
    console.log(process.title, 'started');

    // 根据 CPU 个数来启动相应数量的 worker
    for (var i = 0; i &lt; numCPUs; i++) {
        cluster.fork();
    }

    process.on('SIGHUP', function() {
        // master 进程忽略 SIGHUP 信号
    });

    cluster.on('death', function(worker) {
        console.log(appName, 'worker', '#' + worker.pid, 'died');
        cluster.fork();
    });

} else {
    process.title = appName + ' worker ' + process.env.NODE_WORKER_ID;
    console.log(process.title, '#' + process.pid, 'started');

    process.on('SIGHUP', function() {
        // 接收到 SIGHUP 信号时，关闭 worker
        process.exit(0);
    });

    http.Server(function(req, res) {
        res.writeHead(200);
        res.end('Worker ' + process.env.NODE_WORKER_ID);
    }).listen(8000);
}
</code></pre>

<p>运行服务 <code>node server.js</code> ：</p>

<pre><code>nodejs master started
nodejs worker 1 #38928 started
nodejs worker 3 #38930 started
nodejs worker 2 #38929 started
nodejs worker 4 #38931 started
</code></pre>

<p>如果直接 kill 掉某一个 worker，<code>kill 38928</code>：</p>

<pre><code>nodejs worker #38931 died
nodejs worker 5 #38934 started
</code></pre>

<p>可以看到一个新的 worker 会马上启动，这就保证了服务的不间断性。</p>

<h2>Virtual Host 支持</h2>

<p>通常情况下，我们不会在一个 IP 上只部署一个网站。在使用 node.js 时，可以使用 connect 提供的 vhost 支持 Virtual Host，但是，这也限制了服务器只能用 node.js，而不能同时使用其他的服务，例如再安装一个 PHP 服务之类。</p>

<p>这时就可以使用 nginx 的反向代理来解决了，用户在访问网站时，请求先到 nginx 进行处理，如果是 node.js 站点的话，将请求转发到 node.js 的服务，然后再将 node.js 服务的结果返回给用户。</p>

<p>在 nginx 中设置反向代理很简单，一句 <code>proxy_pass</code> 就可以搞定：</p>

<pre><code>server {
    listen 80;
    server_name example.com;

    location / {
        proxy_pass http://localhost:9000;
    }
}
</code></pre>

<p>在添加了 Virtual Host 之后，就可以把一些静态资源，例如 CSS、JavaScript 之类的文件，直接交给 nginx 来处理，而不是什么请求都需要到 node.js 这一层去处理，也省去反向代理这一关的消耗。</p>

<h2>Session 支持</h2>

<p>使用 express 这个 node.js web framework 来创建网站时，可以配合 connect 这个中间件来实现 session 支持。</p>

<p>默认情况下，connect 的 session 是使用内置的内存存储来存放 session 信息，这时如果 node.js 服务一旦重启，所有的 session 信息都会丢失，这对于用户来说不是个好体验，那么我们可以用外部的存储来存放 session 信息，例如 redis。</p>

<p>要让 connect 使用 redis 作为 session 存储的话也是很方便的：</p>

<pre><code>var express = require('express');
var RedisStore = require('connect-redis')(express);

var app = express.createServer(
    express.session({ secret: 'keyboard cat', store : new RedisStore() })
);
</code></pre>

<h2>监测文件改动</h2>

<p>在调试的时候，经常需要重新启动 node.js 以便修改过的文件生效，原来第三方的 cluster 有一个配置项，可以很方便的配置监测时间间隔，文件改动后自动重新启动 worker，但是原生的 cluster 就没有这个功能了，需要自己来实现。</p>

<p>fs 模块提供了 watch 函数，可以方便的监测文件修改，使用这个就可以来实现文件修改后自动重启 woker 功能了。</p>

<pre><code>if (cluster.isMaster) {
    process.title = appName + ' master';
    console.log(process.title, 'started');

    var workers = [];

    // 根据 CPU 个数来启动相应数量的 worker
    for (var i = 0; i &lt; numCPUs; i++) {
        var worker = cluster.fork();
        workers.push(worker.pid);
    }

    process.on('SIGHUP', function() {
        // master 进程忽略 SIGHUP 信号
    });

    // 监测文件改动，如果有修改，就将所有的 worker kill 掉
    fs.watch(__dirname, function(event, filename) {
        workers.forEach(function(pid) {
            process.kill(pid);
        });
    });

    cluster.on('death', function(worker) {
        var index = workers.indexOf(worker.pid);
        if (index != -1) {
            workers.splice(index, 1);
        }
        console.log(appName, 'worker', '#' + worker.pid, 'died');
        worker = cluster.fork();
        workers.push(worker.pid);
    });

}
</code></pre>

<p>这样，每次文件保存之后，node.js 都会自动重启，从而避免了每次保存文件要手动重启服务的麻烦。</p>

<p>当然，在使用监测文件自动重启的时候，最好加上 NODE_ENV 的判断，在 development 的时候才进行自动重启，而 production 的时候使用手动重启就够了。</p>

<h2>小结</h2>

<p>总的来说，使用 node.js 来构建网站还是很方便的，加上 nginx 反向代理之后，与使用 PHP 之前也没有很大的区别，又可以享受到 node.js 的高效。</p>

<p>嗯，就这样了，希望此文对你有所帮助。</p>

<h2>参考资料</h2>

<ol>
<li><a href="http://zh.wikipedia.org/wiki/Node.js">http://zh.wikipedia.org/wiki/Node.js</a></li>
<li><a href="http://nodejs.org/docs/v0.6.5/api/cluster.html">http://nodejs.org/docs/v0.6.5/api/cluster.html</a></li>
<li><a href="http://learnboost.github.com/cluster/">http://learnboost.github.com/cluster/</a></li>
<li><a href="http://expressjs.com/">http://expressjs.com/</a></li>
<li><a href="http://senchalabs.github.com/connect/">http://senchalabs.github.com/connect/</a></li>
<li><a href="http://redis.io/">http://redis.io/</a></li>
</ol>

<p>&#8211;EOF&#8211;</p>
]]></content:encoded>
			<wfw:commentRss>http://xujiwei.com/blog/build-site-with-nodejs-and-nginx/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>iOS App 自定义 URL Scheme 设计</title>
		<link>http://xujiwei.com/blog/ios-app-custom-url-scheme-design/</link>
		<comments>http://xujiwei.com/blog/ios-app-custom-url-scheme-design/#comments</comments>
		<pubDate>Sat, 10 Sep 2011 07:00:40 +0000</pubDate>
		<dc:creator>Xu Jiwei</dc:creator>
				<category><![CDATA[Mac OS & iOS]]></category>
		<category><![CDATA[App]]></category>
		<category><![CDATA[iOS]]></category>
		<category><![CDATA[Scheme]]></category>
		<category><![CDATA[URL]]></category>
		<category><![CDATA[淘宝]]></category>
		<category><![CDATA[自定义协议]]></category>

		<guid isPermaLink="false">http://xujiwei.com/blog/?p=510</guid>
		<description><![CDATA[<a href="http://xujiwei.com/blog/ios-app-custom-url-scheme-design/" title="iOS App 自定义 URL Scheme 设计"></a>在 iOS 里，程序之间都是相互隔离，目前并没有一个有效的方式来做程序间通信，幸好 iOS 程序可以很方便的注册自己的 URL Scheme，这样就可以通过打开特定 URL 的方式来传递参数给另外一个程序。 例如在 iPad 上浏览网页，并且 iPad 已经安装了 淘宝 HD，那么就打开下面这个链接就会在淘宝 HD 中查看这个商品的详细信息，也可以方便的使用淘宝 HD 进行购买、收藏等操作。 在淘宝 HD 中查看商品“2012西藏卓明谷方舟登舰卡(船票)” 当然，如果你在 Mac OS X 中打开这个链接，或者在没有安装 淘宝 HD 的 iPad 中打开这个链接，会提示没有程序来打开这个链接。 配置 要为 iOS 程序添加自定义协议的支持是一件很方便的事，只需要在程序的 Info.plist 添加一个 URL &#8230;<p class="read-more"><a href="http://xujiwei.com/blog/ios-app-custom-url-scheme-design/">Read more &#187;</a>]]></description>
			<content:encoded><![CDATA[<a href="http://xujiwei.com/blog/ios-app-custom-url-scheme-design/" title="iOS App 自定义 URL Scheme 设计"></a><p>在 iOS 里，程序之间都是相互隔离，目前并没有一个有效的方式来做程序间通信，幸好 iOS 程序可以很方便的注册自己的 URL Scheme，这样就可以通过打开特定 URL 的方式来传递参数给另外一个程序。</p>

<p>例如在 iPad 上浏览网页，并且 iPad 已经安装了 <a href="http://itunes.apple.com/app/id438865278?mt=8">淘宝 HD</a>，那么就打开下面这个链接就会在淘宝 HD 中查看这个商品的详细信息，也可以方便的使用淘宝 HD 进行购买、收藏等操作。</p>

<p><a href="taobao://item.taobao.com/item.htm?id=12688928896">在淘宝 HD 中查看商品“2012西藏卓明谷方舟登舰卡(船票)”</a></p>

<p>当然，如果你在 Mac OS X 中打开这个链接，或者在没有安装 淘宝 HD 的 iPad 中打开这个链接，会提示没有程序来打开这个链接。</p>

<h2>配置</h2>

<p>要为 iOS 程序添加自定义协议的支持是一件很方便的事，只需要在程序的 Info.plist 添加一个 URL types 节点就可以了。在这个节点里，可以设置这个程序所支持的自定义协议名称，像 http、ftp 这种，一般我们可以设置为程序英文名称，像淘宝客户端中就设置了 taobao，这样 taobao:// 这个形式的 URL 就会关联到淘宝客户端的 App。</p>

<p><img src="http://developer.apple.com/library/ios/documentation/iphone/conceptual/iphoneosprogrammingguide/Art/register_custom_scheme.jpg" alt="Info.plist config" /></p>

<h2>实现</h2>

<p>在 Info.plist 里面设置完 URL types 之后，就可以在程序中处理这类 URL 的打开请求了。</p>

<p>在外部程序中，如果打开了指定自定义协议的 URL，程序中 application delegate 的 application:handleOpenURL: 方法就会被调用，在这个方法里，可以获取到触发这个方法的 URL，可以通过对这个 URL 进行判断，例如根据不同的 Host，不同的 Query String 来执行不同的动作。</p>

<pre><code>- (void)application:(UIApplication *)application handleOpenURL:(NSURL *)url {
    NSLog(@"%@", [url absoluteString]);

    // 在 host 等于 item.taobao.com 时，说明一个宝贝详情的 url，
    // 那么就使用本地的 TBItemDetailViewController 来显示
    if ([[url host] isEqualToString:@"item.taobao.com"]) {

        // 这里只是简单地假设 url 形式为 taobao://item.taobao.com/item.htm?id=12345678
        // 先获取要查看的宝贝详情的 itemId
        NSString *itemId = [[url query] substringFromIndex:[[url query] rangeOfString:@"id="].location+3];

        // 使用本地 ViewController 来显示淘宝商品详情
        TBItemDetailViewController *controller = [[TBItemDetailViewController alloc] initWithItemId:itemId];
        [self.navigationController pushViewController:controller animated:YES];
        [controller release];
    }
}
</code></pre>

<h2>淘宝 for iOS</h2>

<p>现在，淘宝 和 淘宝 HD 两个客户端都支持 taobao:// 协议，来打开特定的链接。目前已经支持的有：</p>

<ul>
<li>宝贝详情 <a href="taobao://item.taobao.com/item.htm?id=12688928896">taobao://item.taobao.com/item.htm?id=12688928896</a></li>
<li>宝贝搜索 <a href="taobao://s.taobao.com/?q=iphone">taobao://s.taobao.com/?q=iphone</a></li>
<li>店铺搜索 <a href="taobao://shopsearch.taobao.com/browse/shop_search.htm?q=iphone">taobao://shopsearch.taobao.com/browse/shop_search.htm?q=iphone</a></li>
</ul>

<p>例如，想要在自己的程序中，使用淘宝客户端来显示一个淘宝商品的详情，以支持用户可以直接在 iPhone 上购买，收藏等，就可以使用下面的代码：</p>

<pre><code>- (void)showItemInTaobao4iOS:(NSString *)itemId {
    // 构建淘宝客户端协议的 URL
    NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"taobao://item.taobao.com/item.htm?id=%@", itemId]];

    // 判断当前系统是否有安装淘宝客户端
    if ([[UIApplication sharedApplication] canOpenURL:url]) {
        // 如果已经安装淘宝客户端，就使用客户端打开链接
        [[UIApplication sharedApplication] openURL:url];
    } else {
        // 否则使用 Mobile Safari 或者内嵌 WebView 来显示
        url = [NSURL URLWithString:[NSString stringWithFormat:@"http://item.taobao.com/item.htm?id=%@", itemId]];
        [[UIApplication sharedApplication] openURL:url];
    }
}
</code></pre>

<p>使用淘宝客户端来打开淘宝链接的好处就是可以让用户更加方便的去购买商品，而不需要再重新登录，或者把用户名密码给了第三方的网站而导致安全隐患。</p>

<h2>扩展性</h2>

<p>在淘宝客户端中，支持的 URL 往往是淘宝网站已经有的链接，这些链接的 QueryString 中所带的参数往往已经满足了使用本地代码显示内容的需要，但是为了扩展性考虑，就需要添加一些额外的参数，并且与原有 QueryString 中不冲突的参数名称。通过这些额外的参数，再实现客户端打开链接时更多的自定义行为。</p>

<p>例如，如果在打开特定 URL，进行一些操作后需要再返回原来的程序，就会需要在 URL 中添加类似于 callback 这样的参数，这样在客户端处理完用户的操作后，可以将用户操作的结果返回给原来的程序，从而实现程序间的通信。</p>

<p>示例：</p>

<pre><code>- (void)buyItemInTaobao4iOS:(NSString *)itemId {
    // 构建淘宝客户端协议的 URL
    NSString *format = @"taobao://item.taobao.com/item.htm?id=%@&amp;_action=buy&amp;_callback=myapp://taobaobuysuccess";
    NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:format, itemId]];

    // 使用淘宝客户端打开链接
    [[UIApplication sharedApplication] openURL:url];
}
</code></pre>

<p><strong>注意：当前淘宝客户端并不支持这样的调用方式，这里仅是一个示例。</strong></p>

<p>当然，在使用这种方式实现程序间通信的时候，需要考虑检查一下来源 URL 的合法性，防止一些非法的调用造成用户的损失。</p>

<h2>结语</h2>

<p>通过自定义协议地支持，可以将 iOS 程序的一些功能和服务提供给外部程序，也可以实现 Web 和本地应用之间的互相调用。</p>

<p>如果你的 iOS 程序有这些需求的话，那么就可以考虑在 iOS 程序中添加自定义协议的支持了。</p>

<h2>参考资料</h2>

<ol>
<li><a href="http://developer.apple.com/library/ios/#documentation/iphone/conceptual/iphoneosprogrammingguide/StandardBehaviors/StandardBehaviors.html#//apple_ref/doc/uid/TP40007072-CH4-SW50">iOS Application Programming Guide: Implementing Custom URL Schemes</a></li>
</ol>

<p>&#8212; EOF &#8212;</p>
]]></content:encoded>
			<wfw:commentRss>http://xujiwei.com/blog/ios-app-custom-url-scheme-design/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>淘宝 for iOS 历程</title>
		<link>http://xujiwei.com/blog/taobao-for-ios-evolution/</link>
		<comments>http://xujiwei.com/blog/taobao-for-ios-evolution/#comments</comments>
		<pubDate>Wed, 17 Aug 2011 03:27:38 +0000</pubDate>
		<dc:creator>Xu Jiwei</dc:creator>
				<category><![CDATA[Mac OS & iOS]]></category>
		<category><![CDATA[iOS]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[淘宝]]></category>

		<guid isPermaLink="false">http://xujiwei.com/blog/?p=508</guid>
		<description><![CDATA[<a href="http://xujiwei.com/blog/taobao-for-ios-evolution/" title="淘宝 for iOS 历程"></a>这是在 淘宝2011技术嘉年华 上讲的关于淘宝 for iOS 开发过程的演示文稿。 View more presentations from ohdarling88. &#8212; EOF &#8212;]]></description>
			<content:encoded><![CDATA[<a href="http://xujiwei.com/blog/taobao-for-ios-evolution/" title="淘宝 for iOS 历程"></a><p>这是在 <a href="http://developerclub.taobao.com/">淘宝2011技术嘉年华</a> 上讲的关于淘宝 for iOS 开发过程的演示文稿。</p>

<div style="width:425px" id="__ss_8875347"><object id="__sse8875347" width="425" height="355"><param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=forios-110816221534-phpapp01&#038;stripped_title=for-ios&#038;userName=ohdarling88" /><param name="allowFullScreen" value="true"/><param name="allowScriptAccess" value="always"/><embed name="__sse8875347" src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=forios-110816221534-phpapp01&#038;stripped_title=for-ios&#038;userName=ohdarling88" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"></embed></object><div style="padding:5px 0 12px">View more <a href="http://www.slideshare.net/">presentations</a> from <a href="http://www.slideshare.net/ohdarling88">ohdarling88</a>.</div></div>

<p>&#8212; EOF &#8212;</p>
]]></content:encoded>
			<wfw:commentRss>http://xujiwei.com/blog/taobao-for-ios-evolution/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>给 iOS 项目添加自动更新属性</title>
		<link>http://xujiwei.com/blog/auto-update-attr-in-ios-project/</link>
		<comments>http://xujiwei.com/blog/auto-update-attr-in-ios-project/#comments</comments>
		<pubDate>Tue, 02 Aug 2011 08:07:41 +0000</pubDate>
		<dc:creator>Xu Jiwei</dc:creator>
				<category><![CDATA[Develop]]></category>
		<category><![CDATA[Mac OS & iOS]]></category>
		<category><![CDATA[Bash]]></category>
		<category><![CDATA[Git]]></category>
		<category><![CDATA[iOS]]></category>
		<category><![CDATA[Xcode]]></category>

		<guid isPermaLink="false">http://xujiwei.com/blog/?p=487</guid>
		<description><![CDATA[<a href="http://xujiwei.com/blog/auto-update-attr-in-ios-project/" title="给 iOS 项目添加自动更新属性"></a>在 iOS 项目中，有些时候为了方便跟踪发布时的版本，方便调试，或者为了展示程序的编译日期，可以通过在 Info.plist 里面添加自定义属性的方式来实现，但是这个工作是一个纯粹机械的重复劳动，每次手工去更新是比较麻烦的一个事情。 好在 Xcode 项目支持自定义脚本的编译步骤，我们可以通过在编译过程中使用自定义脚本去更新 Info.plist。 在 /usr/libexec 目录下面，有一个工具 PlistBuddy，它可以很方便地修改 plist 文件，而不需要去用 sed 之类的编辑工具来修改。 为了在使用 PlistBuddy 的时候可以直接用 Set 命令设置属性，我们先在 iOS 项目的 Info.plist 里面加一个需要自动更新的属性，例如 BUILD_DATE 和 GIT_REVISION，类型选择为字符串，值填 AUTO_GENERATED。 然后在 iOS 项目的 Target 上添加一个新的编译步骤 Run Script Build Phase： 下页就是要编写脚本了 &#8230;<p class="read-more"><a href="http://xujiwei.com/blog/auto-update-attr-in-ios-project/">Read more &#187;</a>]]></description>
			<content:encoded><![CDATA[<a href="http://xujiwei.com/blog/auto-update-attr-in-ios-project/" title="给 iOS 项目添加自动更新属性"></a><p>在 iOS 项目中，有些时候为了方便跟踪发布时的版本，方便调试，或者为了展示程序的编译日期，可以通过在 Info.plist 里面添加自定义属性的方式来实现，但是这个工作是一个纯粹机械的重复劳动，每次手工去更新是比较麻烦的一个事情。</p>

<p>好在 Xcode 项目支持自定义脚本的编译步骤，我们可以通过在编译过程中使用自定义脚本去更新 Info.plist。</p>

<p>在 /usr/libexec 目录下面，有一个工具 PlistBuddy，它可以很方便地修改 plist 文件，而不需要去用 sed 之类的编辑工具来修改。</p>

<p>为了在使用 PlistBuddy 的时候可以直接用 Set 命令设置属性，我们先在 iOS 项目的 Info.plist 里面加一个需要自动更新的属性，例如 BUILD_DATE 和 GIT_REVISION，类型选择为字符串，值填 AUTO_GENERATED。</p>

<p>然后在 iOS 项目的 Target 上添加一个新的编译步骤 Run Script Build Phase：</p>

<p><a href="http://xujiwei.com/blog/wp-content/uploads/2011/08/add_script_step.png"><img src="http://xujiwei.com/blog/wp-content/uploads/2011/08/add_script_step-300x97.png" alt="" title="add_script_step" width="300" height="97" class="alignnone size-medium wp-image-488" /></a></p>

<p>下页就是要编写脚本了</p>


<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># 获取编译的日期</span>
<span style="color: #007800;">DATE</span>=<span style="color: #000000; font-weight: bold;">`</span><span style="color: #c20cb9; font-weight: bold;">date</span> +<span style="color: #000000; font-weight: bold;">%</span>Y.<span style="color: #000000; font-weight: bold;">%</span>m.<span style="color: #000000; font-weight: bold;">%</span>d<span style="color: #000000; font-weight: bold;">`</span>
&nbsp;
<span style="color: #666666; font-style: italic;"># 获取编译时 Git 库的短版本号</span>
<span style="color: #007800;">GIT_REVISION</span>=<span style="color: #000000; font-weight: bold;">`</span><span style="color: #c20cb9; font-weight: bold;">git</span> rev-parse <span style="color: #660033;">--short</span> HEAD<span style="color: #000000; font-weight: bold;">`</span>
&nbsp;
<span style="color: #666666; font-style: italic;"># 设置 Info.plist 中相关的属性</span>
<span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>libexec<span style="color: #000000; font-weight: bold;">/</span>PlistBuddy <span style="color: #ff0000;">&quot;<span style="color: #007800;">$TARGET_BUILD_DIR</span>/<span style="color: #007800;">$INFOPLIST_PATH</span>&quot;</span> <span style="color: #660033;">-c</span> <span style="color: #ff0000;">&quot;Set BUILD_DATE <span style="color: #007800;">$DATE</span>&quot;</span>
<span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>libexec<span style="color: #000000; font-weight: bold;">/</span>PlistBuddy <span style="color: #ff0000;">&quot;<span style="color: #007800;">$TARGET_BUILD_DIR</span>/<span style="color: #007800;">$INFOPLIST_PATH</span>&quot;</span> <span style="color: #660033;">-c</span> <span style="color: #ff0000;">&quot;Set GIT_REVISION <span style="color: #007800;">$GIT_REVISION</span>&quot;</span>
&nbsp;
<span style="color: #666666; font-style: italic;"># 将 Info.plist 转换为二进制格式</span>
plutil <span style="color: #660033;">-convert</span> binary1 <span style="color: #ff0000;">&quot;<span style="color: #007800;">$TARGET_BUILD_DIR</span>/<span style="color: #007800;">$INFOPLIST_PATH</span>&quot;</span></pre></div></div>


<p>如果需要在程序里获取这些属性，那么就可以用下面的方法：</p>


<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;">NSString <span style="color: #339933;">*</span>buildDate <span style="color: #339933;">=</span> <span style="color: #009900;">&#91;</span><span style="color: #009900;">&#91;</span>NSBundle mainBundle<span style="color: #009900;">&#93;</span> objectForInfoDictionaryKey<span style="color: #339933;">:</span>@<span style="color: #ff0000;">&quot;BUILD_DATE&quot;</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
NSString <span style="color: #339933;">*</span>revision <span style="color: #339933;">=</span> <span style="color: #009900;">&#91;</span><span style="color: #009900;">&#91;</span>NSBundle mainBundle<span style="color: #009900;">&#93;</span> objectForInfoDictionaryKey<span style="color: #339933;">:</span>@<span style="color: #ff0000;">&quot;GIT_REVISION&quot;</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span></pre></div></div>


<p>&#8212; EOF &#8212;</p>
]]></content:encoded>
			<wfw:commentRss>http://xujiwei.com/blog/auto-update-attr-in-ios-project/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>爱糗事上线啦</title>
		<link>http://xujiwei.com/blog/ihappy-released/</link>
		<comments>http://xujiwei.com/blog/ihappy-released/#comments</comments>
		<pubDate>Mon, 04 Oct 2010 02:18:01 +0000</pubDate>
		<dc:creator>Xu Jiwei</dc:creator>
				<category><![CDATA[Mobile]]></category>
		<category><![CDATA[iPad]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[爱糗事]]></category>
		<category><![CDATA[糗事百科]]></category>

		<guid isPermaLink="false">http://www.xujiwei.com/blog/?p=340</guid>
		<description><![CDATA[<a href="http://xujiwei.com/blog/ihappy-released/" title="爱糗事上线啦"></a>漫长的 In Review 终于过了，爱糗事终于上线了。 爱糗事是一个糗事百科的 iOS 客户端，支持 iPhone 以及 iPad，详细介绍及截图请看这里 通过 iTunes 下载]]></description>
			<content:encoded><![CDATA[<a href="http://xujiwei.com/blog/ihappy-released/" title="爱糗事上线啦"></a><p>漫长的 In Review 终于过了，爱糗事终于上线了。</p>

<p>爱糗事是一个糗事百科的 iOS 客户端，支持 iPhone 以及 iPad，详细介绍及截图<a href="http://ihappy.xujiwei.com">请看这里</a></p>

<p><a href="itms://itunes.apple.com/app/id391905312?mt=8">通过 iTunes 下载</a></p>
]]></content:encoded>
			<wfw:commentRss>http://xujiwei.com/blog/ihappy-released/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Snow Leopard Server 上配置 Gitosis 笔记</title>
		<link>http://xujiwei.com/blog/configure-gitosis-on-snow-leopard-server/</link>
		<comments>http://xujiwei.com/blog/configure-gitosis-on-snow-leopard-server/#comments</comments>
		<pubDate>Wed, 21 Jul 2010 05:56:04 +0000</pubDate>
		<dc:creator>Xu Jiwei</dc:creator>
				<category><![CDATA[Management]]></category>
		<category><![CDATA[Notes]]></category>
		<category><![CDATA[Git]]></category>
		<category><![CDATA[Gitosis]]></category>
		<category><![CDATA[Mac OS X]]></category>
		<category><![CDATA[VCS]]></category>

		<guid isPermaLink="false">http://www.xujiwei.com/blog/?p=313</guid>
		<description><![CDATA[<a href="http://xujiwei.com/blog/configure-gitosis-on-snow-leopard-server/" title="Snow Leopard Server 上配置 Gitosis 笔记"></a>为了迁移项目 Git 仓库到 Mini Server 上，需要在 Snow Leopard Server 上配置一下 Gitosis，但是 Mac OS X 和 Linux 不太一样，有些地方需要特殊处理一下。 安装 Gitosis Gitosis 的安装就不多说，在参考文档2中有。 添加 Git 用户组及用户 添加用户可以用参考文档1中的方法来创建，没有尝试直接用 OSX 的用户管理来创建是否可用。 # 这里的用户组和用户ID 用 401，但是实际用时需要根据服务器上的情况来创建 # 我在使用时 401 这个 gid 就已经被占用了，可以使用以下两个命令看看要用的 # ID 是否已经被用了。 &#8230;<p class="read-more"><a href="http://xujiwei.com/blog/configure-gitosis-on-snow-leopard-server/">Read more &#187;</a>]]></description>
			<content:encoded><![CDATA[<a href="http://xujiwei.com/blog/configure-gitosis-on-snow-leopard-server/" title="Snow Leopard Server 上配置 Gitosis 笔记"></a><p>为了迁移项目 Git 仓库到 Mini Server 上，需要在 Snow Leopard Server 上配置一下 Gitosis，但是 Mac OS X 和 Linux 不太一样，有些地方需要特殊处理一下。</p>

<h3>安装 Gitosis</h3>

<p>Gitosis 的安装就不多说，在参考文档2中有。</p>

<h3>添加 Git 用户组及用户</h3>

<p>添加用户可以用参考文档1中的方法来创建，没有尝试直接用 OSX 的用户管理来创建是否可用。</p>


<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># 这里的用户组和用户ID 用 401，但是实际用时需要根据服务器上的情况来创建</span>
<span style="color: #666666; font-style: italic;"># 我在使用时 401 这个 gid 就已经被占用了，可以使用以下两个命令看看要用的</span>
<span style="color: #666666; font-style: italic;"># ID 是否已经被用了。</span>
<span style="color: #c20cb9; font-weight: bold;">sudo</span> dscl . list <span style="color: #000000; font-weight: bold;">/</span>Users uid
<span style="color: #c20cb9; font-weight: bold;">sudo</span> dscl . list <span style="color: #c20cb9; font-weight: bold;">groups</span> gid
&nbsp;
<span style="color: #666666; font-style: italic;"># 创建用户组 git</span>
<span style="color: #c20cb9; font-weight: bold;">sudo</span> dscl . create groups<span style="color: #000000; font-weight: bold;">/</span><span style="color: #c20cb9; font-weight: bold;">git</span>
<span style="color: #c20cb9; font-weight: bold;">sudo</span> dscl . create groups<span style="color: #000000; font-weight: bold;">/</span><span style="color: #c20cb9; font-weight: bold;">git</span> gid <span style="color: #000000;">401</span>
&nbsp;
<span style="color: #666666; font-style: italic;"># 创建用户 git</span>
<span style="color: #c20cb9; font-weight: bold;">sudo</span> dscl . create users<span style="color: #000000; font-weight: bold;">/</span><span style="color: #c20cb9; font-weight: bold;">git</span>
<span style="color: #c20cb9; font-weight: bold;">sudo</span> dscl . create users<span style="color: #000000; font-weight: bold;">/</span><span style="color: #c20cb9; font-weight: bold;">git</span> uid <span style="color: #000000;">401</span>
<span style="color: #c20cb9; font-weight: bold;">sudo</span> dscl . create users<span style="color: #000000; font-weight: bold;">/</span><span style="color: #c20cb9; font-weight: bold;">git</span> NFSHomeDirectory <span style="color: #000000; font-weight: bold;">/</span>Users<span style="color: #000000; font-weight: bold;">/</span><span style="color: #c20cb9; font-weight: bold;">git</span>
<span style="color: #c20cb9; font-weight: bold;">sudo</span> dscl . create users<span style="color: #000000; font-weight: bold;">/</span><span style="color: #c20cb9; font-weight: bold;">git</span> gid <span style="color: #000000;">401</span>
<span style="color: #c20cb9; font-weight: bold;">sudo</span> dscl . create users<span style="color: #000000; font-weight: bold;">/</span><span style="color: #c20cb9; font-weight: bold;">git</span> UserShell <span style="color: #000000; font-weight: bold;">/</span>bin<span style="color: #000000; font-weight: bold;">/</span><span style="color: #c20cb9; font-weight: bold;">bash</span>
<span style="color: #c20cb9; font-weight: bold;">sudo</span> dscl . create users<span style="color: #000000; font-weight: bold;">/</span><span style="color: #c20cb9; font-weight: bold;">git</span> Password <span style="color: #ff0000;">'*'</span>
&nbsp;
<span style="color: #666666; font-style: italic;"># 创建用户主目录，Git 仓库就要放在里面</span>
<span style="color: #c20cb9; font-weight: bold;">sudo</span> <span style="color: #c20cb9; font-weight: bold;">mkdir</span> <span style="color: #000000; font-weight: bold;">/</span>Users<span style="color: #000000; font-weight: bold;">/</span><span style="color: #c20cb9; font-weight: bold;">git</span>
<span style="color: #c20cb9; font-weight: bold;">sudo</span> <span style="color: #c20cb9; font-weight: bold;">chown</span> <span style="color: #c20cb9; font-weight: bold;">git</span> <span style="color: #000000; font-weight: bold;">/</span>Users<span style="color: #000000; font-weight: bold;">/</span><span style="color: #c20cb9; font-weight: bold;">git</span>
<span style="color: #c20cb9; font-weight: bold;">sudo</span> <span style="color: #c20cb9; font-weight: bold;">chgrp</span> <span style="color: #c20cb9; font-weight: bold;">git</span> <span style="color: #000000; font-weight: bold;">/</span>Users<span style="color: #000000; font-weight: bold;">/</span><span style="color: #c20cb9; font-weight: bold;">git</span>
&nbsp;
<span style="color: #666666; font-style: italic;"># 下面这一句是把 git 用户添加到可以使用 ssh 访问的用户组里面</span>
<span style="color: #666666; font-style: italic;"># 如果不执行这句的话，git push 或者 git pull 等等的时候会出错</span>
<span style="color: #c20cb9; font-weight: bold;">sudo</span> dscl . <span style="color: #660033;">-append</span> <span style="color: #000000; font-weight: bold;">/</span>Groups<span style="color: #000000; font-weight: bold;">/</span>com.apple.access_ssh GroupMembership <span style="color: #c20cb9; font-weight: bold;">git</span></pre></div></div>


<h3>配置 Gitosis</h3>

<p>这个在参考文档2中都有详细说明。</p>

<h3>参考文档</h3>

<ol>
<li><a href="http://blog.ardes.com/2008/5/19/git-hosting-with-leopard">git hosting with Leopard</a>, Ian White</li>
<li><a href="http://progit.org/book/zh/ch4-7.html">权限管理器 Gitosis</a>, Pro Git
</li><li><a href="http://punk-apple.livejournal.com/261072.html">Adduser for Mac OS X = dscl + niutil + nicl</a>, otaku ramblings</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://xujiwei.com/blog/configure-gitosis-on-snow-leopard-server/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>[Cocoa学习］格式化日期和解析日期字符串</title>
		<link>http://xujiwei.com/blog/format-date-and-parse-date/</link>
		<comments>http://xujiwei.com/blog/format-date-and-parse-date/#comments</comments>
		<pubDate>Wed, 26 May 2010 04:57:04 +0000</pubDate>
		<dc:creator>Xu Jiwei</dc:creator>
				<category><![CDATA[Mac OS & iOS]]></category>
		<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[NSDate]]></category>
		<category><![CDATA[NSDateFormatter]]></category>

		<guid isPermaLink="false">http://www.xujiwei.com/blog/?p=308</guid>
		<description><![CDATA[<a href="http://xujiwei.com/blog/format-date-and-parse-date/" title="[Cocoa学习］格式化日期和解析日期字符串"></a>在应用程序中，显示消息的时候一般都需要附带一个消息接收的时间，使用 NSDate 和 NSDateFormatter 即可完成格式化输出日期的任务，但是在使用时会比较麻烦，通过 Category 的方式来给 NSDate 类直接添加两个类方法来做这些事情会比较好，在以后需要格式化字符串时不需要每次都去创建一个 NSDateFormatter 对象。 对于解析日期时间也是同理。 @interface NSDate &#40;FormatString&#41; &#160; - &#40;NSString*&#41;stringWithFormat:&#40;NSString*&#41;fmt; + &#40;NSDate*&#41;dateFromString:&#40;NSString*&#41;str withFormat:&#40;NSString*&#41;fmt; &#160; @end &#160; @implementation NSDate &#40;FormatString&#41; &#160; - &#40;NSString*&#41;stringWithFormat:&#40;NSString*&#41;fmt &#123; static NSDateFormatter *fmtter; &#160; if &#40;fmtter == nil&#41; &#123; &#8230;<p class="read-more"><a href="http://xujiwei.com/blog/format-date-and-parse-date/">Read more &#187;</a>]]></description>
			<content:encoded><![CDATA[<a href="http://xujiwei.com/blog/format-date-and-parse-date/" title="[Cocoa学习］格式化日期和解析日期字符串"></a><p>在应用程序中，显示消息的时候一般都需要附带一个消息接收的时间，使用 NSDate 和 NSDateFormatter 即可完成格式化输出日期的任务，但是在使用时会比较麻烦，通过 Category 的方式来给 NSDate 类直接添加两个类方法来做这些事情会比较好，在以后需要格式化字符串时不需要每次都去创建一个 NSDateFormatter 对象。</p>

<p>对于解析日期时间也是同理。</p>


<div class="wp_syntax"><div class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #a61390;">@interface</span> <span style="color: #400080;">NSDate</span> <span style="color: #002200;">&#40;</span>FormatString<span style="color: #002200;">&#41;</span>
&nbsp;
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span><span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>stringWithFormat<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span><span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>fmt;
<span style="color: #002200;">+</span> <span style="color: #002200;">&#40;</span><span style="color: #400080;">NSDate</span><span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>dateFromString<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span><span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>str withFormat<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span><span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>fmt;
&nbsp;
<span style="color: #a61390;">@end</span>
&nbsp;
<span style="color: #a61390;">@implementation</span> <span style="color: #400080;">NSDate</span> <span style="color: #002200;">&#40;</span>FormatString<span style="color: #002200;">&#41;</span>
&nbsp;
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span><span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>stringWithFormat<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span><span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>fmt <span style="color: #002200;">&#123;</span>
    <span style="color: #a61390;">static</span> <span style="color: #400080;">NSDateFormatter</span> <span style="color: #002200;">*</span>fmtter;
&nbsp;
    <span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span>fmtter <span style="color: #002200;">==</span> <span style="color: #a61390;">nil</span><span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span>
        fmtter <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #400080;">NSDateFormatter</span> alloc<span style="color: #002200;">&#93;</span> init<span style="color: #002200;">&#93;</span>;
    <span style="color: #002200;">&#125;</span>
&nbsp;
    <span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span>fmt <span style="color: #002200;">==</span> <span style="color: #a61390;">nil</span> || <span style="color: #002200;">&#91;</span>fmt isEqualToString<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;&quot;</span><span style="color: #002200;">&#93;</span><span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span>
        fmt <span style="color: #002200;">=</span> <span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;HH:mm:ss&quot;</span>;
    <span style="color: #002200;">&#125;</span>
&nbsp;
    <span style="color: #002200;">&#91;</span>fmtter setDateFormat<span style="color: #002200;">:</span>fmt<span style="color: #002200;">&#93;</span>;
&nbsp;
    <span style="color: #a61390;">return</span> <span style="color: #002200;">&#91;</span>fmtter stringFromDate<span style="color: #002200;">:</span>self<span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #002200;">+</span> <span style="color: #002200;">&#40;</span><span style="color: #400080;">NSDate</span><span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>dateFromString<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span><span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>str withFormat<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span><span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>fmt <span style="color: #002200;">&#123;</span>
    <span style="color: #a61390;">static</span> <span style="color: #400080;">NSDateFormatter</span> <span style="color: #002200;">*</span>fmtter;
&nbsp;
    <span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span>fmtter <span style="color: #002200;">==</span> <span style="color: #a61390;">nil</span><span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span>
        fmtter <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #400080;">NSDateFormatter</span> alloc<span style="color: #002200;">&#93;</span> init<span style="color: #002200;">&#93;</span>;
    <span style="color: #002200;">&#125;</span>
&nbsp;
    <span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span>fmt <span style="color: #002200;">==</span> <span style="color: #a61390;">nil</span> || <span style="color: #002200;">&#91;</span>fmt isEqualToString<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;&quot;</span><span style="color: #002200;">&#93;</span><span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span>
        fmt <span style="color: #002200;">=</span> <span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;HH:mm:ss&quot;</span>;
    <span style="color: #002200;">&#125;</span>
&nbsp;
    <span style="color: #002200;">&#91;</span>fmtter setDateFormat<span style="color: #002200;">:</span>fmt<span style="color: #002200;">&#93;</span>;
&nbsp;
    <span style="color: #a61390;">return</span> <span style="color: #002200;">&#91;</span>fmtter dateFromString<span style="color: #002200;">:</span>str<span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #a61390;">@end</span></pre></div></div>


<p>在这里，dataFromString 和 stringWithFormat 如果没有指定格式字符串参数的话，默认会使用 HH:mm:ss 来格式日期，当然，如果实际应用场景不一样，这里也可以修改。</p>

<p>如果需要更强大的功能，也可以去修改两个方法来符合自己的需要。</p>


<div class="wp_syntax"><div class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #11740a; font-style: italic;">// 获取当前时间的字符串</span>
<span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span>now <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #400080;">NSDate</span> date<span style="color: #002200;">&#93;</span> stringWithFormat<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;HH:mm:ss&quot;</span><span style="color: #002200;">&#93;</span>;
&nbsp;
<span style="color: #11740a; font-style: italic;">// 将一个字符串解析成 NSDate 对象</span>
NSStirng <span style="color: #002200;">*</span>recvTime <span style="color: #002200;">=</span> <span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;2010-05-25 16:58:34 +0800&quot;</span>;
<span style="color: #400080;">NSDate</span>  <span style="color: #002200;">*</span>recv <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSDate</span> dateFromString<span style="color: #002200;">:</span>recvTime withFormat<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;yyyy-MM-dd HH:mm:ss Z&quot;</span><span style="color: #002200;">&#93;</span>;</pre></div></div>


<p>使用 Category 给 NSDate 类添加这两个方法后，再要格式化日期或者解析日期时间字符串，就不需要额外去创建 NSDateFormatter 对象了，可以省不少力气。</p>

<p><strong>参考资料</strong></p>

<ul>
<li><a href="http://stackoverflow.com/questions/399527/parsing-unsupported-date-formats-in-via-cocoas-nsdate">Parsing unsupported date formats in via Cocoa’s NSDate</a></li>
<li><a href="http://stackoverflow.com/questions/822417/why-cant-i-correctly-parse-this-date-string-with-nsdateformatter">Why can’t I correctly parse this date string with NSDateFormatter?</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://xujiwei.com/blog/format-date-and-parse-date/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>[Cocoa学习] 限制 NSTextField 中输入文本的长度</title>
		<link>http://xujiwei.com/blog/limit-text-length-of-nstextfield/</link>
		<comments>http://xujiwei.com/blog/limit-text-length-of-nstextfield/#comments</comments>
		<pubDate>Tue, 25 May 2010 07:36:39 +0000</pubDate>
		<dc:creator>Xu Jiwei</dc:creator>
				<category><![CDATA[Mac OS & iOS]]></category>
		<category><![CDATA[Mac]]></category>
		<category><![CDATA[NSTextField]]></category>

		<guid isPermaLink="false">http://www.xujiwei.com/blog/?p=299</guid>
		<description><![CDATA[<a href="http://xujiwei.com/blog/limit-text-length-of-nstextfield/" title="[Cocoa学习] 限制 NSTextField 中输入文本的长度"></a>需求 NSTextField 作为一个常用的输入控件，有些在使用时需要去限制其中可以输入文本的长度，而 NSTextField 本身并没有提供这个功能，这就需要我们自己去想办法来实现了。 方法 在网上找了一下，发现可以通过继承 NSFormatter 实现一个子类来实现这个功能，参考了一下找到的代码[1]，再将主要的 isPartialStringValid 方法根据自己的需要改了一下。 &#160; - &#40;BOOL&#41;isPartialStringValid:&#40;NSString **&#41;partialStringPtr proposedSelectedRange:&#40;NSRangePointer&#41;proposedSelRangePtr originalString:&#40;NSString *&#41;origString originalSelectedRange:&#40;NSRange&#41;origSelRange errorDescription:&#40;NSString **&#41;error &#123; int size = &#91;*partialStringPtr length&#93;; if &#40; size &#62; maxLength &#41; &#123; if &#40;origSelRange.location == &#91;origString length&#93;&#41; &#123; &#8230;<p class="read-more"><a href="http://xujiwei.com/blog/limit-text-length-of-nstextfield/">Read more &#187;</a>]]></description>
			<content:encoded><![CDATA[<a href="http://xujiwei.com/blog/limit-text-length-of-nstextfield/" title="[Cocoa学习] 限制 NSTextField 中输入文本的长度"></a><h4>需求</h4>

<p>NSTextField 作为一个常用的输入控件，有些在使用时需要去限制其中可以输入文本的长度，而 NSTextField 本身并没有提供这个功能，这就需要我们自己去想办法来实现了。</p>

<h4>方法</h4>

<p>在网上找了一下，发现可以通过继承 NSFormatter 实现一个子类来实现这个功能，参考了一下找到的代码<sup><a href="#ref-1">[1]</a></sup>，再将主要的 isPartialStringValid 方法根据自己的需要改了一下。</p>


<div class="wp_syntax"><div class="code"><pre class="objc" style="font-family:monospace;">&nbsp;
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">BOOL</span><span style="color: #002200;">&#41;</span>isPartialStringValid<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span> <span style="color: #002200;">**</span><span style="color: #002200;">&#41;</span>partialStringPtr
       proposedSelectedRange<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span>NSRangePointer<span style="color: #002200;">&#41;</span>proposedSelRangePtr
              originalString<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>origString
       originalSelectedRange<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">NSRange</span><span style="color: #002200;">&#41;</span>origSelRange
            errorDescription<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span> <span style="color: #002200;">**</span><span style="color: #002200;">&#41;</span>error 
<span style="color: #002200;">&#123;</span>
    <span style="color: #a61390;">int</span> size <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">*</span>partialStringPtr length<span style="color: #002200;">&#93;</span>;
    <span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span> size &gt; maxLength <span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span>
        <span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span>origSelRange.location <span style="color: #002200;">==</span> <span style="color: #002200;">&#91;</span>origString length<span style="color: #002200;">&#93;</span><span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span>
            <span style="color: #11740a; font-style: italic;">// 如果修改的位置在原来字符串的最后，则不做修改，只是拒绝内容修改</span>
        <span style="color: #002200;">&#125;</span> <span style="color: #a61390;">else</span> <span style="color: #002200;">&#123;</span>
            <span style="color: #11740a; font-style: italic;">// 如果修改的位置在原来字符串的中间，就根据剩余的可用的长度把新增加的字符串进行截取</span>
            <span style="color: #a61390;">int</span> preLen <span style="color: #002200;">=</span> origSelRange.location <span style="color: #002200;">+</span> <span style="color: #002200;">&#40;</span>maxLength <span style="color: #002200;">-</span> <span style="color: #002200;">&#91;</span>origString length<span style="color: #002200;">&#93;</span><span style="color: #002200;">&#41;</span> <span style="color: #002200;">+</span> origSelRange.length;
            <span style="color: #002200;">*</span>partialStringPtr <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSString</span> stringWithFormat<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;%@%@&quot;</span>,
                                 <span style="color: #002200;">&#91;</span><span style="color: #002200;">*</span>partialStringPtr substringToIndex<span style="color: #002200;">:</span>preLen<span style="color: #002200;">&#93;</span>,
                                 <span style="color: #002200;">&#91;</span>origString substringFromIndex<span style="color: #002200;">:</span>origSelRange.location<span style="color: #002200;">+</span>origSelRange.length<span style="color: #002200;">&#93;</span><span style="color: #002200;">&#93;</span>;
&nbsp;
            <span style="color: #002200;">&#40;</span><span style="color: #002200;">*</span>proposedSelRangePtr<span style="color: #002200;">&#41;</span>.location <span style="color: #002200;">=</span> preLen;
        <span style="color: #002200;">&#125;</span>
&nbsp;
        <span style="color: #a61390;">return</span> <span style="color: #a61390;">NO</span>;
    <span style="color: #002200;">&#125;</span>
    <span style="color: #a61390;">return</span> <span style="color: #a61390;">YES</span>;
<span style="color: #002200;">&#125;</span></pre></div></div>


<h4>参考资料</h4>

<ul><li id="ref-1"><a href="http://stackoverflow.com/questions/827014/how-to-limit-nstextfield-text-length-and-keep-it-always-upper-case">How to limit NSTextField text length and keep it always upper case?</a></li></ul>
]]></content:encoded>
			<wfw:commentRss>http://xujiwei.com/blog/limit-text-length-of-nstextfield/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>在 REALbasic 中注册 AppleEvent</title>
		<link>http://xujiwei.com/blog/register-appleevent-in-realbasic/</link>
		<comments>http://xujiwei.com/blog/register-appleevent-in-realbasic/#comments</comments>
		<pubDate>Sun, 31 Jan 2010 06:37:19 +0000</pubDate>
		<dc:creator>Xu Jiwei</dc:creator>
				<category><![CDATA[Mac OS & iOS]]></category>
		<category><![CDATA[AppleEvent]]></category>
		<category><![CDATA[Mac]]></category>
		<category><![CDATA[REALbasic]]></category>

		<guid isPermaLink="false">http://www.xujiwei.com/blog/?p=228</guid>
		<description><![CDATA[<a href="http://xujiwei.com/blog/register-appleevent-in-realbasic/" title="在 REALbasic 中注册 AppleEvent"></a>之前为了注册一个自定义协议，需要通过注册 AppleEvent 来实现，在 Objective-C 中，可以很方便的使用 NSAppleEventManager 来注册 AppleEvent 句柄，但是在 REALbaisc 中，是没有办法直接去调用 NSAppleEventManager 的，所以需要通过声明然后调用 C API 来实现相应的功能。 与 NSAppleEventManager 中功能相对应的 C API 有 AEInstallEventHandler, NewAEEventHandlerUPP 等，通过这些 API 我们也可以在 REALbasic 中来注册 AppleEvent 了，再配合 Info.plist 中的 URLScheme 声明，即可实现 URL 自定义协议处理句柄。 #if TargetCarbon soft &#8230;<p class="read-more"><a href="http://xujiwei.com/blog/register-appleevent-in-realbasic/">Read more &#187;</a>]]></description>
			<content:encoded><![CDATA[<a href="http://xujiwei.com/blog/register-appleevent-in-realbasic/" title="在 REALbasic 中注册 AppleEvent"></a><p>之前为了注册一个自定义协议，需要通过注册 AppleEvent 来实现，在 Objective-C 中，可以很方便的使用 NSAppleEventManager 来注册 AppleEvent 句柄，但是在 REALbaisc 中，是没有办法直接去调用 NSAppleEventManager 的，所以需要通过声明然后调用 C API 来实现相应的功能。</p>

<p>与 NSAppleEventManager 中功能相对应的 C API 有 AEInstallEventHandler, NewAEEventHandlerUPP 等，通过这些 API 我们也可以在 REALbasic 中来注册 AppleEvent 了，再配合 Info.plist 中的 URLScheme 声明，即可实现 URL 自定义协议处理句柄。</p>


<div class="wp_syntax"><div class="code"><pre class="vb" style="font-family:monospace;">#if TargetCarbon
    soft <span style="color: #151B8D; font-weight: bold;">declare</span> <span style="color: #E56717; font-weight: bold;">function</span> AEInstallEventHandler Lib CarbonLib ( _
    theAEEventClass <span style="color: #151B8D; font-weight: bold;">as</span> <span style="color: #F660AB; font-weight: bold;">Integer</span>, _
    theAEEventID <span style="color: #151B8D; font-weight: bold;">as</span> <span style="color: #F660AB; font-weight: bold;">Integer</span>, _
    handler <span style="color: #151B8D; font-weight: bold;">as</span> <span style="color: #F660AB; font-weight: bold;">Integer</span>, _
    handlerRefcon <span style="color: #151B8D; font-weight: bold;">as</span> <span style="color: #F660AB; font-weight: bold;">Integer</span>, _
    isSysHandler <span style="color: #151B8D; font-weight: bold;">as</span> <span style="color: #F660AB; font-weight: bold;">Boolean</span>) <span style="color: #151B8D; font-weight: bold;">as</span> <span style="color: #F660AB; font-weight: bold;">Integer</span>
&nbsp;
    Soft <span style="color: #151B8D; font-weight: bold;">Declare</span> <span style="color: #E56717; font-weight: bold;">Function</span> NewAEEventHandlerUPP Lib CarbonLib (userRoutine <span style="color: #151B8D; font-weight: bold;">as</span> Ptr) <span style="color: #151B8D; font-weight: bold;">as</span> <span style="color: #F660AB; font-weight: bold;">Integer</span>
&nbsp;
    <span style="color: #151B8D; font-weight: bold;">Static</span> CallbackUPP <span style="color: #151B8D; font-weight: bold;">as</span> <span style="color: #F660AB; font-weight: bold;">Integer</span> = 0
    <span style="color: #8D38C9; font-weight: bold;">If</span> CallbackUPP = 0 <span style="color: #8D38C9; font-weight: bold;">then</span>
      <span style="color: #151B8D; font-weight: bold;">dim</span> m <span style="color: #151B8D; font-weight: bold;">as</span> MemoryBlock =  AddressOf ForwardCarbonAEEventToObject
      <span style="color: #8D38C9; font-weight: bold;">If</span> m <span style="color: #8D38C9; font-weight: bold;">is</span> nil <span style="color: #8D38C9; font-weight: bold;">then</span>
        Return
      <span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #8D38C9; font-weight: bold;">if</span>
      CallbackUPP = NewAEEventHandlerUPP(m)
    <span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #8D38C9; font-weight: bold;">if</span>
&nbsp;
    <span style="color: #151B8D; font-weight: bold;">dim</span> v <span style="color: #151B8D; font-weight: bold;">as</span> <span style="color: #F660AB; font-weight: bold;">Variant</span> = me
&nbsp;
    <span style="color: #151B8D; font-weight: bold;">dim</span> OSError <span style="color: #151B8D; font-weight: bold;">as</span> <span style="color: #F660AB; font-weight: bold;">Integer</span> = AEInstallEventHandler( _
    OSTypeToUInt(kInternetEventClass), _
    OSTypeToUInt(kAEGetURL), _
    CallbackUPP, _
    v.Hash, <span style="color: #00C2FF; font-weight: bold;">false</span>)
&nbsp;
    msgbox str(OSError)
#endif</pre></div></div>


<p>先使用 NewAEEventHandlerUPP 来生成一个 AppleEvent 回调函数的句柄，然后调用 AEInstallEventHandler 来注册一个共享函数 ForwardCarbonAEEventToObject 为 AppleEvent 事件处理句柄。</p>

<p>AEInstallEventHandler 所需的 AEEventClass 和 AEEventID 都是一个 4 字节的整型，但是通常我们在调用的时候，是用的一个 4 字符的字符串，因此需要一个函数来将 4 字符转换为 4 字节的整形。</p>


<div class="wp_syntax"><div class="code"><pre class="vb" style="font-family:monospace;">// code from ToolbarSearchField by The ZAZ Studios
// http://www.thezaz.com/opensource/realbasic/macosx/searchfield/
<span style="color: #151B8D; font-weight: bold;">static</span> m <span style="color: #151B8D; font-weight: bold;">as</span> <span style="color: #E56717; font-weight: bold;">new</span> MemoryBlock(4)
m.LittleEndian = <span style="color: #00C2FF; font-weight: bold;">false</span>
m.StringValue(0, 4) = s
return m.UInt32Value(0)</pre></div></div>


<p>在 ForwardCartonAEEventToObject 里，参数 theEvent 和 replyEvent 都量个整形，为了从这两个参数里拿到数据，还需要使用 AEGetParamPtr 来从 AppleEvent 中拿到数据。</p>


<div class="wp_syntax"><div class="code"><pre class="vb" style="font-family:monospace;">soft <span style="color: #151B8D; font-weight: bold;">declare</span> <span style="color: #E56717; font-weight: bold;">function</span> AEGetParamPtr lib CarbonLib ( _
    theAppleEvent <span style="color: #151B8D; font-weight: bold;">as</span> <span style="color: #F660AB; font-weight: bold;">Integer</span>, theAEKeyword <span style="color: #151B8D; font-weight: bold;">as</span> <span style="color: #F660AB; font-weight: bold;">Integer</span>, _
    desiredType <span style="color: #151B8D; font-weight: bold;">as</span> <span style="color: #F660AB; font-weight: bold;">Integer</span>, <span style="color: #151B8D; font-weight: bold;">byref</span> actualType <span style="color: #151B8D; font-weight: bold;">as</span> <span style="color: #F660AB; font-weight: bold;">Integer</span>, _
    dataPtr <span style="color: #151B8D; font-weight: bold;">as</span> Ptr, maximumSize <span style="color: #151B8D; font-weight: bold;">as</span> <span style="color: #F660AB; font-weight: bold;">Integer</span>, _
    <span style="color: #151B8D; font-weight: bold;">byref</span> actualSize <span style="color: #151B8D; font-weight: bold;">as</span> <span style="color: #F660AB; font-weight: bold;">Integer</span>) <span style="color: #151B8D; font-weight: bold;">as</span> <span style="color: #F660AB; font-weight: bold;">Integer</span></pre></div></div>


<p>当然还有一系列的 AEGetDataDesc、AEGetDescSize 等函数可以，具体可以查 Xocde 随带的库文档。</p>

<p>关于注册自定义协议，可以参考<a href="http://stackoverflow.com/questions/49510/how-do-you-set-your-cocoa-application-as-the-default-web-browser">这篇文章</a>。</p>

<p>通过 Core Foundation 中的一些 C API，在 REALbasic 也可以完成一些平台相关的工作，虽然麻烦了些：）</p>
]]></content:encoded>
			<wfw:commentRss>http://xujiwei.com/blog/register-appleevent-in-realbasic/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>

