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でプラグインを書ける!何でもデキる気がしてきた∠( ゚ω゚)/






コメント
コメントを投稿