2020年2月12日水曜日

HTML ドキュメントのオフライン化

HTML ドキュメントをアプリ内の asset(場所は app/src/main/assets/ )として APK に内包して WebView で表示するサンプル。画像や CSS、HTML 同士の相対リンクも機能する。バックキーでリンクを戻れるようにもしている。

MainActivity

import android.app.Activity;
import android.os.Bundle;
import android.view.KeyEvent;
import android.webkit.WebView;
import android.webkit.WebViewClient;

public class MainActivity extends Activity {
    WebView webView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        webView = findViewById(R.id.webView);
        webView.setWebViewClient(new WebViewClient());
        webView.loadUrl("file:///android_asset/index.html");
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK && webView.canGoBack()) {
            webView.goBack();
            return true;
        }

        return super.onKeyDown(keyCode, event);
    }
}

layout/activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <WebView
        android:id="@+id/webView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</FrameLayout>

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="(パッケージ名)">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

複式簿記システムの構築 2

複式簿記システムの構築 2 の続き。今回は、減価償却資産とそこから減価償却費を算出するためのシステムの構築について考える。スキーマ的にはこんな感じで十分か。

create table Depreciable_Assets (
 id integer primary key,
 name text,
 date date,
 value integer,
 depreciation_years integer,
 apportion real,
 description text
);

上を基にして Google Spreadsheets の表を作ってみた。仕訳帳と違って適宜更新するようなものではないので、Google Spreadsheets にする必要もなく、直接 TSV を作っても違いはない。

この表を基にして、その年度での減価償却費用を算出し、決算整理仕訳の処理の一環として組み込めばいいわけだ。

確定申告的には、上の処理は、国税庁側のシステムが行うので、自前で用意したとしても二度手間になり、どうしても必要というほどのものでもない。

2020年2月11日火曜日

Firebase Crashlytics

Firebase 推しの Google に従って Firebase Crash Reporting を導入したと思ったら、少し経ったら Google 都合で Crashlytics に変更を余儀なくされることになった。

Crash Reporting に比べて、結構、設定が複雑で、適当に一つ目に導入したアプリのプロジェクトを見て二つ目にも導入しようとしたら、意外と抜けていたので、公式の説明を一つ一つ確認してやるのが無難だと思った。Google の日本語のチームが糞なのか、単に日本語のサイトが糞なのかどちらかわからないが、Crashlytics の公式のページが Android を選択しても iOS の説明しか表示せず、内容以前にサイトの表示機能自体がバグバグだし、そういう問題がない場合でも Developers サイトの日本語版の情報は内容的にも大体が、古くて腐敗した有害ですらある情報だったりもするのであくまでも英語の公式ページを参照すべし。

また上記の通りに設定しても、依然として LogCat に Crashlytics 絡みの謎のエラーログが出ていたので、StackOverFlow で調べたところ、Firebase のコンソールでアプリの署名の SHA-1/SHA-256 のハッシュ値を登録しておいてその設定 JSON ファイルを使う必要があるとのこと。鳴り物入りで Crashlytics へ変更された割には、まだ全然洗練されてないような気がするのだが……。(この件も、英語版ではちゃんと修正されていた。日本語版情報が腐っているだけの話のようだ)

2020年2月10日月曜日

ANDROID_ID の Android 8.0 における仕様変更

ANDROID_ID が Android 8.0(Oreo: API-26)において仕様変更されたようだ。このため、従来のように ANDROID_ID がデバイス固有の ID と思って扱っていると、意図しない結果につながる。

Android ID

In O, Android ID (Settings.Secure.ANDROID_ID or SSAID) has a different value for each app and each user on the device. Developers requiring a device-scoped identifier, should instead use a resettable identifier, such as Advertising ID, giving users more control. Advertising ID also provides a user-facing setting to limit ad tracking.

Additionally in Android O:

  • The ANDROID_ID value won't change on package uninstall/reinstall, as long as the package name and signing key are the same. Apps can rely on this value to maintain state across reinstalls.
  • If an app was installed on a device running an earlier version of Android, the Android ID remains the same when the device is updated to Android O, unless the app is uninstalled and reinstalled.
  • The Android ID value only changes if the device is factory reset or if the signing key rotates between uninstall and reinstall events.
  • This change is only required for device manufacturers shipping with Google Play services and Advertising ID. Other device manufacturers may provide an alternative resettable ID or continue to provide ANDROID ID.
Changes to Device Identifiers in Android O (10 April 2017)

基本的に ANDROID_ID の値はデバイス固有ではなくなり、アプリ毎に提示される ANDROID_ID が異なる。さらに、同じアプリであっても、APK にされたサインが異なると別アプリの扱いとなるので、debug ビルドと release ビルドとでは別アプリの扱いとなり、提示される ANDROID_ID が異なることとなる。

自分の場合、開発者モードを識別するために予め登録した ANDROID_ID(を基に算出した Admob ID)に基いてテストデバイスを識別していたが、なぜか意図通りに認識されないので悩んでいたが、こういうことだった。

GooglePlay には、Admob ID を表示できるアプリなどがあり、最近のレビューではちゃんと表示されないという文句が多く見られたが、それもこれが原因だろう。Android 8 以降かそれ以前かで挙動が異なるわけである。

2020年1月27日月曜日

WebView と HTTPS

HTTPS の証明書の有効期限が切れていたりしてエラーになる場合、WebView では読み込みがされないという(デフォルトの)挙動結果となるようだ。

また、エラーの場合でも強制的に読むようにオーバーライドもできるようである:Android WebView not loading an HTTPS URL

2020年1月17日金曜日

複式簿記システムの構築 1

個人的に青色申告による複式簿記が必要なので、そのための必要十分なシステムを構築する。
(市販の会計ソフトは決して「必要十分」ではなく、単なる「十分」(つまり不必要な余計な要素を過剰に備えている)ので、論外。)

おおまかなイメージとしては:

  • 逐次発生する会計イベントは人手によって「仕訳」してデータを入力し、1 年を通じてデータベース(仕訳帳)に蓄積する
  • 年間の蓄積された仕訳帳に基く年度末の「総勘定元帳の集計」と「決算整理仕訳」と「損益計算書の作成」は、Python プログラムで自動化する。

具体的には:

  • 仕訳帳は Google SpreadSheets を利用して家族で共有
  • 集計・決算整理・損益計算は、Google SpreadSheets から TSV をダウンロードして、SQLite にインポートし、Python で SQL を駆動してそれらの定型化された作業を行い、結果を複数の TSV としてアウトプットする。最後にそれら TSV を単一の .xlsx ファイルにマージして一つの総勘定元帳として得る。

仕訳帳のスキーマ(Google SpreadSheets)

create table Journal (
 id integer primary key,
 parent_id integer,
 date date,
 amount integer,
 debit text,
 credit text,
 description text
);

ID は Google SpreadSheets 上では、単に「行番号+1」の計算式を使っただけのもの。

親IDは、借方 or 貸方が諸口(複数科目)となる場合の「一対多」または「多対多」の仕訳のために用意した要素。グルーピングするエントリーのIDを親ID として指し示す。

通常の一対一の仕訳
「ID」「日付」「金額」「借方科目」「貸方科目」を示し、「親ID」は NULL
一対多(または多対多)の仕訳の親エントリー
「ID」「日付」を示し、「親ID」は NULL
「金額」「借方科目」「貸方科目」は両方とも「諸口」の場合は NULL だが、片方が単一の場合は、そのままその科目と金額を使い、一方だけ諸口とすればよい。
一対多(または多対多)の仕訳の子エントリー
「ID」「親ID」「金額」「借方科目」「貸方科目」のみを示し、「日付」は NULL

プロトタイプ

  1. Google SpreadSheets からは手動で journal.tsv をダウンロードする。
  2. pptsv.py で TSV をプリプロセスする(日付や金額のフォーマットの修正)。
  3. macOS 標準の sqlite3 コマンドを使って、accounting.sqlite ファイルに table を新規作成し、プリプロセスした journal.pp.tsv をインポートする。
    .mode tabs
    .import journal.pp.tsv Journal
  4. Python 経由で上記データベースを処理して、決算整理仕分けを行ってデータベースをアップデートし、各勘定科目に分け、.tsv でエクスポートする(accounting.py)。
  5. 勘定科目別にエクスポートされた .tsv を merge2xlsx.py で単一の 総勘定元帳.xls にマージする。

このプロトタイプで、各処理を確立できたので、最終的に、accounting.py のみで TSV のプリプロセス以降の処理を一挙に行えるようにコーディングし直して、一応の完成を見た。


今後の課題

毎年の確定申告に困らない程度のシステムの構築には至ったが、損益計算書までであり、資産に関する処理(貸借対照表)は未対応である。特に減価償却費が自動化できていないと、損益計算書も本当の意味で完成したとは言えないので、せめて減価償却資産については、対応できるようにしておきたい。

複式簿記システムの構築 2