真面目なブログはこっち 👉 blog.s64.jp

ExcelでUnicodeなcsvを綺麗に開く

ExcelはWindows文化を汲んでいるので、Shift-JISおよびそれ系文字コードではないcsv (tsv) を開こうとするといわゆる "文字化け" が起こる。
これを開く方法を調べると「一度テキストエディタで開いてBOM付きUnicode保存する」なんていうのばかり出てきて本当にゲンナリするので、Excelだけでやる方法をメモ。

1. Excel上で空のExcelブック (シート) を作る

ちょっとここは悲しいけど致し方ない。この時点では保存しなくて可

2. リボン上の「データ -> テキストファイル」をからcsvを開く

Chooserが出るので対象のファイルを見る

3. 「元のファイル」として「Unicode (UTF-8)」を選ぶ

データ形式として最初から「区切り記号付き」が選択されている。
エンコーディングは他エンコーディングならそれ。ダイアログ下部のプレビューが化けて無ければOK。

4. 区切り文字を選択

デフォルトでは区切り文字として「タブ」が選択されているかもなので、csvならカンマに変える。
そのほか気になる項目があれば変える。
正しく区切り文字が設定されれば、プレビューに罫線が入る。

5. 必要に応じて、各列のデータ形式を設定する

4でプレビューに罫線が入ったので、列ごとにクリックして設定する。

6. 既存のシートに挿入する

これはあくまでインポートツールなので、空のシートに挿入する扱いになる。

Visual Studio Codespacesで "Login failed due to an..." みたいにログイン失敗する場合

Visual Studio Codespacesを使おうとして、ログイン時に下記表示になり失敗することがある:

Login failed due to an unexpected error. Please log out and try again.

Log out

Image from Gyazo

エラーの詳細が無くハマったのだが、どうもこれは3rd party cookieのブロックによって発生している模様。
Chromeのプライベートブラウズ機能を使っている場合、新しいタブページの「サードパーティのCookieをブロックする」を無効化すれば、正常に進むことができるはず。

Image from Gyazo

生徒のみなさん、手間取らせてしまってすまねえ

Androidライブラリ開発でRuntimeInvisibleParameterAnnotationsとなりアプリがビルドできない時の対処法

明確な原因まではわからないものの、対処法までは見つかったのでとりあえず書く。ざっくり言うと、Jetifierのバグを踏んだらしい。

問題の再現手順

ライブラリプロジェクトとして、Android Support Libraryを用いたものを作成する。AndroidXではない。

api "com.android.support:support-annotations:28.0.0"

下記のようなEnumクラスを作成する。ポイントなのは、コンストラクタのパラメータにAnnotationが付けてあること。

public enum MyOriginalEnum {
  
  MyOriginalEnum(@Nullable Integer hoge) {
    // do something
  }
  
}

このクラスをライブラリとして参照するプロジェクトで、Jetifierを有効にする。gradle.propertiesにある。

android.useAndroidX=true
android.enableJetifier=true

このEnumをJavaコードから参照する。importだけでも再現する。Kotlinから参照する場合は関係ない。

Log.d("Hoge", MyOriginalEnum.values());

すると、下記のようなエラーになってコンパイルができない。

エラー: MyOriginalEnumにアクセスできません
クラス・ファイル/Users/****/.gradle/caches/transforms-2/files-2.1/****/jetified-****-api.jar(****/MyOriginalEnum.class)は不正です
RuntimeInvisibleParameterAnnotations属性が不正です: MyOriginalEnum(Integer)
削除するか、クラスパスの正しいサブディレクトリにあるかを確認してください。

対処方1

Enum側のパラメータに付与してあるAnnotationを外す。今回の場合は @Nullable を外すので、IDE補助がなくなる。

対処法2

Jetifierを使わない。どうもこの問題はJetifierによるバイトコードの変換で発生しているらしい。

対処法3

Kotlinコードからしか参照しない。試したところ、Kotlinからしか参照しない分には問題は発生しなかった。

2020年賀状を住所を知らないネットの友達に自作デザインで送る

2020年 (2019年末投函分) の場合、日本郵便のはがきデザインキット2020 Web版を使えばいける。
ハガキを用意しなくても、クレジットカードさえあれば印刷から投函までぜんぶやってくれるので便利。

1. ゆうびんIDでログイン

なければ作る。Webアプリ右上の「新規登録 / ログイン」からいける。

2. 全面写真レイアウトで作る

はがきを作るをクリックすると、レイアウトをテンプレートから選択する画面になる。
特段こだわりがないだとか、気に入ったデザインがあるのならここから選んでもよい。その場合、テキストメッセージ, スタンプ, 手書き文字, 写真アリの場合は画像の差し込みくらいなら可能。

今回はオリジナルのデザインにしたいので、上部バー内にある「写真あり」から「全面写真」を選ぶ。

f:id:S64:20191226115728p:plain

3. 用紙を選ぶ

フチ無しの場合は写真用紙、フチありの場合は写真用紙で作る。

4. 入稿データを作る

入稿データと言うけど、ただの画像ファイルでOK。jpg, png, gifに対応。1181x1748 (px) で作るとよい。
フチ有無問わず、四隅5mmが塗り足し(裁ち落とし)となることが利用ガイドで明記されているので注意。 なお、全面写真の場合はマージンなしで配置されるのので気にしなくて良いのだが、フチありの場合は後述するエディタでフチ分のマージンを入れた状態で配置されてしまう。px換算すると60px分になるようなので、その分を差し引いた形式にするとよいかもしれない。

5. エディタにアップロードする

写真を想定しているので、自動補正を掛けることもできる。掛けないこともできる。

6. メッセージ等追加要素を入れる

前述したメッセージやスタンプなどを追加できる。なお後述するとおり送る相手によってメッセージを追加で配置することも可能なので、相手により内容を変更したい場合はここでは何もしなくてよい。

7. 保存する

デザインを保存すれば後から追加注文などもできるので、一旦ここでは保存にしておく。

8. マイデザインから注文へ進む

右上メニューのマイデザインから保存済のデザインを呼び出し注文できる。

9. 配送相手を選ぶ

相手の住所がわかっていれば、ここで「直接相手に届ける」をクリックし必要事項を入力すればよい。プリントから投函まで自動で行われる。
今回はネットの友達宛なのだが、ここで2通りの方法がある。
どちらの場合も自分には相手の氏名や住所が見えることはなく、相手側の個人情報が割れることはない。

相手にTwitterのDMが送れる場合

「Twitterの友達に送る」をクリックし、自分のTwitterアカウントと連携する。宛名登録画面になるため、左側の「友達を選択する」から相手を選ぶ。
このあとの手順を済ませ注文を確定すると、自分のTwitterアカウントから相手へ直接DMが飛ぶ。ここにある専用URLから相手に受領ないし拒否をしてもらい、住所を入力してもらう。

注文確定から数分後にDMが届くようなので、おそらくキューかなんかに溜まっている。

f:id:S64:20191226122857p:plain

相手のメールアドレスがわかる場合

「メールアドレスで送る」をクリックし、「送り先を登録する」から住所録に追加していく。
必須項目は「氏名」「メールアドレス」だが、どちらも受領されるまでしか利用されない。具体的には、受領依頼メール内での文言とその送信先としてしか使われない。そのため相手に見られてもよい限りは氏名には何を入力しても問題ない。

このあと手順を済ませ注文を確定すると、receive_m@design-kit.jpのFROMで相手にメールが届く。ここにある専用URLから相手に受領ないし拒否をしてもらい、住所を入力してもらう。

f:id:S64:20191226122038p:plain

※住所もTwitterもメールアドレスもわからないけど個別連絡が取れる場合

LINEだとかFacebook Messengerで送るメニューはないためアンオフィシャルな使い方になるが、下記の手順で正常に受領してもらえることを確認した。

  1. 「メールアドレスで送る」へ進む
  2. 自分が受け取れる形式でメールアドレスを指定する
  3. 受け取ったメール(の専用URL)をコピーする
  4. 相手へ個別メッセージで送る
    • 発行されるURLが個人専用なので、不特定多数が踏めてはいけない

f:id:S64:20191226122748p:plain

10. 差出人を登録する、またはしない

名前, 郵便番号, 住所 を入力し、宛名面に印刷する差出人名を設定できる。
ただし、郵便は差出人を書かなくても届けることができ、左側チェックボックスの「宛名面に印刷しない」を設定すればこのステップをスキップできる。もし相手に実名や住所を教えたくない場合は印刷を無効にすればよい。

f:id:S64:20191226123318p:plain

11. 必要なら、個別メッセージなどを挿入する

左側で相手を選ぶと、個別のデザインプレビューが出る。ここで「デザインを編集する」をクリックすることで、個別にメッセージやスタンプなどを挿入できる。

f:id:S64:20191226123555p:plain

12. 注文内容を確認し、購入手続きをする

10枚以上送るなら、一度の注文でまとめて手続をすると割引が効く。
相手が受け取るか否かが確定しないため、ここではクレジットカードのみ利用可能。決裁をすると、一度オーソリとしてカードに全ての受領があった場合の請求が走る。もし相手が受取拒否ないし期限までに受領しなかった場合、その分が返金処理される。

以上で手続は完了。

手続の期限

注文が確定され相手にメッセージが届いてから3日以内に手続が行われなかった場合、その分はキャンセル扱いになり、前述のとおり枚数分の返金処理が走る。
また、相手にはこの3日間ずっと催促メッセージが飛ぶので注意。

f:id:S64:20191226124436p:plain

法務省のソフトが何度やっても「ICカードリーダの初期化に失敗しました。ICカードがICカードリーダに差し込まれているか確認してください。」となるので手順を書き起こす

合同会社の設立に伴って法務省の「申請用総合ソフト」を使うときにマイナンバーカードを使って署名を付けたりするんだけど、何度やっても正しいであろう手順を踏んでも

ICカードリーダの初期化に失敗しました。ICカードがICカードリーダに差し込まれているか確認してください。

というエラーで失敗してしまう。
めちゃくちゃ数十回と再試行しまくって、やっと下記手順でやれば再現性のある形で署名ができることを確認した。

  1. 申請用総合ソフトを起動しておく
  2. ICカードリーダを接続する
  3. 「ツール」 ->「オプション」 を開く
  4. ICカード切り替え タブに切り替える
  5. 「使用するICカードライブラリを登録します。」の「登録」ボタンをクリックする
  6. 「使用するICカードライブラリを切り替えます。」で「個人番号カード」を選ぶ
  7. 「適用」をクリックする
  8. 「設定」をクリックする(ダイアログを閉じる)
  9. 目的の「署名付与」へ進む
  10. 「ICカードで署名...」をクリックする
  11. 「ICカード差し込み確認」というダイアログが出るので、このタイミングでマイナンバーカードを差し込み、次へ進める
  12. パスワードを入力し、次へ進める
  13. これで署名成功!

マイナンバーカードを挿入するタイミングやICカードリーダを接続しておくタイミングがけっこうシビアで、これをミスるとすぐエラーになる模様。

Android WebViewのUserAgentいくつか

端末 / 環境 API Level バージョン Implementation User Agent
Genymotion 16 4.1.1 n/a Mozilla/5.0 (Linux; U; Android 4.1.1; en-us; Custom Phone Build/JRO03S) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30
Emulator 16 4.1.2 n/a Mozilla/5.0 (Linux; U; Android 4.2.2; en-us; Android SDK built for x86 Build/JB_MR1.1) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30
Emulator 17 4.2.2 n/a Mozilla/5.0 (Linux; U; Android 4.2.2; en-us; Android SDK built for x86 Build/JB_MR1.1) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30
Emulator 18 4.3.1 n/a Mozilla/5.0 (Linux; U; Android 4.3.1; en-us; Android SDK built for x86 Build/JB_MR2) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30
Emulator 19 4.4.2 n/a Mozilla/5.0 (Linux; Android 4.4.2; Android SDK built for x86 Build/KK) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/30.0.0.0 Mobile Safari/537.36
Genymotion 19 4.4.4 n/a Mozilla/5.0 (Linux; Android 4.4.4; Custom Phone Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/33.0.0.0 Mobile Safari/537.36
Emulator 21 5.0.2 n/a Mozilla/5.0 (Linux; Android 5.0.2; Android SDK built for x86_64 Build/LSY66K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/37.0.0.0 Mobile Safari/537.36
Emulator 24 7.0 Chrome WebView Mozilla/5.0 (Linux; Android 7.0; Android SDK built for x86_64 Build/NYC; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/51.0.2704.90 Mobile Safari/537.36
Emulator 24 7.0 Google WebView Mozilla/5.0 (Linux; Android 7.0; Android SDK built for x86_64 Build/NYC; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.124 Mobile Safari/537.36
Genymotion 24 7.0 AOSP WebView Mozilla/5.0 (Linux; Android 7.0; Custom Phone Build/NRD90M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/51.0.2704.91 Mobile Safari/537.36
Emulator 28 9 Chrome WebView Mozilla/5.0 (Linux; Android 9; Android SDK built for x86_64 Build/PSR1.180720.075; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/69.0.3497.100 Mobile Safari/537.36
Emulator 28 9 Android System WebView (Google) Mozilla/5.0 (Linux; Android 9; Android SDK built for x86_64 Build/PSR1.180720.075; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/69.0.3497.100 Mobile Safari/537.36
Genymotion 28 9 Android System WebView (AOSP) Mozilla/5.0 (Linux; Android 9; Custom Phone Build/PD1A.180720.031; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/66.0.3359.158 Mobile Safari/537.36

Android 4.4.x (API 19) にはiframe内anchorに挙動差異のあるバージョンが混在している

Android 4.4.2(とそれ以下)のWebView内でiframeに含まれるWebページ内のAnchorクリックをしても、ページの遷移イベントを取れない時がある。
具体的には、通常WebViewでは画面遷移時に WebViewClient#shouldOverrideUrlLoading というコールバックが叩かれるのだが、これが動かないパターンがある。

いくらか確認してみたところ、これはtarget属性によって挙動が変わっている模様。たとえば

<a href="https://example.com" target="_blank">_blank</a>

というリンクの場合、WebView内のさらにiframen内で遷移してしまう。

対し下記の場合、

<a href="https://example.com" target="_top">_top</a>

ちゃんと期待どおり WebViewClient#shouldOverrideUrlLoading が呼ばれる。

この挙動チェックはGitHubにサンプルアプリを置いた。

github.com


(Android 4.4.3環境が手元にないので)Android 4.4.4で同じ挙動を確認すると、どちらのリンクも期待どおりWebViewClient#shouldOverrideUrlLoadingが呼ばれる様になっている。

4.4.3はわからないが、少なくとも 4.4.2 と 4.4.4 の間には挙動の差異が存在する。


なお、4.4.xにおけるWebViewの挙動差異は他にも存在して、たとえばPromiseが4.4.2までは存在しないのに対し、4.4.3からは利用できたりする。

h.s64.jp

上記記事に記したとおり、内部のChromiumバージョン変更が行われており挙動にいくつかの差異が発生しているのが実態のようだ。