はじめに
こんにちは。 私は徳島大学院で物質機能化学の研究を行っている修士2年のakidon0000です。
私は3年前に個人で徳島大学生向けに 「トクメモ+」 というアプリをiOS、Androidで開発し、
・ダウンロード数 5200件
・MAU 3259ユーザー (徳大学部生の 約56%)
のアプリを大学非公認で運用しています。
本記事は、「トクメモ+」 がどういった経緯で開発され、どんな活動をしてきたのかをまとめたものです。
トクメモ+についての発表スライド
トクメモ+とは、どんなアプリなのか
本アプリは、徳島大学の講義情報やレポート提出、そして学内情報などの一元化を目的としており、それにはevaluateJavaScriptや、Webスクレイピング、そしてRSSフィードなどを活用し、学生生活のほとんどが一つのアプリで完結するという形で実現したアプリです。
https://www.youtube.com/watch?v=zRVeZhip5ow
トクメモ+紹介動画
.
.
.
と大層な言葉で説明していますが、やっていることとしては大学が提供しているWebサイトに自動ログインして表示させる"まとめサイト"アプリです。
学生からの評判は良く
- 月間利用者数 学生の50 %以上
- レビュー評価件数 273件
- 平均レビュー評価 4.7
時系列
月 | 内容 |
---|---|
2021 | |
8-9月 | トクメモ+を個人開発し、iOS版をリリース |
2022 | |
2-3月 | Android版の開発リリース |
4月 | 徳島大学公認の学生団体を設立(11名) 500ダウンロード突破 |
11月 | 1000ダウンロード突破 |
12月 | 広告機能を追加し、無償で部活動の告知などを掲載し続ける & トクメモ+をイメージした曲を作ってもらう(徳島大学作曲DTM研究部) |
2023 | |
1月 | 部活・サークル一覧機能の実装 |
2月 | 学生団体の解散 |
3月 | 開発メンバー募集目的で「徳島大学もくもく会」を実施 (計5回実施) |
4月 | 2000ダウンロード突破 |
5月 | 開発メンバー募集目的で「プログラミング質問会」を実施 (計2回実施) |
6月 | プログラミング質問会で出会った子を誘ってグループを立ち上げ |
8月 | 3000ダウンロード突破 |
10月 | 学園祭機能の実装 |
2024 | |
4月 | 部活サークル専用の新歓カレンダー機能追加 |
6月 | 活動メンバー6名 |
7月 | 5000ダウンロード突破 |
開発の動機
トクメモ+ができる前から徳島大学には
大学公式のiOS, Androidアプリありました。
機能として1つの大学Webサイトにおける自動ログインを行ってくれます。
しかし、以下の欠点がありました。
1, ログインしてくれるWebサイトは使用頻度が低いもの
2, 使用頻度が高い方のWebサイトの閲覧はできなかった
3, タイムアウトするとタスクキルを行う必要があった
私の周りでは、このアプリを使ってる子はおらず、アプリのレビュー欄も大喜利がされている状態でした。
これをきっかけに、自分でより便利なアプリを作ろうじゃないかと思い開発を始めました。
大学のWebサービスの問題点
ログイン後、数十分程でログアウトされる
90分の講義前&講義後で、それぞれログイン作業をする必要がありました🥲
(大学講義を受ける前に資料閲覧のためにIDパスワードを入力してログインし、90分の講義後の小テストを受ける際にはログアウトされているので、再度IDパスワードを入力する必要があった。)
↑こんな画面を見るのはしょっちゅう
学生にとって面倒な制度
大学ではパスワード更新が年1回あり、去年とは異なる10桁以上のパスワードを設定する必要があります。
これは、パスワードを他サイトと流用している学生を考慮すると、年1のパスワード更新は当然の仕組みと思います。
しかし、
・1日に何度も求められるパスワード入力
・年1の更新
・10桁以上が必要
この3つがあるかぎり、パスワードマネージャー等を使わない学生は
覚えやすい、簡単なパスワード、普段使用しているパスワード
を設定してしまうのではと思っています。
この煩雑さは、問題が起こった時の責任追求の回避に思え、その影響を学生が受けているように感じました。
ただ、大学側も学生を思い色々考慮した結果、この仕組みに落ち着いたのかなと思っています。
私は、パスワード入力を自動化させることで、
1日に何度も求められるパスワード入力
を改善し、複雑なパスワードを設定しても問題ないようにしようと考えました
大学関係の情報がまとまっていない
以下は徳島大学関連のWebサイトです
・教務事務システム
成績や出欠、大学からの連絡をみるサイト
・manaba
講義や小テストを受けるサイト
・生協ショップ
大学生協のショップ時間や食堂の期間限定情報サイト
・大学図書館
大学図書館の蔵書検索、貸し出し延長や開館カレンダーサイト
・キャリア支援室
大学の就職相談室の時間予約サイト
・SSS学習支援室
学生が運営している授業内容質問相談会のサイト
・命を守る防災知識
教授が発信している防災についての情報サイト(南海トラフなど)
などなど
これらの情報は全て1箇所にまとまっているわけではなく、ポスターや各サイトにて情報発信しており、Webサイトがあることに知らない学生が多くいました。
APIが提供されていない
情報を集めるにしても、認証をするにしても、第三者が利用する仕組みが大学には用意されていませんでした。
唯一あるのは、大学の広報ニュースはRSSでも公開されており、それを利用できるぐらいでした。
実装
まずは、iOSアプリの開発から取り組みました。
アーキテクチャは、「Androidとロジック部分を共有できるようになればいいな〜」ぐらいの温度感でMVVMを採用していました。
パスワードの自動入力化・自動ログイン機能
当然ながら大学からログイン認証等のAPIは提供されていませんでした。
まず、大学はどのようなログインの仕組みを取っていたかを調べると、
シングルサインオン(SSO)の機能を実装していることが分かりました。
そのため、1度ログインすれば別のサイトでも認証済みで利用することができます。なので、ログイン時の「ID」「パスワード」を自動入力し、「同意ボタンを押す」操作をJavaScriptにより自動化させることを目指しました。
iOSでは、
WkWebViewのevaluateJavaScriptを使って、HTML側にJavaScriptを送り込むことができ、
これらのメソッドを用いて、実装を進めました。
Webサイトのまとめ
身の回りの友人やアンケートなどで、普段使用している大学関連のWebサイトを聞き込み、トクメモ+に組み込みました。
URLは全て以下のように保存しています。
protocol UrlProtocol {
func string() -> String
func urlRequest() -> URLRequest
}
enum Url: String, CaseIterable, UrlProtocol {
// ----- 大学教務 関連 -----
/// 教務システム(PC)
case courseManagementPC = "https://eweb.stud.tokushima-u.ac.jp/Portal/StudentApp/Top.aspx"
...
}
extension Url {
/// URLを文字列として返す
func string() -> String {
return rawValue
}
/// URLをURLRequestとして返す
func urlRequest() -> URLRequest {
let urlString = rawValue
let url = URL(string: urlString)! // fatalError
return URLRequest(url: url)
}
}
現在は、GitHubホスティングサービスなどを用いて、アプリアップデートを行わずにURLの修正を行えるような仕組みを検討中です。
学生証をスマホで再現
徳島大学では学生証をカードリーダーにタッチすることで、
- 授業の出欠確認
- 施設の入館
- 図書館の本貸し出し
などを行っていましたが、これをスマホに取り込むことが出来ないかと調査しました。
が、
結果は無理という判断でした
理由はiOSに単純に実装できるのか?という問題と
もう1つに徳島大学の学生証は「教育機関向けFCFキャンパスカード」を採用していたためがあります。
FeliCaカードは、各カードにIDmという個別のシリアル番号が書き込まれており、区別しているため複製することは困難でした。
でも、せっかくなのでバーコード式の学生証を用意して、観賞用機能を実装しました🥲
実装者: suvalism
また、この年から新規発行される学生証にプリペイド機能が追加され、
金銭トラブルを防ぐため学生証をスマホで再現するのは断念、機能削除しました。
RSS配信されている大学ニュースを表示
そのため、iOS版ではXMLパーサーライブラリのKannaを用いて、実装しました。
RSSに画像のURLが含まれていなかったので、画像のURLだけWebスクレイピングしていた時期もありましたが、WebスクレイピングするならRSSいらねぃじゃん、まぁ用意されてるからRSSで表示させるかと迷走していた時期もありました。
学生のための部活動紹介の欄を掲載
弊大学では、大学公認の部活動を紹介するサイトはありましたが、
学生プロジェクト団体や、非公認団体などをまとめて紹介するサイトがありませんでした。
なので、HTML,CSS,JavaScriptを用いて自作のまとめサイトを作成しました。
また、勝手に掲載するのではなく、申請を受けて掲載する仕組みとしました。
ネイティブ側ではWebViewを表示させているだけですが、
HTML側からネイティブの関数を呼び出し、X(Twitter)やInstagramなどを読み込ませる処理を実装しています。
<li onclick="PostMessage('https://www.instagram.com/tokushimaucc/')" class="list-group-item list-group-item-action tableList"> サイクリング部 </li>
function PostMessage(url) {
if ( navigator.userAgent.indexOf('iPhone') > 0 || navigator.userAgent.indexOf('iPad') > 0 || navigator.userAgent.indexOf('iPod') > 0) {
// iOS用
window.webkit.messageHandlers.tokumemoPlus.postMessage(url)
} else {
// Android用
// document.location.href = url; // 通常に画面遷移する場合
alert(url) // AndroidでKotlinの関数を動かしたい場合
}
}
詳しくは、JavaScript 相互通信 などで調べると出てきます。
extension ClubListsViewController: WKNavigationDelegate, WKScriptMessageHandler {
/// Web側(JavaScript)から値渡し
/// postMessageを受けとり、表示する
/// window.webkit.messageHandlers.tokumemoPlus.postMessage(url)
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
if let urlStr = message.body as? String {
// 押された時に実行したい処理
}
}
}
// Web側(HTML,JavaScript)からKotlinが通知を受ける
override fun onJsAlert(view: WebView, url: String, message: String, result: JsResult): Boolean {
// アラートの表示をキャンセルする
result.cancel()
// 実行したい処理
return true
}
現在の懸念点は、これらの情報を更新できるのがトクメモ+運営者のみで負担がかかるという点
それぞれの学生団体運営者に管理者権限を与えて、簡単に修正できるGUIを提供することも検討しています。
学生のための広告欄(掲載費無料)を実装
現状の大学には学生の活動を告知する場がとても限られています。(図書館の掲示板など)
それより、MAU(月間利用者数)が学生の50%以上のトクメモ+に掲載することで、より宣伝効果があると考え実装しました。
ありがたいことに、これまで多くの掲載を行ってきました。
詳細情報ボタンを押すと、各掲載団体が指定したWebサイトへと遷移します。
イベントに対応する機能
学園祭や各団体の新歓イベントカレンダーをWebで自前実装し、
誘導するボタンを生成
立ちはだかる壁たち
このアプリの作成、運用、維持、利用者拡大は、簡単な道のりではありませんでした。
認められない大学公認
以前に1度、大学に公認アプリとして認めてもらえないかと打診したことがありました。
公認アプリとなることで、
- IDとパスワード入力に不安を感じる利用者が少なくなる
- アプリ利用者が増加する
- 知名度が向上し、運営メンバーを獲得しやすくなる
- 教授などと連携し、アプリに新規機能を追加しやすくなる
- 学外から見た大学ブランドの向上
のメリットがあると考えていました。
まずは、
大学の情報センター長へメールにて連絡
↓
徳島大学 学務室に相談してほしいと言われる
大学の学務室へメールにて連絡
↓
徳島大学 広報室に相談してほしいと言われる
情報センター、学務室から広報室にやってきたことを追記し、メールにて連絡
↓
自分では対応できないので、偉い人に相談するとの返信
↓
(偉い人からの返信)
ある関東の大学生が作った大学生用アプリで、個人情報が漏洩した新聞記事がある。
同じようにあなたのアプリでも、個人情報を保存しており漏洩のリスクがあるため、
大学公認と認めることはできない。
概ね、想像していた対応でした。
そのため、この偉い人に対して、
- 「トクメモ+」が個人情報はサーバーに保存していない
- 漏洩するとしても、個人の端末から一つだけ
- 情報はAppleやGoogleが推奨している保存方法でセキュアに保存している
と説明しても無駄だと悟りました。
その後、
大学公認アプリ開発団体を作ることで前述したメリットは達成できる
と考え、学生団体を設立した。
また、大学内サーバーを借りることはできないかと情報センターに打診したこともありますが、
「問題が発生した際の責任は誰が取るんだ」
「大学としては学生に責任を負わせることはできない」
「必然的に先生になるが、好んで責任をとってくれる先生はいない」
という話になり、断念しています。
大学の情報センター室からの呼び出し
アプリをリリースして2年ほど経ったあと、大学の情報センター室からトクメモ+の件についての呼び出しがありました。
要件は
- トクメモ+アプリを大学公認と勘違いした学生がバグ報告を情報センターにしにくるので、アプリ内でわかりやすくしてほしい
- 学生達のIDやパスワードはどのように保存されているのか
- 1度入力したパスワードは、生体認証等がない限りは安易に再表示させないでほしい
- このアプリで自動化している利用規約の画面をスキップしないでほしい
とのことで、呼び出し後に即アプリのアップデートを行い修正しました。
DOS攻撃にならないように対策
このアプリでは、JavaScriptをHTMLに送り込み実行することで、事前にユーザーがトクメモ+に保存したIDやパスワードを入力、ボタンの押下などを実行するして自動化する仕組みです。
重要なのが、WebView
で読み込みが完了(didFinish
)したタイミングで、指定したログイン入力が必要な画面のURL
と一致指定していれば、JavaScriptを送り込むという点です。
パスワードを間違えて登録し、それを実行した場合を考えてみます。
パスワードを間違えているとユーザ名かパスワードが違います
とアラートが出るとともに、URLのパラメーターが s1
-> s2
へと変化しています。
これを元にこのパラメーター変化で自動入力の成否を決定しても良さそうだと思われるかも知れませんが、
私はこのパラメーターで自動入力の成否を決めてはいけないと考えました。
というのも、大学非公認で活動しているため、確定した情報ではなかったからです。
もし、
- サーバーの仕様が変更された
- 想定していた仕様と異なっていた
とした場合、
このログイン処理がループする可能性があり、複数のデバイスからDOS攻撃によって大学のサーバーが停止。授業がストップするなど被害が現れる事態は避けないといけません。
この解決には単純に状態管理をしてあげることで解決します。
enum LoginState {
case .loggedIn: // ログイン中にログインが完了すればURLドメインが変わるので判定可能(例外なし)
case .loggingIn: // アプリ起動時や再ログインが必要な時
case .loggedOut: // パスワード未入力ユーザー
case .timeOut: // タイムアウト時
}
しかし、タイムアウト問題という別の問題も出現しました。
セッションのタイムアウトが発生すると、別の画面が表示されますが
URLもパラメーターも変化なし、HTTPステータスも変わらず
といった状態になり、判断基準がなくなってしまったため、
として、現在も正常に稼働中です。
10秒にした理由は、何回かログイン処理を試した結果
5秒以上かかることは稀にあり、10秒を超えることは無かったから
レガシーな図書館カレンダー問題
徳島大学附属図書館の開館カレンダーはアンカーhref属性
にPDFファイルへのパスが指定されており、
https://www.lib.tokushima-u.ac.jp/pub/pdf/calender/calender_main_2023.pdf
を読み込んであげると、
開館カレンダーのPDFが表示されます。
syuusei
許せん
RSS等で配信してもいいものが、時代を逆行しているのかこのような状態で公開されていました。
これに対しては、Webスクレイピングで対応することにしました。
力こそ正義 パワー ハッ... 👁️👄👁️
運営にお金がかかる問題
トクメモ+のアプリは全て無料で、広告料も無料なため、収入がゼロなわけです。
しかし、無情にもサービス提供や環境改善にはお金がかかります。
これまでに、
- 部活動リスト
- 広告の掲載
- イベントに対応する機能
- Discordのボット開発
- 新歓イベントカレンダーの申請対応
などを開発してきましたが、それぞれサーバーが必要になってきます。
私有しているラズパイをサーバー代わりにすることも検討しましたが、性能面セキュリティ的、置き場所等に不安があり断念
そのため、以下の二つを使用して解決しました。
- GitHubのホスティングサービス
- Google Apps Scripts (GAS)
GETしかできないWebAPIもどきはGitHubのリポジトリにJsonファイルを置き、GitHub PagesのActionを動かすだけで再現
関数の定期実行などはGASを用いることで
どちらも無料枠で再現可能でした。
その他
学生団体やグループを作るにあたって、開発以外の面でも考えないといけないことが多くありました。
コミュニケーションツール
コミュニケーションツールにDiscordを以下の理由で採用しました。
- Discordには「緩い」「発言しやすい」と思わせるイメージがある
- 基本的にオンラインコミュニケーションなので、ボイスチャンネルなどを用意したい
- この団体はグループというよりコミュニティ。Slackは、「仕事」というイメージがあるため合わない
- Slackの無料プランは90日すぎると発言履歴が無くなる
Discordの環境は主に、Hikaが献身的に行なってくれました。
Hika (@Hikax138)
このDiscordは一般外部にも公開されており、誰でも入れる状態です。
そのため、さまざまなチャンネルを用意し、各々が雑談をしている状態を生み出しています。
属人性の低減 & 自動化
全てのアカウントを私が保有している状態がありました。
継続的に運用するにあたって、少しづつ私しか知らない情報を減らしていこうと考えました。
主に、ねこ (@Nekoq0o0p)が環境整備を行なってくれました。
アプリの使用状況
AppStoreConnectやGooglePlay,FirebaseAnalyticsから情報を取ってきて、グラフ化させ
毎晩Discordに通知するbotを作成しました。
他にも
Gmailの内容や、お問い合わせに使用しているGoogleFormsの内容を通知してくれたりと便利なBotが沢山あります。
おわりに
この記事は、
@koheisato さんの記事に感化され、書き始めました。
これまで、大したことはしていないと思っていましたが、振り返ってみると色々な出来事を経験していたなと思いました。
他にも、大学非公認で活動しているアプリ達があるようですね👀
学生エンジニアが大学関係のアプリを作るのは"あるある"っぽい
現在の課題は、iOSとAndroidの開発ができるのが自分しかいないという点です。
以前までは、開発コストを下げるためにFlutterにフルリプレイスすることを検討していましたが、Flutter学生エンジニアを育てるという点で挫折してしまいました。
現在は、アプリを開発・運用してくれる企業を見つけたので、これを交渉材料に大学に運用してもらえないか交渉することを検討しています。
この記事を書いた人
松山 晃大
徳島大学大学院 物性化学専攻
https://github.com/akidon0000