MOSA Multi-OS Software Artists

MOSAはソフトウェア開発者を支援します

  • iPhone/iPod touch アプリ紹介
  • MOSA掲示板
  • 活動履歴
  • About MOSA(English)

【MOSAメルマガ#25】SwiftでMySQLに接続する (2018年3月6日配信)

MOSAメールマガジン第25号 SwiftでMySQLに接続する

◆目次
・MOSAからのお知らせ
・SwiftでMySQLに接続する
・ニュース
・このメールマガジンについて
・バックナンバーについて
・配信先の変更・停止について

ーーーーーーーーーーーーーーーーーーーー
◆MOSAからのお知らせ
ーーーーーーーーーーーーーーーーーーーー
●【夜間】関東swift勉強会2018-03
開催日: 2018年3月16日
受付期間: 2018年3月16日

プログラミングを一人で勉強するのはつらくて長い道のり…
そんなあなたの
BUKURO.swift

・Cocoa勉強会とMOSAの合同勉強会です。
・macOS/iOS/watchOS/tvOSプログラマーのための勉強会です。
・初心者大歓迎です。
・関連があれば、他の環境についてもOKです。
・発表を希望される方は申し込み時のアンケートでお申し込みください。

プログラマーが楽しくプログラミングできるようにサポートする場を提供したい
・勉強会に参加された方全員が学びを得られる様にサポートします!
・勉強会に参加できない方にも学び得られるよう、勉強会の成果を可能な限りアウトプットします!
・プログラマの拠り所となる場を目指します!

詳細はこちら。
http://www.mosa.gr.jp/?p=42372

●【夜間】BUKURO.swift 2018-04
開催日: 2018年4月4日
受付期間: 2018年4月4日

プログラミングを一人で勉強するのはつらくて長い道のり…
そんなあなたの
BUKURO.swift

・Cocoa勉強会とMOSAの合同勉強会です。
・macOS/iOS/watchOS/tvOSプログラマーのための勉強会です。
・初心者大歓迎です。
・関連があれば、他の環境についてもOKです。
・発表を希望される方は申し込み時のアンケートでお申し込みください。

プログラマーが楽しくプログラミングできるようにサポートする場を提供したい
・勉強会に参加された方全員が学びを得られる様にサポートします!
・勉強会に参加できない方にも学び得られるよう、勉強会の成果を可能な限りアウトプットします!
・プログラマの拠り所となる場を目指します!

詳細はこちら。
http://www.mosa.gr.jp/?p=42369

ーーーーーーーーーーーーーーーーーーーー
◆コラム 
ーーーーーーーーーーーーーーーーーーーー
SwiftでMySQLに接続する
高橋真人

「お仕事は何をしているのですか?」と人に聞かれた時、基本的には「Macのプログラムを作っています」と答えますが、もう少し詳しく言えば「民間企業で、業務用のアプリを作ったり業務効率化のためのシステムを作ったりしています」ということになります。昔はISP(インハウス・ソリューション・プロバイダ)という造語を使って表現したりもしてましたが、要は何でも屋さんと言ってもいい立場です。
ですので、今の世の中、依頼される仕事の中にはかなりの比率でWeb関係の仕事が含まれます。
Web絡みでも、ある程度込み入った場合にはCocoaで専用のアプリを作ることもありますが、大方は比較的ライトな依頼で、PHPで作ったフロントのバックエンドでMySQLが動いているようなものがほとんどです。ですから、自然と開発も仮想環境(主にCentOS)上にセットアップしたLAMP環境(最近、あまりこの言葉を耳にすることがなくなったのは私だけ? Linux上にMySQL、Apache、PHPにより構成されるWebサーバー環境)で行うことがほとんどになって、必然的にサーバーの立ち上げ(ただし仮想環境に限る)やApache、MySQLなどの設定に慣れてしまいました。

そんなわけで、MySQLはそこそこ身近な存在でありmacOSのアプリを作る際にもMySQLを使うことは多いです。ただ、PHPでフロントエンドを作る場合を除けば、MySQLにはCのAPIで接続して利用するのが普通です。なぜかWeb検索すると中間にWebサーバー立ててPHPからMySQLにアクセスするという回りくどい(?)やり方を勧める記述が多く見つかるのですが、何でわざわざそんなことをしなければならないのか謎ですし、そもそもMySQLサーバーが動いているマシンに自由に使えるWebサーバーも常に備わっていると決まっているわけでもありません。

もしかしたら、macOSやiOSのアプリから直接MySQLを操作するための情報が少ないのもそれに拍車をかけているのかもしれません。

そこで、今回のコラムでは、私が以前からやっていて、最近ではSwiftを使ってMySQLに接続するアプリの手法をご紹介し、iOSからの接続についても簡単に触れてみたいと思います。

MySQLに接続するための仕組みとしては、MySQLのサイトで公式に配布されているMySQLコネクタというもの( https://www.mysql.com/jp/products/connector/ )があります。

対応言語は、C、C++、Java、Python、ADO.NET、ODBC、Node.js、PHPで、対応ブラットホームはWindows、Linux、macOS、FreeBSDなどです。(言語ごとに多少の違いはある)

macOS用には、あらかじめビルドされた状態で配布されているものがありますから比較的簡単に導入できますが、iOS用のものは存在しないので、ソースファイルから自力でビルドするか、どこかの誰かがビルドしてくれているものを使うことになります。

macOS上でSwiftを使ってMySQLを操作したい場合、Swift用のドライバは現時点では存在しないので、C用のものをSwiftから利用することになります。「比較的簡単に導入できる」とは言いましたが、XcodeでAppleが提供する以外のフレームワークやライブラリを利用した経験がないとか、SwiftからCのAPIを呼び出すことをしたことのない方だと、引っかかる箇所がいくつかあるでしょうから、その辺を中心に手順をご紹介します。

最初に、先のMySQLコネクタのページからmacOS用のものをダウンロードします。現時点では「mysql-connector-c-6.1.11-macos10.12-x86_64」というものが最新です。選択肢に.dmgのものと.tar.gzのものの二種類がありますが、.dmgのものはインストーラで入れるようになっています。実際に試してはいませんが、恐らくこちらだと手元のシステムにライブラリやらヘッダファイルやらを組み込んでしまうと思われます。自分の環境のみで使用するだけならばそれでもいいのですが、アプリにして配布したい場合には、アプリのバンドルの中にドライバを組み込んでおく必要がありますので、.dmgではなく.tar.gzの方をダウンロードした方が便利かと思います。

.tar.gzのファイルを解凍(普通にFinderでダブルクリックで大丈夫です)したら、フォルダの中にあるincludeというフォルダと、libというフォルダの中にあるlibmysqlclient.aというスタティックライブラリのファイル(これがドライバです)をXcodeのプロジェクトのフォルダの中にコピーします。コピーしなくても最終的にビルドの段階でスタティックライブラリのファイルがアプリのバンドルの中にコピーされていればいいので、Xcodeが認識できるようにパスが通してあれば問題はないのだと思いますが、私の場合、1つのプロジェクトを複数の環境に持ち回って作業することが多いため、関連ファイルは1つのフォルダ内にまとめてしまっています。

あとは、以下の手順で設定などをします。

・プロジェクトファイルと同じ階層にMySQLという名のフォルダを作り、前述のlibysqlclient.aとincludeを入れる
・PROJECTのBuild SettingsのHeader Search Pathsに$(PROJECT_DIR)/MySQL/includeと入力
・TARGETのBuild PhasesのLink Binary With Librariesのディスクロージャトライアングルを開き、+ボタンをクリック、Add Other…ボタンを押してlibmysqlclient.aを選ぶ
・再度+ボタンをクリックしたら、libc++.tbdというのを選択する。(検索フィールドにc++と入れればすぐに見つかります)

Objective-CやCの場合にはここまででOKですが、Swiftの場合にはさらに以下を行います。

・ブリッジングヘッダーを作り、以下の二行を書き込む

#import <mysql.h>
#import <errmsg.h>

ObjC/Cの場合にはmysqlのAPIを利用するソースコードの冒頭でこの2つのヘッダを取り込みます。

以上で準備は完了です。あとは、Cで書くのと同様にMySQLに接続するコードを書いていけばいいのですが、Webを検索してもあまりSwiftでのサンプルを見つけることはできない気がしますので、Swift 4での実装例をご紹介します。
ちなみに、Cocoaアプリではなくコンソールアプリの例です。

<main.swift>
001: import Foundation
002: 
003: enum MySQLError: Error {
004:     case badQuery(error: String, query: String)
005: }
006: 
007: func do_query(_ mysql: UnsafeMutablePointer<MYSQL>, query: String) throws {
008:     let err = mysql_query(mysql, query)
009:     if err != 0 {
010:     let errno = mysql_errno(mysql)
011:     let errMsg = "Error: [\(errno)]" + String(cString: mysql_error(mysql), encoding: String.Encoding.utf8)!
012:     throw MySQLError.badQuery(error: errMsg, query: query)
013: }
014: 
015: let field_count = Int(mysql_field_count(mysql))
016:     if 0 < field_count {
017:         let res = mysql_use_result(mysql)
018:         let numFields = Int(mysql_num_fields(res))
019: 
020:         var row = mysql_fetch_row(res)
021:         while row != nil {
022:             for i in 0..<numFields {
023:                 let field = mysql_fetch_field_direct(res, UInt32(i))
024:                 let key = String(cString: (field?.pointee.name)!, encoding: String.Encoding.utf8)!
025: 
026:                 var value: Any? // default value is nil
027:                 if let rowValue = row![i] {
028:                     let string = String(cString: rowValue, encoding: String.Encoding.utf8)!
029:                     value = string
030:                 }
031: 
032:                 print("\(key) => \(value ?? "NULL")")
033:             }
034: 
035:             row = mysql_fetch_row(res)
036:         }
037: 
038:         mysql_free_result(res)
039:     }
040: }
041: 
042: func main() {
043:     let server = <<MySQLサーバーのアドレス>>
044:     let database = <<データベース名>>
045:     let user = <<ユーザー名>>
046:     let pass = <<パスワード>>
047: 
048:     guard let mysql = mysql_init(nil) else {
049:         perror("mysql_init")
050:         return
051:     }
052:     var timeout = 5
053:     guard mysql_options(mysql, MYSQL_OPT_CONNECT_TIMEOUT, &timeout) == 0 else {
054:         perror("mysql_options")
055:         return
056:     }
057: 
058:     guard mysql_real_connect(mysql, server, user, pass, database, 0, nil, 0) != nil else {
059:         perror("mysql_real_connect")
060:         return
061:     }
062: 
063:     guard mysql_select_db(mysql, database) == 0 else {
064:         perror("mysql_select_db")
065:         return
066:     }
067: 
068:     do {
069:         let query = "SELECT * FROM <<テーブル名>> LIMIT 5"
070:         try do_query(mysql, query: query)
071:     }
072:     catch {
073:         print(error)
074:     }
075: 
076:     mysql_close(mysql)
077: }
078: 
079: main()

※43〜46、69の各行の部分は、適宜ご自分の環境に合わせて設定してください

MySQLサーバーに接続して、簡単なSQLクエリーを投げて結果を得るという単純なものですが、これでうまく接続できたら、あとはお好きなように手を加えていけばいいと思います。

さて、iOSの場合についてですが、大まかな流れはmacOSの場合とほぼ共通です。ただ、macOS用のライブラリはプロセッサの異なるiOSマシンでは機能しないため、どうやってiOS用のMySQLドライバを手に入れるかが最大のハードルとなります。

ちょうど一年前の今ぐらいに、iOSでのMySQLへの接続に挑戦していたのですが、意外と手こずったのでその辺のお話をします。

MySQLとかiOSなどのワードでWeb検索すると、いくつか関連サイトが見つかります。中に「iOSからMySQLに接続するためのベストな方法」的なタイトル(英語ですが)のとこがあったので、「お」と思って期待して読んでみたら、あろうことが前述の「PHPでサーバーを立てろ」てなアドバイスになっててがっかりしました。

さらに探して、Githubに独自にiOS用にドライバをビルドしているのが見つかったので、自分のiOSアプリに組み込んでみました。とりあえず接続することはできたのですが、残念なことにその時の私のニーズは満たしてはくれませんでした。SSLでの接続ができなかったのです。

接続したいデータベースには個人情報が保存されていたので、MySQLのSSL接続を強制する設定にしてありました。しかしSSLを介さなければ問題なく接続できるのに、SSLを使うと接続できないという状態でした。macOS版ではちゃんとSSLで接続できていたので、これはもうドライバーの問題としか考えられません。

この時は、自前のアプリでなくても、とにかくこのデータベースにアクセスしたかったので、App Storeにあるいくつかのアプリも試しました。SSH経由で接続するというのに比べるとSSLでの接続に対応するアプリはあまり多くなかったのですが、これなら行けそうだと思うのを購入して試しましたが、やはりSSLだとつながりません。

エラーメッセージが、私の作ったアプリでのものと同一だったので、もしかしたらApp Stroreに並んでいたアプリも私が見つけたのと同じドライバーを使っていたのかもしれません。

結局、必要なタイミングでアプリを完成させることはできず、その件はお流れとなったのですが、あとフォローとして実験を重ね、最終的にはSSLで接続するアプリを作ることができました。(間に合わなかったので、実用に供されることはありませんでしたが。笑)

残念ながら、どうやったかはあまりちゃんと憶えていません。そもそもいろんなサイトを参照しまくった挙句さまざまな方法を試したうちの1つだけがうまく行ったという状態なため、それをきちんと整理してその後につなげるということはできていません。

いずれ、その辺を再度調べてまとめてみようとは思っていますので、関心のある方は何かでお会いした折にでもお声をかけていただければ、何らかの情報をご提供できるかもしれません。

ーーーーーーーーーーーーーーーーーーーー
◆ニュース
ーーーーーーーーーーーーーーーーーーーー
●Google、iOS/Androidアプリ開発向けオープンソースSDK「Flutter」をβ公開
http://www.itmedia.co.jp/news/articles/1802/28/news076.html
興味深いライブラリです。

●Apple、macOSやiOSのネットワークAPIについてフィードバックを募集中。
https://applech2.com/archives/20180228-networking-feedback-feb-2018.html
ネットワーク系の処理を書いている方は是非フィードバックしましょう。私もせっかくの機会なのでフィードバックを送りました。

●なぜNTT東日本は旭川医科大学に逆転勝訴できたのか。判決文から分かる教訓とは
https://storialaw.jp/blog/4019
システム開発失敗時に過失割合が10(ユーザー):0(ベンダー)となるケースは珍しいと思います。最高裁に係属中であるとのことなので、今後の展開は確定していませんが注目です。

●国内ITサービス市場は1%程度のゆるやかな成長を継続。ただしITサービスベンダーが成長するには自分自身のデジタルトランスフォーメーション推進が必要。IDC Japan
http://www.publickey1.jp/blog/18/it1itidc_japan.html
業務のデジタル化のための企業や組織が、みずからは対応できていないというのでは説得力に欠けます。

●macOS 10.13 High Sierra前後では計算機アプリでパーセント「%」の扱いが違う。
https://applech2.com/archives/20180228-macos-high-sierra-calculator.html
計算機アプリ、バージョンアップしていたのですね。

●Spotifyが上場申請。CEOが語る夢と現実
https://www.gizmodo.jp/2018/03/spotify-is-officially-going-public.html
新規上場ですが、新たな資金調達ではないという珍しいパターンです。音楽ストリーミングは潤沢な資金を持つもの同士がぶつかりあっています。

ーーーーーーーーーーーーーーーーーーーー
◆このメールマガジンについて
ーーーーーーーーーーーーーーーーーーーー
このメールマガジンではMOSA会員の皆様からの寄稿を募集しています!!
法人会員の皆様、自社のイベントやプレスリリースなどの案内を掲載しませんか?
個人会員の皆様、自作のアプリやOSSで作ったライブラリ、試してみたことなどを掲載してみませんか?
会員ではない皆様、MOSAの会員になって、寄稿してみませんか?

寄稿したい方は以下のページから、お寄せください。
https://mosa-gr-jp.heteml.jp/mosa.gr.jp/?page_id=40953

MOSAの会員については、以下のページをご覧ください。
http://www.mosa.gr.jp/?page_id=4

ーーーーーーーーーーーーーーーーーーーー
◆バックナンバーについて
ーーーーーーーーーーーーーーーーーーーー
バックナンバーは以下のページで公開しています。
http://www.mosa.gr.jp/?page_id=41102

ーーーーーーーーーーーーーーーーーーーー
◆配信先の変更・停止について
ーーーーーーーーーーーーーーーーーーーー
配信先の追加はこちらです。
https://mosa-gr-jp.heteml.jp/mosa.gr.jp/?page_id=40929

配信先の停止はこちらです。
https://mosa-gr-jp.heteml.jp/mosa.gr.jp/?page_id=40938

配信先の変更は、新アドレスを追加後に旧アドレスを停止してください。

このアドレスは送信専用のため、このメールにご返信頂きましてもご回答出来ません。
お問い合わせについては、以下のページをご覧ください。
https://mosa-gr-jp.heteml.jp/mosa.gr.jp/?page_id=4711

ーーーーーーーーーーーーーーーーーーーー
(C) 2018 特定非営利活動法人MOSA
http://www.mosa.gr.jp/

MOSAメールマガジンについて

MOSAからのお知らせ、コラム、IT系ニュース、MOSAの会員からの寄稿をお届けします。
基本は隔週火曜日配信+臨時特別号。購読料も無料です。
是非、ご登録ください!

メールマガジンの配信登録はこちらから。