Posted at

【iOS】MarkdownをHTMLにレンダリングするライブラリを使って、Qiitaの記事をMarkdownで表示してみた

More than 3 years have passed since last update.


はじめに

iOS Second Stage Advent Calendar20日目の記事です。

個人的には7記事目になります。


本題

Markdownを描画するライブラリを見つけたので、それを使用してQiitaの記事を用事するサンプルをつくってみました。

ライブラリはmdiep/MMMarkdownです。

サンプルプロジェクトは以下においておいきました。

AdventCalendar2015/SampleMMMarkdown at master · ryokosuge/AdventCalendar2015


スクリーンショット



  • 一覧

    スクリーンショット 2015-12-20 0.27.39.png




  • 詳細

    スクリーンショット 2015-12-20 0.28.07.png



こんな感じで表示できました。


導入

MMMarkdownCarthageか自分でコピーするとのことなのでCarthageを使用して導入しました。

Carthageでの導入方法などは世にたくさん出ているので、そちらを参考にしてください。

ちなみに今回使ったライブラリは以下になります。


Cartfile

## Himotoki

## source: https://github.com/ikesyo/Himotoki
github "ikesyo/Himotoki" ~> 1.3

## Alamofire
## source: https://github.com/Alamofire/Alamofire
github "Alamofire/Alamofire" ~> 3.0

## BrightFutures
## source https://github.com/Thomvis/BrightFutures
github "Thomvis/BrightFutures" ~> 3.2

## MMMarkdown
## source https://github.com/mdiep/MMMarkdown
github "mdiep/MMMarkdown"


最近Himotokiを使うのが自分の中でのブームになっています。


ソースコード

QiitaのAPIから記事のMarkdownの値が取得できるので、それを使ってやりました。


Himotokiを使ってレスポンスを構造体に変換

以下はQiitaAPIから取得できるレスポンスを保持する構造体です。


ItemResponse.swift


import Foundation
import Himotoki

struct TagResponse: Decodable {
let name: String
let versions: [String]

static func decode(e: Extractor) throws -> TagResponse.DecodedType {
return try TagResponse(name: e <| "name", versions: e <|| "versions" )
}

}

struct UserResponse: Decodable {

let description: String?
let facebookID: String?
let followeesCount: Int
let followersCount: Int
let githubLoginName: String?
let id: String
let itemsCount: Int
let linkedinID: String?
let location: String?
let name: String
let organization: String?
let permanentID: Int
let profileImageURL: String
let twitterScreenName: String?
let websiteURL: String?

static func decode(e: Extractor) throws -> UserResponse.DecodedType {
return try UserResponse(description: e <|? "description", facebookID: e <|? "facebook_id", followeesCount: e <| "followees_count", followersCount: e <| "followers_count", githubLoginName: e <|? "github_login_name", id: e <| "id", itemsCount: e <| "items_count", linkedinID: e <|? "linkedin_id", location: e <|? "location", name: e <| "name", organization: e <|? "organization", permanentID: e <| "permanent_id", profileImageURL: e <| "profile_image_url", twitterScreenName: e <|? "twitter_screen_name", websiteURL: e <|? "website_url")
}

}

struct ItemResponse: Decodable {

let renderedBody: String
let body: String
let coediting: Bool
let createdAt: String
let id: String
let privateItem: Bool
let tags: [TagResponse]
let title: String
let updatedAt: String
let URL: String
let user: UserResponse

static func decode(e: Extractor) throws -> ItemResponse.DecodedType {
return try ItemResponse(renderedBody: e <| "rendered_body", body: e <| "body", coediting: e <| "coediting", createdAt: e <| "created_at", id: e <| "id", privateItem: e <| "private", tags: e <|| "tags", title: e <| "title", updatedAt: e <| "updated_at", URL: e <| "url", user: e <| "user")
}

}


ItemResponseの中のbodyの値が投稿のMarkdownテキストになっています。

詳しくはQiita API v2 ドキュメントを参照ください。

ではそれを描画するのに MMMarkdownを使用してみます。


Markdownの描画

以下のページを参考にしてやってみました。

initWithFunk: by Eric Allam

描画にはUITextViewを使用しています。

それのソースコードは以下になります。


DetailViewController.swift

import UIKit

import MMMarkdown

class DetailViewController: UIViewController {

static func instantiateViewControllerWithItem(item: ItemResponse) -> DetailViewController {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let viewController = storyboard.instantiateViewControllerWithIdentifier("DetailViewController") as! DetailViewController
viewController.item = item
return viewController
}

@IBOutlet weak var textView: UITextView!
private var item: ItemResponse!

override func viewDidLoad() {
super.viewDidLoad()

// Do any additional setup after loading the view.
setupView()
}

override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}

}

/// MARK: - private methods.
extension DetailViewController {

private func setupView() {
if let htmlString = try? MMMarkdown.HTMLStringWithMarkdown(item.body) {
let style = "<style>img { max-width: 300px; height: auto; }</style>\n"
let body = style + htmlString
print(body)
if let data = body.dataUsingEncoding(NSUnicodeStringEncoding) {
let attribute = [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType]
if let attributeText = try? NSAttributedString(data: data, options: attribute, documentAttributes: nil) {
textView.attributedText = attributeText
}
}
}
textView.editable = false
}

}


DetailViewControllersetupView()の中でMarkdownを表示するテキストに変換しています。

これだけで表示することができました。


余談

let style = "<style>img { max-width: 300px; height: auto; }</style>\n"を追加しているのは 画像がそのままのサイズで表示されているからです。

比率を保ったまま、表示するので適当に設置してみました。

あとUITextViewですが、かなり色々できるクラスになっています。

以下のページがわかりやすく紹介してくれているので参考にするといいかと思います。

iOS - [Objective-C] HTMLを使って文章をスタリングする - Qiita


終わりに

Markdownを返してくるサービス(API)ってあまり見かけませんが、自社サービスとか社内サービスとかにはいいかもですね。

以上になります。


参考