Help us understand the problem. What is going on with this article?

Swift で Markdown をレンダリングしたい時どうしたか

More than 1 year has passed since last update.

Swift その2 Advent Calendar 2016 9日目です!

Swift と言いつつ iOS と JavaScript の話がメインになってしまいました :pray: :bow:

ピーちゃん

ピーちゃんという、 esa.io の iOS クライアントアプリを作っていて、そこで Markdown をアプリ上で表示しています。
その時どうやって Markdown をレンダリングしていったかやり方を書いていきます。

Swift で Markdown

Swift で Markdown をレンダリングしたい時は以下の方法があるかと思います。

  1. Markdown を自力で Parse して、記法に応じたフォントサイズや太さなどを設定し表示
  2. SimonFairbairn/SwiftyMarkdown などライブラリを使用
  3. WebView で JavaScript を使い表示

1 は厳しいというか面倒、2 も何か制限がありあそうだしこれ使っておけば安心というデファクトスタンダードというほどではない。
3 は JS の Markdown ライブラリも豊富にあり良さそう、ということで WebView に Markdown を渡す方式にしました。

WebView で Markdown を表示

  1. Markdown をレンダリングするための html/js をローカルに用意する
  2. WebView がその html を読み込む
  3. html の読み込みが完了したら Markdown を js に渡す
  4. js が Markdown を解釈しレンダリングする

の手順で読み込んでいきます。
ここでは UIWebView を使っていますが、良い子は WKWebView を使ってください。

1. Markdown をレンダリングするための html/js をローカルに用意する

各ライブラリの取得

Markdown をレンダリングする js ライブラリとして marked.js、 css ライブラリとして github-markdown-css を利用します。
せっかくなので emoji も表示したいですね :sushi: 。では emojify の js と css もお借りしましょう。

上記の js / css をダウンロードしフォルダに配置します。
また、それらのライブラリを利用する本体の md.html も作成してしまいましょう。

そうすると、 Xcode にはこのように表示されているはずです。

unspecified.png

md.html でライブラリを読み込む

上記で設置した md.html で 各ライブラリを読み込んでいきます。

<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <script type="text/javascript" src="./emojify.min.js"></script>
  <link rel="stylesheet" href="./emojify.min.css">
  <script type="text/javascript" src="./marked.js"></script>
  <link rel="stylesheet" href="./github-markdown.css">
  <script>
  function insert(html) {
    marked.setOptions({
      gfm: true,
      tables: true,
      breaks: true
    });
    document.getElementById('content').innerHTML = marked(html);
    emojify.setConfig({img_dir: 'https://github.global.ssl.fastly.net/images/icons/emoji/' });
    emojify.run(document.getElementById('content'));
  }
  </script>
</head>

<body>
  <article class="markdown-body">
    <div id="content" />
  </article>
</body>

</html>

各ライブラリの読み込みと function insert(html) で Markdown を Swift 側から受け取る準備をしています。

ここら辺は marked.js や emojify の使い方になってくるので、詳しくは各ドキュメントを参照ください。

2. WebView がその html を読み込む

ViewController の viewDidLoad などで html を読み込みます。

    override func viewDidLoad() {
        super.viewDidLoad()
        let url = Bundle().url(forResource: "md", withExtension: "html")
        let req = URLRequest(url: url)
        webView.loadRequest(req)
    }

3. html の読み込みが完了したら Markdown を js に渡す

    func webViewDidFinishLoad(_ webView: UIWebView) {
        setMarkdown()
    }

    func setMarkdown() {
        let markdown = "# h1\\n ## h2 \\n * list\\n    * :)"
        let js = "insert('\(markdown)');"
        self.webView.stringByEvaluatingJavaScript(from: js)
    }

webView の stringByEvaluatingJavaScript を使い、先ほど用意した function insert(html) で js を実行しています。

ここで少し注意が必要で、 Swift 側で html の読み込みが完了する前に js を実行してしまうと js の実行が失敗してしまうので、 webViewDidFinishLoad が呼ばれるまで待ちます。

4. js が Markdown を解釈しレンダリングする

無事レンダリングされました :relaxed:

2016-12-10 16.32.46.png

おわり

WebView を使い Markdown をレンダリングする一通りの流れを記載しました。 :blush:

あまり Swift Advent Clendar とは関係ない話になってしまいましたが :bow: 誰かの役に立てればと思います :muscle:

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away