LINEヤフー Tech Blog

LINEヤフー株式会社のサービスを支える、技術・開発文化を発信しています。

LINE iOSアプリ内ブラウザに検索機能を実装しました。

はじめに

こんにちは、iOSアプリエンジニアのKiichiです。こちらの記事で紹介されている通り、今年の3月に、LINEアプリ内ブラウザ上からYahoo!検索できる機能がリリースされました。本記事では、iOS実装を担当した私から、この機能の紹介と、開発における技術的詳細をお届けします。

新機能の紹介

LINEアプリでは、トークルームで送受信したリンクをアプリ内ブラウザで開くことが可能です。このブラウザはもともと、リロードや共有、ブラウザバックなどの基本機能を備えています。しかし、他のWebページへの導線となる検索機能は持っておらず、そのページ内で気になった内容がある場合は別のブラウザアプリで検索する必要がありました。

3月にリリースされた新バージョンのLINEアプリでは、アプリ内ブラウザに検索窓が追加され、そこに文字列を入力することでYahoo!検索をすることができます。Yahoo!検索は日本のユーザーにとってより使いやすくなるような工夫がされているため、今回のアップデートを通して、より快適な検索体験が実現されました。また、この検索窓はアドレスバーの役割も担っており、現在閲覧中のページのURLを確認できるほか、URLを直接入力・ペーストすることでそのURLにジャンプすることも可能になっています。

操作フロー

新機能実装前に、リファクタリング

これまでのLINEのアプリ内ブラウザは、いくつかの機能追加はありつつも、全体的なメンテナンスは行き届いていない状態でした。この状態で大きな修正を加えようとすると、

  • 周りのコードに合わせて古い慣習に従ったコードを書く必要があり、現在プロジェクト内で推奨されている最新のコーディングスタイルを適用できない
  • 関心の分離ができておらず、機能追加に伴い一つのファイル・一つのクラスが肥大化してしまう
  • 多くのロジックがUI実装と密に結合しており、ユニットテストが書きづらい

というリスクがありました。そこで、実際に新機能を実装する前、まだ仕様を議論しているうちから、少しずつリファクタリングを進めることにしました。中身はそれなりに複雑な構造になっており、一気に全てを修正することはできないため、新機能に関わりがありそうな部分だけでも仕様決定前に終わらせることを目指しました。

ファイルの整理

一つのファイルに複数の型定義が含まれており、開発中に参照したい型がどこに定義されているのか分かりにくいという問題がありました。このようなファイルは分割し、基本的には一つのファイルに一つの型を定義して、ファイル名と型名が同じになるようにしました。

また、すべてのファイルがプロジェクトルートに配置されていて、今後ファイルが増えた際に見づらくなることが予想されました。これを解消するため、社内で推奨されているレイヤリングに従うようにディレクトリを作成し、各ファイルがどこに属するかを考えて再配置しました。この時点では、ほとんどのロジックがViewやViewControllerといったUI関係のファイルに含まれてしまっていましたが、そのようなファイルも一旦全てUI用のディレクトリに入れ、ロジックの分離は後で行うことにしました。

Auto Layoutの適用

LINEアプリのUIの多くがUIKitを用いて実装されており、さらにそのうちのほぼ全てがAuto Layoutを用いて実装されています。しかし、アプリ内ブラウザの実装においては、Auto Layoutが推奨される前にAuto Layoutを使わずに実装されたコードが多く残っていました。検索機能実装で想定されるシンプルなUIコンポーネントを追加するだけであれば、Auto Layoutを使用しないことによるバグや開発コストの増加のリスクは低いですが、将来的に複雑なUIを導入する可能性・古いレイアウトコード増加への懸念から、Auto Layoutを適用しておくという判断に至りました。

Auto Layout適用の実装後、QAの段階で発見されたUIバグも少々あったものの、最終的には無事に置き換えを行うことができました。

MVVMアーキテクチャの適用

先述の通り、ほぼすべてのコードがUI関係のファイルに含まれてしまっていたため、追加予定の検索機能に関わりそうな部分だけでも、ロジックを抽出し別ファイルに移動したいと考えました。LINEアプリでは、プロジェクトによってMVPとMVVMという2種類のアーキテクチャがそれぞれ多く使われていますが、アーキテクチャが導入されていなかったこのプロジェクトにおいては、将来的なSwiftUIの導入を見据え、SwiftUIと相性の良いMVVMを採用しました。(その後WWDC25でWebKitのSwiftUI向けAPIが発表されたため、先見の明があったとも言えそうです。)

SwiftUIへの置き換えをすぐに実行するのは難しかったため、UIKitでの実装をそのまま使い、Combineによって状態をバインドすることにしました。

いざ、検索機能実装

新しく追加する検索機能では、サーバーAPIを介して検索結果を取得するほかに、ローカルに検索履歴を保存して表示したり、ブラウザ画面上でアドレスバーとして検索窓を表示したりと、周辺の実装もいくらか必要でした。それらの実装の中でも特徴的だと思われる部分をいくつか紹介します。

SwiftUIの使用

LINEアプリの多くの箇所では、SwiftUI未対応の社内ライブラリに依存しているため、SwiftUIで一つの画面を作り上げるのは難しい状況にあります。しかし偶然にも、アプリ内ブラウザはこのライブラリに依存していないため、SwiftUIを適用することが可能でした。私自身はSwiftUI発表以後にアプリ開発を始めた、いわば「SwiftUIネイティブ世代」であり、ずっとSwiftUIを使う機会を伺っていたため、新画面追加を機にSwiftUIの使用に踏み出すことに決めました。

新しく追加する検索画面はブラウザ画面とは別の画面になっており、ブラウザ画面から検索画面を表示するようになっています。ブラウザ画面はUIKitで実装されているため、SwiftUIで実装された検索画面を表示するにはUIHostingControllerを使う必要があります。ブラウザ画面と検索画面は一部相互にやり取りする必要がありますが、UIHostingControllerを通じてUIKitコンポーネントとSwiftUIコンポーネントがやり取りする実装は複雑化・可読性低下につながるため、ブラウザ画面のViewModel内に検索画面のViewModelをネストし、ViewModel内だけでやりとりが完結するようにしました。

さて、実際にSwiftUIを使った実装を始めてみると、検索窓のテキストフィールドのデザインなど、SwiftUIだけでは実現できない箇所があることに気がつきました。このような箇所は、今後SwiftUIでよりリッチなUIを実現するためのAPIが公式で追加されることを祈りながら、UIViewRepresentableUIViewControllerRepresentableを使ってUIKitコンポーネントを併用することにしました。

入力URLの判別

検索窓には、検索語句の他に、閲覧したいWebページのURLを入力することができるという仕様のため、入力された文字列が検索語句なのかURL文字列なのかを判別する必要があります。例えばhttps://yahoo.co.jpのような文字列は当然URL文字列だと分かりますが、入力のしやすさを考慮すると、yahoo.co.jpのような省略されたものもURL文字列として認識し、自動でhttps://yahoo.co.jpのように置き換えられると良いでしょう。一方で、yahooのような文字列は通常URLとは考えられず、ユーザー体験を考慮しても語句検索として扱うことが妥当でしょう。そのような判別を行うにあたり、自前でロジックを実装する場合、URLの仕様を細かく考慮する必要があります。しかし、そこは検索機能の本質とは離れているため、あまりコストを割きたくありません。

そこで、標準的に提供されているNSDataDetectorを用いてURL判別を行うことにしました。このクラスは、表示されている文字列に含まれるURL文字列をハイライトするような用途が想定されており、本来の使用方法とは異なります。しかし、このクラスによって意図しない文字列がURLとして認識されたりその逆があったりしても、ユーザーの安全面でリスクとなるほどの不正はないだろうと判断し、これを導入することにしました。ただし、foo://yahoo.co.jpのような無効なスキームは除外するため、NSDataDetectorによる判別の後に独自の実装によりフィルタリングすることにしました。

表示URLの整形

ブラウザ画面においては、検索窓はアドレスバーの役割を担っており、現在閲覧中のURLが表示されます。ここに表示されるURLの文字数には限界があり、重要な情報を少しでも多く見せるため、https://などのスキームやwwwなどの汎用的なサブドメインは非表示(例えばhttps://www.yahoo.co.jpの場合yahoo.co.jpのみ表示)にする必要がありました。スキームに関しては、このブラウザはhttphttpsの2パターンしか対応していないため全てのスキームを除いて表示すれば良いのですが、汎用的なサブドメインに関してはそう単純ではありません。

例えばwww.co.jpというURLにおけるwwwは、汎用サブドメインではなく、そのWebサイトにとって重要な識別子です。そこからwww.を取り除くとアドレスバーにはco.jpのみが表示されることになり、ほとんど意味のない文字列に見えます。しかし、www.co.comというURLにおけるwwwは汎用サブドメインです。つまり、先頭のwwwが全て汎用サブドメインというわけでもないし、ドット区切りで右から定数番目のwwwが全て汎用サブドメインというわけでもありません。正しく「汎用サブドメインのwww」を識別するには、co.jpcomのような、「その一つ左に重要な文字列をが置かれるようなドメイン」を知っている必要があります。これは、jpcomのようなトップレベルドメインに追加した「実質的なトップレベルドメイン」という意味で、「effective top-level domains = eTLD」と呼ばれます。eTLDはPublic Suffix ListというGitHub上のリポジトリで管理され、頻繁に更新されているため、開発者によって任意のタイミングでそのリストを取得してLINEアプリに取り入れる仕組みを作り、アプリ内ブラウザのアドレスバーではそれを参照して汎用サブドメインと見なされたとき(eTLDから1つ以上離れかつ一番左のとき)のみwww.を除いて表示するようにしました。

アドレスバーの表示

おわりに

この記事では、LINE iOSアプリ内ブラウザに新たに実装された検索機能の技術的な側面について詳しく紹介しました。これまでの開発プロセスや技術的な選択を通じて、よりスムーズで効率的な検索体験をどのようにして提供することができたかをお伝えしました。

この新機能により、ユーザーはLINEアプリ内でリンクを開く際に、他のブラウザを使わずにその場で検索を行うことができます。特に日本のユーザーにとって馴染み深いYahoo!検索を採用することで、利便性を高めています。ぜひ、この新しい検索機能を試してみて、その利便性を実感していただければと思います。