ofxCef を使用した app を作る

[ofxCef のビルド手順](http://qiita.com/hideyukisaito/items/54c346126a6fc063a0de) の続きです。

## 環境
- Mac OS X 10.10.3
- Xcode Version 6.4 (6E35b)
- oF v0.8.4
- [cef_binary_3.2171.1979_macosx32](http://www.magpcss.net/cef_downloads/index.php?query=label%3A~Deprecated+label%3ACEF3+label%3Abinary#list)

## projectGenerator でプロジェクトを作成
いつもと同じように projectGenerator を使ってプロジェクトを生成します。
Addons で ofxCef にチェックを入れるのを忘れずに。

## サーチパスの修正
僕の環境だとデフォルトのヘッダサーチパスが下記の様におかしなことになります。。
![スクリーンショット 2015-08-23 0.59.57.png](https://qiita-image-store.s3.amazonaws.com/0/5807/ad93deb6-5676-6ff5-9e0a-f585f41c2824.png)

まずはこれを以下のように修正します。

- `$(OF_CORE_HEADERS)`
- `../../../addons/ofxCef-master/libs`
- ```../../../addons/ofxCef-master/libs/CEF```
- ```../../../addons/ofxCef-master/libs/CEF/osx32```
- ```../../../addons/ofxCef-master/libs/CEF/osx32/include```
- ```../../../addons/ofxCef-master/libs/CEF/osx32/include/base```
- ```../../../addons/ofxCef-master/libs/CEF/osx32/include/base/internal```
- ```../../../addons/ofxCef-master/libs/CEF/osx32/include/capi```
- ```../../../addons/ofxCef-master/libs/CEF/osx32/include/internal```
- ```../../../addons/ofxCef-master/libs/CEF/osx32/include/wrapper```
- ```../../../addons/ofxCef-master/libs/CEF/osx32/lib```
- ```../../../addons/ofxCef-master/src```

## ファイルタイプの変更
次に ofxCef の中で Objective-C のコードを使用しているファイルについて、そのファイルタイプを "Objective-C++ Source" に変更します。具体的には以下のファイルです。

- ofxCEF.cpp
- ofxCEFRenderHandler.cpp

![スクリーンショット 2015-08-23 1.17.23.png](https://qiita-image-store.s3.amazonaws.com/0/5807/c42efcd8-c9b5-e66c-7f40-d120c02da742.png)

## process_helper_mac.cpp を削除
main関数が2つあるぞ！と怒られるので Build Phases > Compile Sources から process_helper_mac.cpp を削除します。

## ライブラリを追加
General > Linked Frameworks and Libraries から以下を追加します。

- Chromium Embedded Framework.framework
- libcef_dll_wrapper.a

Chromium Embedded Framework.framework は ```$OF_PATH/addons/ofxCef-master/libs/CEF/osx32/lib``` に、libcef_dll_wrapper.a は[前回](http://qiita.com/hideyukisaito/items/54c346126a6fc063a0de)ビルドしたものをそれぞれ使用します。

## Run Script を追加
Build Phases > + > New Run Script Phase で以下のスクリプトを追加します。

```sh
exec cp -Rf "../../../addons/ofxCEF-master/libs/CEF/osx32/lib/Chromium Embedded Framework.framework" "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app/Contents/Frameworks/"
exit 1
```

```sh
exec install_name_tool -change "@executable_path/Chromium Embedded Framework" "@executable_path/../Frameworks/Chromium Embedded Framework.framework/Chromium Embedded Framework" "${BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}"
exit 1
```

```sh
cp -Rf "../../../addons/ofxCef-master/example_ofxCEF/bin/cefHelper.app" "$TARGET_BUILD_DIR/$PRODUCT_NAME.app/Contents/Frameworks/"
mv "$TARGET_BUILD_DIR/$PRODUCT_NAME.app/Contents/Frameworks/cefHelper.app/Contents/MacOS/cefHelper" "$TARGET_BUILD_DIR/$PRODUCT_NAME.app/Contents/Frameworks/cefHelper.app/Contents/MacOS/$PRODUCT_NAME Helper"
rm -rf "$TARGET_BUILD_DIR/$PRODUCT_NAME.app/Contents/Frameworks/$PRODUCT_NAME Helper.app"
mv "$TARGET_BUILD_DIR/$PRODUCT_NAME.app/Contents/Frameworks/cefHelper.app" "$TARGET_BUILD_DIR/$PRODUCT_NAME.app/Contents/Frameworks/$PRODUCT_NAME Helper.app"
exec install_name_tool -change "@executable_path/Chromium Embedded Framework" "@executable_path/../../../../Frameworks/Chromium Embedded Framework.framework/Chromium Embedded Framework" "$TARGET_BUILD_DIR/$PRODUCT_NAME.app/Contents/Frameworks/$PRODUCT_NAME Helper.app/Contents/MacOS/$PRODUCT_NAME Helper"
```

```sh
exec "../../../addons/ofxCef-master/example_ofxCEF/make_more_helpers.sh" Frameworks $PRODUCT_NAME
```
最後のスクリプトのみ Input Files に ```$(BUILT_PRODUCTS_DIR)/$(EXECUTABLE_PATH)```を追加してください。

## ソースの修正
だいぶ疲れてきましたがもう少しです！

ofApp.h / .cpp を以下のように修正します。

```cpp:ofApp.h
#pragma once

#include "ofMain.h"
#include "ofxCEF.h"

class GLFWwindow;

class ofApp : public ofBaseApp{

public:
        void setup();
        void update();
        void draw();
        void exit();
		
        // Chromium の JS からメッセージを受け取るためのハンドラ
        void gotMessageFromJS(ofxCEFMessageArgs& msg);
        // Chromium からイベント受け取るためのハンドラ
        void eventFromCEF(ofxCEFEventArgs& e);
        
        // CEF
        ofxCEF *cef;
};

```

```cpp:ofApp.cpp
#include "ofApp.h"
#include "ofAppGLFWWindow.h"

// スクロールイベントを受け取るためのハンドラ
void mouseScroll(GLFWwindow* window, double x, double y){
    ((ofApp *)ofGetAppPtr())->cef->mouseWheel(x*10, y*10);
}

void ofApp::setup(){
#if defined(TARGET_OSX)
    // スクロールイベントのコールバックを登録
    glfwSetScrollCallback( ((ofAppGLFWWindow *) ofGetWindowPtr())->getGLFWWindow(), mouseScroll);
#endif
    
    cef->setup();
    
    ofAddListener(cef->messageFromJS, this, &ofApp::gotMessageFromJS);
    ofAddListener(cef->eventFromCEF, this, &ofApp::eventFromCEF);
    
    ofSetFrameRate(60);
    ofSetVerticalSync(true);
    
    cef->load("http://google.com");
}

void ofApp::update(){
    cef->update();
}

void ofApp::draw(){
    ofBackground(0);
    cef->draw();
}

void ofApp::exit() {
    cef->exit();
    delete cef;
    cef = NULL;
}

void ofApp::gotMessageFromJS(ofxCEFMessageArgs& msg){
    
}

void ofApp::eventFromCEF(ofxCEFEventArgs& e){
    
}
```

さらに main.cpp を以下のように修正します。

```cpp:main.cpp
#include "ofMain.h"
#include "ofApp.h"
#include "ofAppGLFWWindow.h"

int main( ){
    
    // エントリーポイントでまず CEF を初期化
    int argc = 0;
    char** argv = NULL;
    ofxCEF * cef = initofxCEF(argc, argv);
    
    ofAppGLFWWindow window;
    ofSetupOpenGL(&window, 1400, 850, OF_WINDOW);
    
    // 初期化した CEF を ofApp に渡す
    ofApp * p = new ofApp();
    p->cef = cef;
    ofRunApp( p );
}
```

それではビルドしてみましょう。見慣れた Google のトップが表示されれば成功です！
![スクリーンショット 2015-08-23 2.29.03.png](https://qiita-image-store.s3.amazonaws.com/0/5807/242b0b2a-95c3-bd08-fefb-5c93eb5c423e.png)

## まとめ
このようにまだまだ罠が多いですが、oF で Chromium の恩恵を受けられるのは大きいし、Web 系フロントエンドの人に UI を書いてもらってグラフィックスだけ oF で、という協働のしかたも考えられたりして夢が広がります。
今回は書きませんでしたが JS を使ったコミュニケーションも可能なので、今後も色々探っていきたいと思います。