読者です 読者をやめる 読者になる 読者になる

non vorrei lavorare

ブログ名の通りです。javascript three.js mruby rust OCaml golang julialang blender

Atom ShellでCocoa APIが叩けるようになった

おはようございます。奥さんの出張から帰って来て、久しぶりに我が家で、 ダンボール滑り台を出して、兄弟仲良く遊びました。kjunichiです。
 

背景

NodObjCというモジュールを使うと、Node.jsCocoa APIを叩けるようになる。しかし、内部で使用しているネイティブモジュールのnode-ffiが0.11系のnodeに対応していなかった。

つまり、Atom ShellではNode.jsの0.11系を使っており、NodObjCモジュールが使えない状態だった。node-webkitは0.8系がNode.jsの0.10系をサポートしているのでこっちを使えば動かせた

先日、そんな状況の中、神が登場して、この状況が変わった。

事前準備

nvm,nodebrewなど、Node.jsのバージョンを切り替えることが容易なツールで予め、0.10系、0.11系の2系統のnodeを入れておく。

Atom ShellでNodObjCをつかう

0.10系のnodeでNodObjCを入れる

mkidr CocoaAtom
cd CocoaAtom
nodebrew use 0.10
npm install NodObjC

0.11系で動くnode-ffiをもってくる

nodebrew use 0.11
npm install -g node-gyp
git clone https://github.com/avatar5d/node-ffi.git
cd node-ffi
npm install nan

NodeObjC付属のnode-ffi(ffi)を入れ替える

rm -rf node_modules/NodObjC/node_modules/ffi
mv node-ffi node_modules/NodObjC/node_modules/ffi

Atom Shell向けのネイティブモジュールとしてビルドする

cd node_modules/NodObjC
HOME=~/.atom-shell-gyp node-gyp rebuild --target=0.11.13 --arch=x64 --dist-url=https://gh-contractor-zcbenz.s3.amazonaws.com/atom-shell/dist
cd ../..

サンプルを作ってみる

main.js

var app = require('app');  // Module to control application life.
var BrowserWindow = require('browser-window');  // Module to create native browser window.

// Report crashes to our server.
require('crash-reporter').start();

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the javascript object is GCed.
var mainWindow = null;

// Quit when all windows are closed.
app.on('window-all-closed', function() {
  if (process.platform != 'darwin')
    app.quit();
});

// This method will be called when atom-shell has done everything
// initialization and ready for creating browser windows.
app.on('ready', function() {
  // Create the browser window.
  mainWindow = new BrowserWindow({width: 800, height: 600});

  // and load the index.html of the app.
  mainWindow.loadUrl('file://' + __dirname + '/index.html');

  // Emitted when the window is closed.
  mainWindow.on('closed', function() {
    // Dereference the window object, usually you would store windows
    // in an array if your app supports multi windows, this is the time
    // when you should delete the corresponding element.
    mainWindow = null;
  });
});

index.html

<!DOCTYPE html>
<meta charset="UTF-8">
<html>
<title>Hello,Cocoa</title>
<h2>Hello NodObjC</h2>
We are using node.js
<script>
  document.write(process.version)
</script>.
<div id="hello"></div>
<button id="play">notice</button>
<script>
  var $ = require('NodObjC');
  $.framework('Foundation');
  $.framework('Cocoa');

  var app = $.NSApplication('sharedApplication');
  var string = $.NSString('stringWithUTF8String', 'Hello Objective-Cの世界へ');

  document.getElementById("hello").innerHTML = string;
  var btn = document.getElementById("play");
  btn.addEventListener('click', function() {
    var snd = $.NSSound('soundNamed', $('Hero'));
    snd('play');
    // create an NSString of the applescript command that will be run
    var command = $.NSString('stringWithUTF8String', 'display notification "無理やり通知する!" with title "node-webkit" subtitle "applescriptで"');

    // create an NSAppleScript instance with the `command` NSString
    var appleScript = $.NSAppleScript('alloc')('initWithSource', command)

    // finally execute the NSAppleScript instance synchronously
    var resultObj = appleScript('executeAndReturnError', null)

    // resultObj may be `null` or an NSAppleEventDescriptor instance , so check first
    if (resultObj) {
      // print out the value
      console.dir(resultObj('stringValue').toString())
    }
  });
</script>
</html>

動かす

~/Download/atom-shell-v0.15.9-darwin-x64/Atom.app/Contents/MacOS/Atom ../CocoaAtom/

関連記事