【iOSアプリ】Sans の制作過程を紹介するよ【スクショ検索】

どうも。Reoです。

本日リリースされた iOS アプリ「Sans – Screenshot Searcher」の制作過程を紹介していこうと思います。

アプリの紹介記事は此方→「【iOSアプリ】文字認識でスクリーンショットを検索・整理するアプリ「Sans」をリリースしました!

 

Sans – Screenshot Searcher とは

Sans(サンズ)は、「スクリーンショット内の文字を認識して検索・整理するアプリ」です。

AppStoreにて配信中です。

 

制作期間

このアプリは一度制作しようとして、技術的に難しくて諦めていたアプリになります。

2020年7月27日にプロジェクトを作成して、それから1ヶ月ほど戦ったんですがどうしても上手くいかず、諦めて Repotch を作成していました。

Repotch をリリースした後に、改めてアイディアを練り直して、制作を開始しました。

2020年11月14日に新規プロジェクトを作成して、2021年1月24日リリースなので、約2ヶ月半(+1ヶ月)って感じですね。

11月12月は結構サボってる日多いな…

 

Repotch での記録は こんな感じです。165.1時間…!

 

最初のアイディア

最初のアイディアは、スクリーンショットを文字認識してそこにマーカーを引きたい!というものでした。

以下はアイディアメモの一部です。

これを1ヶ月かけて形にしようと頑張っていたんですが、文字認識の精度のあまりに酷さに挫折しました。あとはマーカーを引くっていう部分もかなり大変で、矩形をとってハイライトすることはできても、タップした場所の文字列を取得するのが難しくて、挫折です。

作ってる最中にこんなアプリもいいんじゃないか?とメモしたのが以下になります。

Sansはこっちのアイディアを実現したものですね。マーカー機能とWebサイトの話は死んだ。

 

調査

SSMarker として作成したアイディアが失敗していたので、そもそもこのアイディアが実現可能なのか、実現して使い物になるのかどうかの調査から始めました。

最初からもう挫折ですよね。

まず、日本語を文字認識できるライブラリが少ない。そこの壁から始まりました。

日本語の文字認識に対応したライブラリは

のほぼ二択でした。(なんか他もあった気がするけど忘れた)

OCR のライブラリ自体は結構あるんですが、どれも日本語対応がされていないんですよね。Apple公式の Vision もまだ日本語対応されていません。

日本語を含めないことも考えたんですが、やっぱり自分がまともに使えないアプリはなぁと日本語の認識ができるものを選択しました。

 

ライブラリ選定

SwiftyTesseract

SwiftyTesseract はオープンソースのOCRライブラリです。

メリットは

  • 無料で使える
  • ローカルで解析ができる

デメリットは

  • 認識精度が悪い
  • 認識に時間がかかる

でしょうか。

とにかく SwiftyTesseract で調べると、日本語は認識精度が悪いという記事ばっかり出てきちゃうぐらい…

 

MLKit

FirebaseMLは、Google が提供する機械学習用のSDKです。

此方はクラウドベースになります。

メリットは

  • 認識精度が良い

デメリットは

  • 従量課金制

此方は実際に試してはいないので、スピード感とかはちょっとわからないです。

 

両方を調べて比較して、「SwiftyTesseract」を選択しました。

理由としてはやっぱり、従量課金が怖いです。ユーザー1人が1000枚のスクリーンショットを持っていたらそれだけで課金が始まってしまう。

選択して認識ではなく、すべてのスクリーンショットに文字認識をかけるので、流石に恐ろしすぎて無理でした。

 

プロトタイプ作成

実際に、端末内のスクリーンショットを取得して文字認識をする機能の実装を始めました。

手順は以下です。

  1. 端末から PHAsset を取得
  2. PHAsset から UIImage の取得
  3. SwiftyTesseract で文字認識
  4. Realm に認識した文字と画像の ID を保存

これをスクリーンショット1枚1枚に行うわけです。もう時間がえらいかかるわけですよ。

この実装をして、数枚を文字認識させて、「Twitter」と検索をかけてみると、ちゃんとTwitterのスクショが出てきたんですよ!おお、これはいけるぞ!と。

反面、3の工程でメモリリークする問題が発生していました。

あとは、認識中にも操作はできるように非同期処理にしないといけない等の問題がとにかく多かったです。

 

このメモリリークがとにかくどうにもできなくって、かなり諦めかけてましたね。autoreleasepool しても意味ないし、ライブラリ側の自分じゃどうしようもないところでリークしちゃってる感があって、本当に終わったなと思ってました。

 

RxSwiftへの移行

ダメ元で、RxSwift への移行をケツイしました。

上記の1~4の手順をゆっくり川流れさせれば、いけるのではという考えでした。多分 Rx 使わなくてもできるけど、結構面倒臭い。

いやー。RxSwift やるのも半年以上ぶりぐらいだし、個人アプリでは初めての採用だしで、結構大変でした。

でもRxSwiftありがとう!!!!おかげで認識中のメモリリークの壁を超えました!!!

この処理で乗り切りました。(唐突なコード)

unrecognizedScreenshots
    .skip(1)
    .take(1)
    .map { $0.map { $0.localIdentifier } }
    .observeOn(ConcurrentDispatchQueueScheduler(qos: .background))
    .flatMap { Observable.from($0) }
    .buffer(timeSpan: DispatchTimeInterval.seconds(10), count: 1, scheduler: ConcurrentDispatchQueueScheduler(qos: .background))
    .compactMap { $0.first }
    .bind(to: fetchAssetAction.inputs)
    .disposed(by: disposeBag)

buffer のおかげですよ本当。RxSwift をちゃんと書けてるかはわからんです。

 

UIの詳細決定・実装

メインの機能が実現できたので、UIや機能の洗い出しをしました。

この時はまだタグ機能があったんですが、最終的に消しました。よくわからなくなったので。

あとはこれにそってとにかく実装するだけでしたねー。タグ機能をなくした以外は完全にこのままです。

 

名前決め

リリース前夜に数時間でアプリ名を決めました。

仮名はSSSearcher(スクリーンショットサーチャー)だったので、SSSを雷に見立てた感じにするイメージだけはあったんですが、そこからなかなか出てこなかった。

呼びやすい名前と響きがよくて、それなりに意味があって…SSを並べると結構まずいのと、スクリーンショットをSSって呼ぶ人間は結構少ないぞというのと…

最終的に、「SSS」->「3つのS」->「3S」-> 「Sans」です。安直。

頑張ってAppStoreにいるサンズを倒すのが目標です💀

 

アイコン決め

アイコンアイディアはこんだけです。

決定したのはピンクのやつですね。ネオンっぽくしたかった。アイコンもただの3つのSですよ。

アイコンを決めてから、アプリ内のアクセントカラーもピンクにしました。

 

スクショ作成とかローカライズとかもしてますが、適当なので割愛。

 

Uploadができない問題

最後の壁もだいぶきつかったですね。Archive後のValidateが通らなくてアップロードができない。

App Store Connect Operation Error
Invalid Bundle Structure – The binary file ‘Sans.app/Frameworks/libtesseract.framework/libtesseract’ is not permitted. Your app can’t contain standalone executables or libraries, other than a valid CFBundleExecutable of supported bundles. Refer to the Bundle Programming Guide at https://developer.apple.com/go/?id=bundle-structure for information on the iOS app bundle structure.

というエラーで死んでました。これを解決してアップロードするのに1日かかりました。

Archiveファイルから直接 libtesseract.framework を取り除くという多分正解じゃない方法で解決してます。

 

2度のリジェクト

2回のリジェクトをされちゃいました。どっちも同じ箇所です。

写真へのアクセス許可をするアラートの説明文でリジェクトされました。

1回目はローカライズ忘れて日本語で提出して、2回目は説明不足ということで落とされました。プライバシー周りはやっぱり審査厳しくなってるなぁって感じました。

その後、修正して無事にリリースされました。

 

制作を終えて

Sans は、とにかく技術面で実装が苦しかったです。ギリギリ実現させたって感じのアプリなので、認識した文字列をみると、本当にリリースしちゃって大丈夫だったのか?って思ってしまいます。

今後のアップデートはバグ修正ぐらいにとどめて、AppleのVisionが日本語対応されたり、他に良いライブラリがでてきたら移行する予定です。MLKit はちょっと使う勇気ないです。

あとは広告消しを…(毎度言って今までに実装したことない)

 

いやー。がんばったよ、これは。Repotch より画面数少ないのに、制作にかかった時間にあんまり差がないので。重かった。

 

次に作るアプリは、久々に公式に寄せないデザインです。絶賛制作中です。

2人で作っているので無事に完成させて、リリースさせることが目標です。既に何度か私のメンタルが死んでパーにしそうになっているので本当に頑張ります。リリースまで頑張って、ちゃんと誰かともできるよっていう証明になってくれないと困る。(既に手遅れ感やばいけど)

 

おわりに

是非インストールして使ってみてください!!

AppStore にて Sans – Screenshot Searcher をインストールする

 

あと仕事探してます。(雑)(タヒ)

 

 


ごめんなさい少し吐き出し。

いや本当に絶望的にお金がなさすぎて余裕がなくて、友達と遊ぶことも躊躇ったり、酷いこと言ってしまったりする…今かなり良くない。リリースの達成感よりも、逃げ場がなくなってしまった感が強すぎてやばい…。

もしこんな私にiOS教わりたい人とかいれば連絡ください…

いや、ちゃんとした仕事を探さないとなんだけど、情緒不安定になりまくって死んでるので、えっこの状態からでもできる仕事があるんですか?になってしまっている…。

技術力あっても人間力なかったら結局ダメなんですよ。技術力も大したことないけどさ。今現在個人アプリ開発兼1人のメンターで月収2万円とかで、もう家賃どころかカード代も払えなくて、彼氏や友達にお金借りてる状態のクソオブクソよ。生きる選択すら苦しい。こんなことブログの最後に書いてること自体がもう最悪だよ。

無限に一人で作りたいものだけ作っていられれば、それだけで良いのにね。

お目汚し本当にごめんなさい。とにかく未来ある選択ができるように変わっていかないと。このブログをみる限り何一つ変わってないけどさ…。

鬱発信でできた友達もいるけど、こんなものに共感しますなんてどうか言わないでほしい。必ず違う部分があるから、痛みは分けらんないし慰めにもならないよ。

ちょっと誰にも見せない専用ノートでも作って、ちゃんと自分自信と向き合いますわ…。

頑張る。

Sans
コメントは認証制です。詳しくは下記の注意をお読みください。お気軽にコメントお願いします!

Write a Comment

コメント時の注意

「Twitter」「Facebook」「Google+」「WordPress」のいずれかのアカウントをお持ちの方は各アカウントと連携することでコメントできます。 コメントしたことはSNSに流れませんので、アカウントをお持ちの方はこちらの方法でコメントを投稿して下さると嬉しいです。 アカウントをお持ちでない方はメールアドレスで投稿することができます。 初回コメント時は承認後に表示されます。

Related Memo...

UINavigationController + UIScrollView の組み合わせで使っている時に謎の余白ができる時

UINavigationController + UIScrollView の組み合わせで使っていて、UIScrollView 上に AutoLayout で上下左右0で View を設置しているのに、30px程度上にずれてしまうとき。

`navigationController.navigationBar.isTranslucent = false` にすると直るかもしれない。

ScrollView上のコンテンツとNavigationBarの重なっているところが透過していたら多分これで直せるはず。

通常のターゲットではちゃんと動いているのに、iOSSnapshotTestCase を用いたテストでだけこの対応が必要なのよくわからないけれど。。。

iOS

UITableView.RowAnimation の .none はアニメーションするよ

UITableView.RowAnimation の .none はアニメーションがnoneなわけじゃなく、デフォルトの設定を使うよという意味らしい。

The inserted or deleted rows use the default animations.

なのでアニメーションしちゃう。今更の気づき。

 

iOS

記事を書くほどでもないけれどメモっておきたいこと

テスト投稿。

例えばiphone7 の画面サイズ

750 × 1334
半分375 × 667

iOS
more