たくさんの自由帳

ブラウザと USB で APK インストール + 開発者認証の文句

投稿日 : | 0 日前

文字数(だいたい) : 10660

どうもこんにちわ。
Pixel 10 Pro Fold届きました、初!!!!!!!フォルダブル?折りたたみ?スマホです。

pixel10profold_unboxing

こわいのでケース買います!純正のは高いので適当にアマゾンで買おうと思いますが、そういえばわたしプライム会員じゃ無いんですよね。
without プライム会員なのでいつも送料無料になるまでなにか探しています。最近だと実物写真取るのに背景が映ると嫌なのでちっちゃい撮影スタジオみたいなのを買いました。グリーンバック

それで今回は、、、会社のチームメンバーにプライム会員!!!がいらっしゃったので代わりに買ってもらいました。
なお商品の値段だけ払った模様。プライム古事記ですよねそうです。

case

プライムはや~~~い、
プライム会員、お急ぎ便とか無料配送とか抜きにしても確か映画とかドラマが見れるらしい。
わたしもガリレオの映画(3つ目のやつ)まだ見れてない。あとすみっコぐらしも絵本のやつ良かったから他のも見たい。

めちゃいいかんじです。ヒンジ?開いたときに収納される部分も守ってくれるやつを買いました。高いからね仕方ないね。
折りたたまない方の画面の保護フィルムは自分で貼りたかったのですが、折りたたみスマホのケースって大体こっちの画面も守ってくれるんですよね。ガラスフィルムみたいなのが一体になってる。保護フィルム見たく粘着するんじゃなくてはめるだけ。
多分画面を覆うようにはめ込む設計にしないと落っこちちゃうからだと。どうしても縁?バンパー?だけなら両面テープ。

でもどうしてもフィルムを使いたかったので、、、ガラスを割りました。でもほんのちょっとだけ怪我したのでおすすめしません
バンパーだけじゃ落っこちちゃうので付け焼き刃ですが両面テープを貼りました。怪我したけどさらさらのアンチグレアフィルムが使えて満足(いつもPDA工房Perfect Shieldを買ってる)

screen_protector

最後に初感

めちゃいいです。おりたたみ。多分フリック入力のが早いんだけど、開いたときのローマ字が良い。
GmailとかGoogle KeepとかGoogle マップがでかい画面対応してていいな~、アダプティブレイアウト作りたいな~気分になりました。layout.xmlじゃないしそんな難しくないと見込んでるけどどう?

css_mediaquery

あと、これならスマホでMarkdownも夢じゃないのでは!?!?

以上です。本編行くぞ!!!

先に完成品

Chromeブラウザを使ってAPKファイルをインストールする

first

confirm

installed

本題

近い将来、APKファイルを直接配信する開発者に対しても、Googleは開発者登録を強制する。

わるさをするAPKを繰り返し配信し続ける奴らを締め出したい。のが目的らしい。
身元を特定できるようにして、もうインストール出来ないようにするらしい。別にアプリを審査するわけではなく、ただ前科がある開発者かどうかを見るだけっぽい。

いやめんどくせえな、君たちがGoogle Play製品版のハードル引き上げたんだろうに、次はこれかよ。

何が困る

Apple iPhoneとは違うある程度開かれたプラットフォームを期待してた人は残念だし、APKファイルを配るだけなのにGoogleへ個人情報を渡さないといけない。

macOSもサードパーティアプリに対してが、どのルートで配布するにしてもAppleに登録が必要。これを公証とか言うらしく、macOSのゲートキーパー機能が公証したアプリか確認しているそう。
これと同じことがAndroidにも来る。。しかも回避策は後述するadb install以外にない。

なんでGoogleに登録しないといけないんだ。自分で買ったんだから自由にできる選択があるだろうよ。

というかこれが執行されるとGoogleの力が強くなりすぎてしまう。Googleにとって都合が悪いアプリを難癖つけて配信停止に追いやることだって技術的には出来る。
それだけの権限があるんだけど。

セキュリティだけであればGoogle Play Protectがあるし、そっちに全振りすればいいと思う。

水面下ではすでに開発者認証で使われるであろうAPIが登場し始めています。
https://developer.android.com/sdk/api_diff/36.1-incr/changes/android.content.pm.PackageInstaller
本題からずれるので文句は一番最後に書いた。開発者認証の文句

回避策

開発者向けとしてADBコマンドを利用すると回避できるみたいです。
ただADBコマンドを利用するためには、AndroidStudioを入れるか、platform-toolsを単品で入れるかが必要で、開発者でなければ厳しい。

WebUSB

さて、話変わって、Googleが作ってるChrome ブラウザの話でも。

Chrome(とその系列)には、WebUSB APIがあります。これは、フロントエンド開発者向けに、ウェブサイト内でUSBで接続したデバイスと通信したいな~ってときに使えます。
(通信したい時がほとんど無いと思うんだけど、、、)
それこそ、ADBコマンドのようなUSB接続をするようなアプリを、ブラウザだけで作ることが出来ます。

知ってる限り、Google Pixel端末へAndroid OSを入れ直す(焼く)(Flashする)ためのウェブサイトで使われてます。まじでChromeだけで出来る。

一方、このAPIChromeだけで、SafariFireFoxではこのWebUSBは利用できません。
なのでCanIUseChrome 系列のみになっている→https://caniuse.com/webusb

Standards Positions見たけどやっぱりそれぞれ反対してる。

スマホアプリとかはUSBにアクセスしたところで、審査があるので最低限担保されるかもだが、Webではそうはいかない。ユーザーに委ねるのはあまりにも危険。

まあ使い道が思いつかない。
今回みたいに、本来は開発者向けに使われるadb installを何故かパソコンのブラウザだけで出来るように上方修正する。みたいな抜け道としてしか使われなくない?
調べた:マイコンボードに書き込むのに使ってるらしい。Webブラウザでコード書くのかな。GoogleDocsみたいにめちゃめちゃ作り込まれてないとWebベースのIDEは厳しい気が。

ユーザーが騙されてダイアログでUSBデバイスを接続してぐちゃぐちゃにされる未来しか無いんだけど気のせい?

WebUSB で adb install すればパソコンのブラウザだけで開発者認証を回避できるのでは

adb install経由では免除されると、また、WebUSBを使えばADBコマンドの実装が出来そう、、、

あれ、これ、パソコンのブラウザだけでAPKサイドローディング出来ませんか?
adbのセットアップとか無しで。
いいんですか???もちろんパソコンへスマホを接続する必要がありますが。

なんというか、Safari / Firefoxに従っておけば抜け道ができることなんて無かったの、かも。(いうほど抜け道か?)

WebUSB で ADB できるか調査

これがNPM ライブラリっぽく使えそう。

あと先駆者さんがいました、
Chu!人のネタのパクリでごめん(そういえば HoneyWorks 原点回帰した!??!)

つくった

冒頭の画像を再掲しますが、、、

first

confirm

installed

ADBの実装は↑のライブラリを使っているだけです。
あとは適当にNext.js (static export) + TailwindCSS + TypeScriptです。
WebUSBはもちろんブラウザ JavaScriptAPIなので、Next.js使ったけどクライアントコンポーネントです。

ボタンを押してWebUSB API経由で端末と接続し、APKファイルを選択するとインストールが開始されます。
.apkファイルをAndroidへインストールするために、もうあの黒い画面、コマンドプロンプト・PowerShellのようなターミナルさんに一切触れること無くインストールできます。
ほんとにパソコンにはChromeが入っていればそれだけで良くなった。

なんか実装が間違っているのか、常にUSB デバッグを許可しますか?のダイアログがでています。
localStorage的なのに書き込んで永続化する必要があったかもしれません。

感想

作った感想だよ~

GoogleChromeLabs/wadb が今日のフロントエンドで動くようにする

git cloneしたあと、
デモサイトを消しました。ライブラリ単品で欲しかったので・・・
テストを消しました。すいません。

あと今のTypeScriptで通るようにArrayBufferLikeのあれこれを直しました、DataViewのところをDataView<ArrayBuffer>とジェネリクスの型を渡すようにしました。
とりあえず動いてる。

あとWeb Crypto APIが使えなかった?ためか代替ライブラリを使っていたのですが、ネイティブのWeb Crypto APIで動いてそうだったのでライブラリを消しました。
この代替ライブラリはC言語?のコンパイル処理が存在してて、そのためにはWindowsの場合は多分VisualStudioとかを入れる必要があって・・・

こんな感じに、npx tsc --noEmitが激怒長エラーメッセージが消えればおっけーです。型が合わないエラーメッセージが長いんよな・・・

最後にnpm i ./gitcloneしたときのパスすれば、ローカルにあるnpmパッケージを入れることが出来ます。
どうでもいいですがnpm i githubのリポジトリurlもいけます。

APK ファイルを選ぶ input の mimeType

application/vnd.android.package-archive!!!

<input
    id="apk_select"
    className="px-5 py-2 bg-blue-200 rounded-full"
    type="file"
    accept="application/vnd.android.package-archive"
    onChange={ev => {
        const apkFile = ev.currentTarget.files?.item(0)
    }} />

実際にインストールするまで

GoogleChromeLabs/wadbをつかって

まずは接続に必要なインターフェースを実装します。よくわからないのでデモからコピペしています。

class MyKeyStore implements KeyStore {
    private keys: CryptoKeyPair[] = [];
    async loadKeys(): Promise<CryptoKeyPair[]> {
        return this.keys;
    }

    async saveKey(key: CryptoKeyPair): Promise<void> {
        this.keys.push(key);
        console.log('Saving Key' + key);
    }
}

つぎは接続箇所。
呼び出すと、パソコンのブラウザでUSBに繋いだAndroid端末を選ぶダイアログ?が出るので選んで。
Android端末側ではUSB デバッグを許可するか?のダイアログで許可してあげてください。

const adbClient = useRef<AdbClient>(null)
const transport = useRef<WebUsbTransport>(null)

/** 接続を開始する。ユーザーは開いたダイアログでデバイスを選択すること */
async function connect() { // 近い将来 React Compiler が登場するので、手動で useCallback するのはやめる、JetpackCompose の StrongSkippingMode みたいな
    const options: Options = {
        debug: true,
        useChecksum: false,
        dump: false,
        keySize: 2048
    };

    try {
        const keyStore = new MyKeyStore()
        transport.current = await WebUsbTransport.open(options)
        adbClient.current = new AdbClient(transport.current, options, keyStore)
        const info = await adbClient.current.connect()

        // info に接続した端末の名前とかが入ってる

    } catch (e) {
        // TODO err
    }
}

次にAPKファイルを転送+インストールする処理。いままでadb installと言っていましたが、
正しくはapkファイルをAndroid端末に転送して、そのあとそこからインストールするコマンドを叩く。が正解です。

apkFile<input>onChange = { ev => ev.currentTarget.files?.item(0) }の値です。
HTMLInputElementに生えてますよね。

try {
    // 転送する
    const apkBinary = await apkFile.arrayBuffer()
    const blob = new Blob([apkBinary])
    const tempApkFilePath = `/data/local/tmp/${Date.now()}_android_apk_sideload_web.apk`
    // 1_000_000 にした途端動かなくなった...
    // いい感じにバイト配列を分割して転送してくれるそう
    await adbClient.current?.push(blob, tempApkFilePath, "0755", 5_000)

    // インストールする
    await adbClient.current?.shell(`pm install ${tempApkFilePath}`)

    // 消す
    await adbClient.current?.shell(`rm ${tempApkFilePath}`)
} catch (e) {
    // todo えらー
}

WebUSBの技術的な制約なのか何なのかはよくわかりませんが、一度に遅れるバイトには制限があるらしく、このライブラリでは分割して送ってるみたいです?
手元では1_000_000したら0バイトのファイルが転送されていました。ギリギリで生きるのをやめます。

あとはインストールコマンドと削除。
よくみるとadb installとかadb devicesとかのコマンドではなく、adb shell した後にするコマンドを入れる必要がありますね。
adb shell am start -d https://example.comみたいな。

切断するなら。

try {
    await adbClient.current?.disconnect()
    await transport.current?.close()
} catch {
    // 物理的に引っこ抜いたとか...
}

おわりに

CloudFront+S3でサイトを公開したのですが、これからもこの構成で公開するとなるとCloudFormation的なのを作っておこうと思い作ってたんですが3日ぐらいかかりました。
使うかわからんものに・・・

あーあ、マネジメントコンソール(ブラウザ)をポチポチしてれば1時間くらいだったのに。

開発者認証の文句

悪口ばっかりなのでもう帰ってもらって結構です。
サイドローディングであーだこーだ言ったところで大多数はサイドローディングしないんだから極論どうでもいいんだよな。

私としてはすでにPlayConsoleに個人情報を渡しているからなあ、それにともないPlayStoreで本名だけは開示されてるし、、、学生とかだとクソきついと思う

開発者認証のためにインターネット接続が必要になる予感。登録済みアプリ全部のリストをローカルに持っておくわけにはいかないだろうし。
個人情報を渡したくない場合は、趣味向けアカウントを作ることが出来るが、これはインストールする端末の識別子(何が使われるかは不明)を登録した後配布する必要がありとても現実的ではない。
https://www.reddit.com/r/Android/comments/1nwddik/heres_how_androids_new_app_verification_rules/

自分で買ったスマホなんだから自由にさせてくれて良くない?Google Pixel 10 Pro Fold26万したんだけど
なんで26万払って自分でアプリを入れるかの選択ができないの?
Android 12にアップデートしてからAndroid/dataフォルダが見れなくなった件も、今回の件も、返金の準備したほうが良いんじゃないかな Google さん?

adb install以外は開発者認証済みのAPKが必要になり、adb以外の回避策はない模様。
GooglePlay 開発者サービスの一つとして実装されると思うので、ユーザーは無効にするとかは出来ない気がする。

開発者サービスを入れない選択はカスタム ROMを入れるときにGoogle なしのを焼くとか、Root権限でなんとか出来るのかもだけど、どっちにろブートローダーがアンロックできないのでやっぱり何も出来ない。通信キャリア許せねえよ
Shizukuでなんとかなるもんなんですかね?希望はある

悪意あるアプリの拡散を防ぐと言っているが、通報を受け付ける仕組みなのか、AIか何かが検知して勝手にアカウントをBANにするのかは調べたけど分からなかった。

Chromeからapkをダウンロードする機能を消せば良くない???こんな極論に走るよりも

applicationIdが被った場合はダウンロード数が多いほうがゲット出来る。

あとこれは去年くらいにあった製品版の制限のが近いけど、AndroidがこのザマならわざわざCompose Multiplatformとかのマルチプラットフォームなんか使わずに、
ファーストは諦めて大人しくiOSだけ作ってれば良い流れになりませんか?流石にそんなこと無いか。

カード会社の攻撃のせいでえっちなのを取り締まってるみたいに、アプリを全部握ったら思わぬ外部からの攻撃で消されることにもなりそう。
下手に握ってると開発者登録があるのに Google はなんで野放しにしてたんだ!!!とかいちゃもんつけられそうじゃないですか?やっぱやめようよ。

仮にAPK配布のための開発者アカウントも、PlayConsoleBANされたら一生 Android アプリを配信できないってことで合ってる?
恩赦は?

開発者アカウントの作成には個人情報を渡す必要がある。一方、それだけで作れる。
少なくともPlayConsoleの方では、携帯電話の契約みたいにeKYCみたいに自分の顔を撮影するやつは要求されないので、誰かの個人情報を入手できれば作れちゃいそうなんだけど。
そしてサイドローディングする開発者向けにわざわざeKYC相当を用意するとも到底思えない。負担すぎるでしょ。

Play Console の本人確認をした - たくさんの自由帳

https://takusan.negitoro.dev/posts/play_console_developer_account_verfy/

アプリストアが泣かず飛ばずだったWindowsを見たのか、どうしてもアプリストアを手放したくない。が、今日、それを各国は許さない。だからせめてものの負け惜しみだと思ってる。

先述したけど、これが執行されるとGoogle都合が悪いアプリを権力行使で利用不可に出来る。それくらいの力がある。インストールするアプリはすべて申請が必要になるので。
Googleが強くなりすぎてしまう。
強くなりすぎてしまった場合、もし仮に、
代わりのアプリストアが登場した時、アプリの審査はそのアプリストアが担当するべきだが、これに加えて何故かGoogle首突っ込んでくることになる。代替アプリストアなのにGoogle許さなければ配信できない。


Googleの力が強くなりすぎてしまう件は以前に似たようなことがあります

Uncomfortable Questions About App Signing

https://commonsware.com/blog/2020/09/23/uncomfortable-questions-app-signing.html

PlayConsoleへ審査のためにアプリをアップロードする際、APKファイルからAABを要求するようになりました。
簡単に言うと、AABファイルが.zipファイルみたいになってて、Google側でzipからスマホ向けタブレット向けや、C++があればARM 64bitx86_64それぞれのAPKを生成します。Androidは引き続きAPKを要求するので、AABから作る必要があります。
一見するとスマホ向けをダウンロードすればタブレット向けのレイアウトが不要になるので通信量を節約できていいじゃん。ってなるんですが、大きなセキュリティの問題が残っていて、それは今日でもなお使われています。
・・・・
.zipからAPKを作る際、もちろん署名をします。署名をすることで、悪さをする同じアプリに擬態しても(applicationIdをパクっても)署名が合わないので更新がブロックされるって仕組みです。
さて、AABからAPKを作る作業はGoogle側がやると言いました。これに伴い、Googleがアプリ毎に署名鍵を作ってGoogleが署名をします。次回以降も署名するためにGoogleが保管します。
・・・
悪さをする同じアプリに擬態しても更新がブロックされるのは、署名がされているからで、逆に言えば署名さえも擬態されてしまえば更新が成功します。
署名さえも擬態することが可能な人間が、ここまでの文章で登場しているのがわかりますか・・・・・・・・・・
Googleですね。彼らは更新が成功する署名鍵を持っているため、正規の開発者からもらったアプリのコードを書き換えたとしても、そのまま署名してしまえば、誰にも改ざんがバレずにアプリの配信ができてしまいます。
・・・
もちろんGoogleは自分自身が勝手に変更したり配布することは無いと言いました。先述の通り不可能ではなく、やろうと思えば出来るはずなので無いdon'tであって、can'tとは言っていない。

Uncomfortable Questions About App Signing

https://commonsware.com/blog/2020/09/23/uncomfortable-questions-app-signing.html

今回も施行されてしまえば強い力を持つことになるので、このようにcan'tではなくdon'tの声明が出る。のかは不明です。