0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

android用銀行デモアプリ

0
Posted at

デモアプリのラマ銀行をandroidで作る

ラマ銀行 https://qiita.com/tnagata/items/471ff499b3bd9e9eff33
のバックエンドをそのままし、フロントエンドをandroidアプリにする
開発環境: Windows 11 Home, Android Studio Otter 2025.2.1
実行方法:バックエンドはaxum079フォルダでcargo run(ダウンロード方法などは上記の記事を参照)
フロントエンドはエミュレータ上で動かす(詳しくは下記参照)

アプリの実行イメージ

スクリーンショット 2026-05-05 112640.png

スクリーンショット 2026-05-05 104456.png

右側のweb版から25000円送金して、左側のandroid版で入金が確認できる

アプリの仕様概略

  1. ホームページ: 新規口座開設(登録)とログインボタン
  2. 口座登録: ユーザー名、パスワード、氏名、口座番号(アルファベット1文字 + 4~6桁数字)、初期残高を入力
  3. ログイン: ユーザー名とパスワードで認証。失敗時はエラーメッセージを表示
  4. ログイン後の機能: 残高表示(初期ページ)、送金処理、取引履歴、登録情報、本人確認写真のアップロード
  5. 以下のボタンで各ページに遷移する
  6. 送金: 送金先口座番号と金額を入力。残高不足時は警告を表示
  7. 残高
  8. 履歴: 過去1ヶ月の入金・送金履歴を表示
  9. プロファイル パスワードの変更
  10. アップロード 本人写真のアップロード

📂 ソースファイルの役割・機能(1行要約)

 ①アプリ基盤・エントリポイント

  • MainActivity.kt: アプリのエントリポイントで、Jetpack
    Composeを用いた画面遷移(Navigation)の管理と依存関係の注入を行う
  • NetBankApplication.kt: アプリケーション全体のライフサイクルと初期設定を管理する基盤クラス
    ②データ層 (Data Layer)
    ローカル保存 (Local)
  • data/local/AuthPreferences.kt:
    SharedPreferencesを使用し、JWTトークンや口座番号などのログイン情報をデバイス内に安全に保存・管理する

データモデル (Model)

  • data/model/AccountModels.kt: 残高照会レスポンスや取引明細(Transaction)などの口座関連のデータ構造を定義する
  • data/model/AuthModels.kt: ログインや新規登録リクエスト、それに対するレスポンスのデータ構造を定義する
  • data/model/LocalDateTimeSerializer.kt: APIのISO 8601形式の日時文字列をKotlinの LocalDateTimeへ変換するためのシリアライザー
  • data/model/ProfileResponse.kt: プロファイル画像パスを含むユーザー情報のレスポンスを定義する
  • data/model/TransferRequest.kt: 送金元・先、金額、メモといった送金処理に必要な情報を保持するデータクラス
  • data/model/UploadResponse.kt: 画像アップロード成功時のメッセージやファイルパスを受け取るためのモデル

リモート通信 (Remote)

  • data/remote/AccountService.kt:
    Ktorクライアントを用い、残高取得・履歴照会・送金・画像アップロード等のAPI通信を実装する
  • data/remote/AuthService.kt: ログインおよび新規口座開設のAPIエンドポイントへのリクエストを担当
  • data/remote/HttpRoutes.kt:
    Rust(Axum)バックエンドのベースURLや各APIエンドポイントのパスを一括管理する定数クラス
  • data/remote/NetworkModule.kt: Ktor
    HttpClientの初期化(JSONシリアライズやログ設定)と、各サービスのシングルトン提供を行う
  • data/remote/UserService.kt: パスワード変更など、ユーザー設定に関連するAPI通信を担当
  • data/remote/model/ChangePasswordRequest.kt: パスワード変更時にバックエンドへ送信するデータを定義する

リポジトリ (Repository)

  • data/repository/AuthRepository.kt: AuthService
    をラップし、UI層に対して認証関連のビジネスロジックを抽象化して提供する
  • data/repository/UserRepository.kt: UserService をラップし、ユーザー情報の変更操作などをリポジトリとして管理する

③ UI層 (UI Layer)
画面 (Screens)

  • ui/BalanceScreen.kt: ユーザーの現在の残高を円単位で表示し、メインメニューとして機能する画面
  • ui/HistoryScreen.kt: 取引履歴を時系列にリスト表示し、入出金の詳細を確認できる画面
  • ui/HomePage.kt: アプリ起動時に表示されるトップ画面で、ログインや口座開設のナビゲーションを提供する
  • ui/LoginScreen.kt: ユーザー名とパスワードを入力して認証を行い、成功時にトップ画面へ遷移させるUI
  • ui/ProfileScreen.kt: パスワード変更などのユーザーセキュリティ設定を行うための専用画面
  • ui/RegisterScreen.kt: 新規ユーザー登録と初期入金を行い、新しく口座を開設するための入力フォーム画面
  • ui/TransferScreen.kt: 他の口座への送金機能を提供し、金額やメモを指定して実行する画面
  • ui/UploadScreen.kt: 本人確認用の画像を選択・アップロードし、プロファイル画像を更新する機能を提供する

UI共通コンポーネント・テーマ

  • ui/BottomNavigationBar.kt: 主要画面間の移動とログアウト機能を提供する、アプリ共通の下部ナビゲーションバー
  • ui/theme/Color.kt / Theme.kt / Type.kt: Material Design
    3に基づいたアプリ全体の配色、ダークモード、タイポグラフィの設定を行う

④ 状態管理 (ViewModel)

  • ui/viewmodel/RegisterViewModel.kt:
    口座開設画面の状態(入力中・通信中・成功・エラー)を管理し、非同期処理を制御する

🔄 処理フローの詳細解説を2例

①フロントエンドからバックエンド、データベースを経てJWTが返されるまでのログイン処理のフローを解説する:

(1) フロントエンド:ユーザー入力と送信

  • LoginScreen (ui/LoginScreen.kt)
    • Button onClick:
      ユーザーが「ログイン」ボタンをタップすると、coroutineScope.launch(コルーチン)により非同期通信が開始される。UIをフリーズさせずにバックグラウンドで処理を行う
  • AuthService (data/remote/AuthService.kt)
    • loginメソッド: 通信ライブラリ Ktor HTTP Client を使用し、入力された username と password を LoginRequest (JSON)
      としてサーバーへPOST送信する
    • ポイント: 接続先URLはエミュレータからPC本体を指す http://10.0.2.2:3001 を使用する

(2) バックエンド:リクエストの受信とルーティング

  • create_app / auth_routes (axum079/src/lib.rs)
    • ルーティング定義により、Androidアプリからの POST /auth/login リクエストが handlers::auth::login
      関数にルーティングされる

(3) バックエンド:認証処理(DB照合とパスワード検証)

  • login ハンドラ (axum079/src/handlers/auth.rs)
    • DB照合: sqlx::query_as を使用して、SQLiteデータベース(usersテーブル)からユーザー名に一致するレコードを検索する
    • パスワード検証: bcrypt::verify
      関数を使い、アプリから送られた平文パスワードと、DBに保存されているハッシュ化されたパスワードを照合する

(4) バックエンド:JWT生成とレスポンス送信

  • login ハンドラ (続き)
    • Claimsの作成: ユーザーIDと有効期限(24時間後)を含む Claims 構造体を作成する
    • JWT生成: jsonwebtoken::encode 関数を使用し、サーバー側の秘密鍵で署名してJWT(トークン文字列)を生成する
    • レスポンス送信: 生成されたトークンとユーザー情報を LoginResponse構造体に詰め込み、JSON形式でフロントエンド(Androidアプリ)に返す

(5) フロントエンド:JWTの受信と永続化

  • AuthPreferences (data/local/AuthPreferences.kt)
    • データの永続化: 受信したJWTトークンをAndroid標準の SharedPreferencesに保存する。これにより、アプリを終了しても次回起動時にログイン状態を維持できる
  • Navigation (MainActivity.kt)
    • 画面遷移: ログイン成功のコールバックを受け取り、navControllerを用いて「残高照会画面(BalanceScreen)」へ遷移する

AndroidとWebアプリ(Dioxus)版との対比する:

  • 非同期処理: Rust の async/await に相当する機能として、Kotlin では Coroutines (コルーチン) を採用。suspend
    関数を組み合わせることで、Rust 同様に同期処理のような見た目で非同期通信を安全に記述できる
  • 通信ライブラリ: Rust の reqwest や surf の代わりに、Kotlin マルチプラットフォームでも定評のある Ktor HTTP Client
    を採用している
  • セキュアな保存: Dioxus(Web/Desktop)で設定ファイルや localStorage に保存していた情報の代わりに、Android
    OSが提供する SharedPreferences を利用して認証情報を管理している

② 取引履歴表示ついて、フロントエンドからDB、そして画面にデータが表示されるまでのフローを解説する:

(1) フロントエンド:リソースの要求

  • HistoryScreen (ui/HistoryScreen.kt)
    • LaunchedEffect: Dioxusの use_resourceに相当する機能。画面表示時にコルーチンを起動し、非同期で取得を開始する
    • AuthPreferences: LocalStorage の代わりに、Androidの SharedPreferencesからログイン中の「自分の口座番号」と「JWTトークン」を読み出す
  • AccountService (data/remote/AccountService.kt)
    • 読み出したトークンを HTTPヘッダーの Authorization: Bearer <トークン> にセットし、/api/history/<口座番号>
      へGETリクエストを送信する

(2) バックエンド:認証とルーティング

  • AuthUser ミドルウェア (axum079/src/middleware/auth.rs)
    • Androidアプリから送られてきたヘッダーのJWTを検証する。有効であればリクエストを続行させ、無効であればエラーを返す
  • get_history ハンドラ (axum079/src/handlers/transactions.rs)
    • ルーティングにより、認証済みのリクエストがこのハンドラへ到達する

(3) バックエンド:SQLクエリの実行

  • SQLxによる検索
    • sqlx::query_as を使用し、SQLiteの transactions テーブルに対してクエリを実行する
    • 条件: from_account(送金元)または
      to_account(送金先)が、引数で渡された自分の口座番号と一致する全レコードを抽出する
    • 日時: DBには日時は UTC(協定世界時) で保存されており、そのままの形で取得される

(4) バックエンド:レスポンス送信

  • JSONシリアライズ
    • 取得した取引データのリストをJSON形式に変換し、フロントエンド(Androidアプリ)へレスポンスとして返す

(5) フロントエンド:パースと日本時間への変換
ここが Android 版での最大の特徴で、

  • LocalDateTimeSerializer (data/model/LocalDateTimeSerializer.kt)
    • JSON内の日時文字列(UTC)を Kotlin の LocalDateTime オブジェクトへデシリアライズする
  • TransactionItem (ui/HistoryScreen.kt)
    • 日本時間への変換: バックエンドから届いた UTC の時間を、ユーザーが住む 日本時間(JST) へと UI表示の直前に変換する
   val formattedDateTime = transaction.created_at
         .toInstant(TimeZone.UTC)                   
      // UTCの「Instant」として認識
         .toLocalDateTime(TimeZone.of("Asia/Tokyo")) 
      // 日本のタイムゾーンに変換
         .toJavaLocalDateTime()                     
      // 整形用にJava形式へ
         .format(DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm")) 
      // 文字列に整形
    • 表示の最適化: 自分の口座番号と比較し、送金(赤)か入金(緑)かを判定してアイコンや色を出し分け、LazyColumnでリスト表示する

技術的なポイント

  • バックエンドの共通化: 前回のWebアプリ(Dioxus)と同じ Rust コード、同じミドルウェア、同じ SQL クエリが Android
    アプリでもそのまま機能している
  • フロントエンドの責務:
    バックエンドはあくまで不変のデータ(UTC)を返し、フロントエンドがユーザーのコンテキスト(端末のタイムゾーン)に合わせて表示を調整するという、モバイル開発のセオリー通りの実装になっている
  • ライブラリの使い分け: Rust の chrono で行っていた処理を、Kotlin では kotlinx-datetime で実現している

🚀 試してみたい方へ

GitHub リポジトリ: https://github.com/tnagata/llamabank-rust

  1. リポジトリをクローン
  2. README.md の指示に従って backend(axum079) を起動
  3. esato / esato123 でログインして動作確認!
  4. 次に
  5. 新規登録も試して!

:fireworks: 実機での検証

最後に先月購入したandroidタブレット Xiaomi Pad7でも検証した。
ipアドレスをプライベートなアドレスに書き換えるだけ、と思いきやAndroid OS (v16)の強固なセキュリティにより、Cleartextの送信が許可されない。manifestファイルに許可を書いてもダメで、ソースコードを変更することになった。
IMG_0244.jpeg

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?