SwiftでCordova(ionic)のpluginを開発するには?
Swiftでcordovaのプラグインを開発することはできるのだろうか?
このあたりを見ると開発できそうだ。
Chris Dell - Software Developer :: Writing an iOS Cordova plugin in pure Swift
How to write Cordova plugin in Swift? - Stack Overflow
やってみよう。
今回はChrisさんのコードを参考に、HTMLからネイティブに小文字のメッセージを送って大文字変換されたメッセージを受信するというサンプルを作る。これが完成形。
ビルドシステムはionicを使うが、プラグイン部分の開発はcordovaでも通用するはず。
まずはblankプロジェクトを作ろう。
CDVEchoPlugin/www/index.htmlをこのように編集する。
CDVEchoPlugin /www/js/app.jsをこのように編集する。
ここまでで一応起動しておこう。
カスタムプラグインのディレクトリを作る。
次の内容でCDVEchoPlugin/plugins-dev/EchoPlugin/plugin.xmlを作る。
さらに次の内容でCDVEchoPlugin/plugins-dev/EchoPlugin/echo-plugin.jsを作る。
Swiftのソースディレクトリを作る。
次の内容でCDVEchoPlugin/plugins-dev/EchoPlugin/src/ios/EchoPlugin.swiftを作る。
プロジェクトのトップディレクトリに移動し、作ったプラグイン「EchoPlugin」をプロジェクトにインストールする。
ここで次の項目を確認する。
SwiftはiOS8以降なので最低OSを8にする必要がある。そこで、CDVEchoPlugin/config.xmlに次のように「<preference name="deployment-target" value="8.0" />」の記述を加える。
そして、この設定をCDVEchoPlugin/platforms/ios/CDVEchoPlugin.xcodeprojに反映させる。
次の内容でCDVEchoPlugin/platforms/ios/CDVEchoPlugin/Classes/Bridging-Header.hを作る。
これはSwiftからObjective-Cのライブラリ(Cordovaなど)にアクセスするために必要。でなければコンパイルエラーになる。ただ作っただけではダメで、Xcodeにて手動で設定する必要がある。
XcodeでCDVEchoPlugin/platforms/ios/CDVEchoPlugin.xcodeprojを開く。
先ほどターゲットOSを指定するためにprepareした効果は、General→Deployment Info→Deployment Targetで確認できる。
「Build Settings」タブに移り、「All」をクリックして、「Objective-C Bridging」で検索フィルターをかけ、「Objective-C Bridging Header」に「CDVEchoPlugin/Classes/Bridging-Header.h」を設定する。
追記15.09.16: ※ここでObjective-C Bridging Headerが見つからない場合は、Xcode上でClassesに適当にswiftファイルを追加すると「自動的に設定しますか」的なことを言われる場合がある。OKすると勝手にClasses/プロジェクト名-Bridging-Header.hを作ってくれる。
ここまでで、とりあえずProduct→Buildでコンパイルできるはず。
しかし、Bridging Headerにはさらに落とし穴があって、この状態で実行するとこのようなエラーが出る。
なぜ出るのか?解決方法は?
iphone - dyld: Library not loaded: @rpath/libswiftCore.dylib - Stack Overflow
一番usefulがついている"Embedded Content Contains Swift Code"の方法では解決しなかったが、"Runpath Search Paths"の方法で解決した。
「Build Settings」タブに移り、「All」をクリックして、「runpath」で検索フィルターをかけ、「Runpath Search Paths」に「@executable_path/Frameworks」を設定する。
ここまでやればProduct→Runで実行できるはず。
「echo」ボタンをクリックすると「msg.return」に大文字になってエコーが返ってくる。単純ではあるが、Swiftで開発したプラグインが正常に動作している証拠だ。
これでSwiftでプラグインを書ける!何でもデキる気がしてきた∠( ゚ω゚)/
このあたりを見ると開発できそうだ。
Chris Dell - Software Developer :: Writing an iOS Cordova plugin in pure Swift
How to write Cordova plugin in Swift? - Stack Overflow
やってみよう。
今回はChrisさんのコードを参考に、HTMLからネイティブに小文字のメッセージを送って大文字変換されたメッセージを受信するというサンプルを作る。これが完成形。
ビルドシステムはionicを使うが、プラグイン部分の開発はcordovaでも通用するはず。
まずはblankプロジェクトを作ろう。
$ ionic start CDVEchoPlugin blank
CDVEchoPlugin/www/index.htmlをこのように編集する。
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width"> <title>CDVEchoPlugin</title> <link href="lib/ionic/css/ionic.css" rel="stylesheet"> <link href="css/style.css" rel="stylesheet"> <!-- IF using Sass (run gulp sass first), then uncomment below and remove the CSS includes above <link href="css/ionic.app.css" rel="stylesheet"> --> <!-- ionic/angularjs js --> <script src="lib/ionic/js/ionic.bundle.js"></script> <!-- cordova script (this will be a 404 during development) --> <script src="cordova.js"></script> <!-- your app's js --> <script src="js/app.js"></script> </head> <body ng-app="starter" ng-controller="controller"> <ion-pane> <ion-header-bar class="bar-stable"> <h1 class="title">CDVEchoPlugin</h1> </ion-header-bar> <ion-content padding="true"> <label class="item item-input"> <span class="input-label">msg.send</span> <input type="text" ng-model="msg.send"> </label> <label class="item item-input"> <span class="input-label">msg.return</span> <input type="text" ng-model="msg.return"> </label> <button class="button button-block button-positive" ng-click="onClickBtnEcho();">echo</button> </ion-content> </ion-pane> </body> </html>
CDVEchoPlugin /www/js/app.jsをこのように編集する。
/* jshint -W117, -W035, -W072, -W003 */ 'use strict'; // Ionic Starter App // angular.module is a global place for creating, registering and retrieving Angular modules // 'starter' is the name of this angular module example (also set in a <body> attribute in index.html) // the 2nd parameter is an array of 'requires' angular.module('starter', ['ionic']) .run(function($ionicPlatform) { $ionicPlatform.ready(function() { // Hide the accessory bar by default (remove this to show the accessory bar above the keyboard // for form inputs) if(window.cordova && window.cordova.plugins.Keyboard) { cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true); } if(window.StatusBar) { StatusBar.styleDefault(); } }); }).controller('controller', function($scope) { console.log('controller init'); $scope.msg = { 'send': 'message to send', 'return': '' }; $scope.onClickBtnEcho = function() { console.log('onClickBtnEcho: msg.send=' + $scope.msg.send); if (window.EchoPlugin) { EchoPlugin.echo($scope.msg.send, function(returnMsg) { $scope.msg.return = returnMsg; console.log('onClickBtnEcho: msg.return=' + $scope.msg.return); $scope.$applyAsync(); }); } else { console.log('NO EchoPlugin'); } }; });
ここまでで一応起動しておこう。
$ cd /path/to/CDVEchoPlugin/
$ ionic run ios
カスタムプラグインのディレクトリを作る。
$ mkdir plugins-dev
$ cd plugins-dev
$ mkdir EchoPlugin
次の内容でCDVEchoPlugin/plugins-dev/EchoPlugin/plugin.xmlを作る。
<?xml version="1.0" encoding="UTF-8"?> <plugin xmlns="http://apache.org/cordova/ns/plugins/1.0" id="echo-plugin" version="0.1"> <name>EchoPlugin</name> <description>This plugin just echoes uppercased string.</description> <js-module src="echo-plugin.js"> <clobbers target="window.EchoPlugin" /> </js-module> <!-- iOS --> <platform name="ios"> <config-file target="config.xml" parent="/*"> <feature name="EchoPlugin"> <param name="ios-package" value="EchoPlugin" /> </feature> </config-file> <source-file src="src/ios/EchoPlugin.swift" /> </platform> </plugin>
さらに次の内容でCDVEchoPlugin/plugins-dev/EchoPlugin/echo-plugin.jsを作る。
'use strict'; var exec = require('cordova/exec'); var EchoPlugin = { echo: function(sendMsg, onSuccess, onFail) { return exec(onSuccess, onFail, 'EchoPlugin', 'echo', [sendMsg]); } }; module.exports = EchoPlugin;
Swiftのソースディレクトリを作る。
$ mkdir src
$ cd src
$ mkdir ios
$ cd ios
次の内容でCDVEchoPlugin/plugins-dev/EchoPlugin/src/ios/EchoPlugin.swiftを作る。
import Foundation @objc(EchoPlugin) class EchoPlugin : CDVPlugin { func echo(command: CDVInvokedUrlCommand) { var message = command.arguments[0] as! String message = message.uppercaseString // Prove the plugin is actually doing something var pluginResult = CDVPluginResult(status: CDVCommandStatus_OK, messageAsString: message) commandDelegate.sendPluginResult(pluginResult, callbackId:command.callbackId) } }
プロジェクトのトップディレクトリに移動し、作ったプラグイン「EchoPlugin」をプロジェクトにインストールする。
$ cd /path/to/CDVEchoPlugin
$ ionic plugin add plugins-dev/EchoPlugin/
ここで次の項目を確認する。
- plugins-dev/EchoPluginの内容がplugin/EchoPluginにコピーされているか?
- CDVEchoPlugin/platforms/ios/CDVEchoPlugin/config.xmlにplugin.xmlで設定したfeatureの内容が追加されているか?
- CDVEchoPlugin/platforms/ios/CDVEchoPlugin/Plugins/echo-plugin/EchoPlugin.swiftがあるか?
- CDVEchoPlugin/platforms/ios/www/plugins/echo-plugin/echo-plugin.jsがあるか?
SwiftはiOS8以降なので最低OSを8にする必要がある。そこで、CDVEchoPlugin/config.xmlに次のように「<preference name="deployment-target" value="8.0" />」の記述を加える。
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <widget id="com.ionicframework.cdvechoplugin107512" version="0.0.1" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0"> ・・・・・・ <preference name="deployment-target" value="8.0" /> </widget>
そして、この設定をCDVEchoPlugin/platforms/ios/CDVEchoPlugin.xcodeprojに反映させる。
$ ionic prepare
次の内容でCDVEchoPlugin/platforms/ios/CDVEchoPlugin/Classes/Bridging-Header.hを作る。
// // Use this file to import your target's public headers that you would like to expose to Swift. // #import <Cordova/CDV.h>
これはSwiftからObjective-Cのライブラリ(Cordovaなど)にアクセスするために必要。でなければコンパイルエラーになる。ただ作っただけではダメで、Xcodeにて手動で設定する必要がある。
XcodeでCDVEchoPlugin/platforms/ios/CDVEchoPlugin.xcodeprojを開く。
先ほどターゲットOSを指定するためにprepareした効果は、General→Deployment Info→Deployment Targetで確認できる。
「Build Settings」タブに移り、「All」をクリックして、「Objective-C Bridging」で検索フィルターをかけ、「Objective-C Bridging Header」に「CDVEchoPlugin/Classes/Bridging-Header.h」を設定する。
追記15.09.16: ※ここでObjective-C Bridging Headerが見つからない場合は、Xcode上でClassesに適当にswiftファイルを追加すると「自動的に設定しますか」的なことを言われる場合がある。OKすると勝手にClasses/プロジェクト名-Bridging-Header.hを作ってくれる。
ここまでで、とりあえずProduct→Buildでコンパイルできるはず。
しかし、Bridging Headerにはさらに落とし穴があって、この状態で実行するとこのようなエラーが出る。
dyld: Library not loaded: @rpath/libswiftCore.dylib
Referenced from: /private/var/mobile/Containers/Bundle/Application/2E6CCCD1-E46C-43F8-8F1F-1204A1991455/CDVEchoPlugin.app/CDVEchoPlugin
Reason: image not found
なぜ出るのか?解決方法は?
iphone - dyld: Library not loaded: @rpath/libswiftCore.dylib - Stack Overflow
一番usefulがついている"Embedded Content Contains Swift Code"の方法では解決しなかったが、"Runpath Search Paths"の方法で解決した。
「Build Settings」タブに移り、「All」をクリックして、「runpath」で検索フィルターをかけ、「Runpath Search Paths」に「@executable_path/Frameworks」を設定する。
ここまでやればProduct→Runで実行できるはず。
「echo」ボタンをクリックすると「msg.return」に大文字になってエコーが返ってくる。単純ではあるが、Swiftで開発したプラグインが正常に動作している証拠だ。
これでSwiftでプラグインを書ける!何でもデキる気がしてきた∠( ゚ω゚)/
コメント
コメントを投稿