【Android】メソッド数が64Kを超えてしまいビルドできない
APKビルドしたら突然のエラー
apkビルド時に以下のエラーが出てビルド失敗となりました
Error:The number of method references in a .dex file cannot exceed 64K. Learn how to resolve this issue at https://developer.android.com/tools/building/multidex.html
ちなみにエミュレータでの実行時にはエラーになりません
エミュレータと全然違うじゃん!
もういいよ、私Androidやめる!
何が起きているのか
64K を超えるメソッドを使用するアプリの設定 | Android Studio
要約:メソッド数はライブラリ含め65,536
対処
大抵の場合ライブラリが原因だと思われます
私の場合はGooglePlayServiceが圧迫していました SDKバージョンを変えたことにより、メソッド数もつられて増えたようでした 調べたところGooglePlayServiceだけで2万超えるようです
build.gradleを以下のように変えました
BEFRE
dependencies { compile 'com.google.android.gms:play-services:+' }
AFTER
dependencies { compile 'com.google.android.gms:play-services-gcm:+' }
GooglePlayService利用は必要なものだけ含めましょう
より詳しい対策などはこちら
Githubのbranchesの画面にプルリクエストのタイトルを表示する
やりたいこと
Githubのbranchesのブランチが何のブランチかブランチ名だけじゃわかりづらい なのでプルリク名をだして該当ブランチを見つけやすくしたい
こんな感じに
やり方
専用のChrome拡張を作ってもいいんだけど些末な機能なのでこちらの拡張を利用させてもらう
拡張をインストールしたらいかのコードを貼るだけ
const _wr = function(type) { var orig = history[type]; return function() { var rv = orig.apply(this, arguments); var e = new Event(type); e.arguments = arguments; window.dispatchEvent(e); return rv; }; }; history.pushState = _wr('pushState'), history.replaceState = _wr('replaceState'); window.addEventListener('pushState', function(e) { setTimeout(setPRName, 1000); function setPRName() { const $branches = document.querySelectorAll(".branch-summary"); const style = { "position": "absolute", "top": "12px", "left": "330px", "background": "#a60bff", "padding": "1px 5px", "line-height": "20px", "color": "#fff", "text-align": "center", "border-radius": "3px" }; for (let $br of $branches) { const $btn = $br.querySelector(".state,.State"); if ($btn) { const title = $btn.getAttribute("title"); const $elem = document.createElement("div"); $elem.innerText = title; for (let name in style) { $elem.style[name] = style[name]; } $br.style.position = "relative"; $br.appendChild($elem); } } }
2017/05/10更新 GithubがhistoryAPIで制御されていたので画面遷移後にスクリプトが実行されていなかったので変更 - pushStateをフック - setTimeoutで画面レンダリングを待つ
あまりきれいではない…
alertを使ってjavascriptからJavaへイベントの通知を行う
webview側からAndroid側へ通知を行いたいとき、以下のような方法があります
- JavascriptInterface
- Android側から一定間隔でWebView側を監視
- onJsAlert
JavascriptInterfaceが正攻法で、指定したメソッドをJS側へ公開します しかし、JavascriptInterfaceはv4.2以前だと任意のメソッドが実行可能な脆弱性を持っています
AndroidのWebViewの脆弱性についての私的なまとめ - 金利0無利息キャッシング – キャッシングできます - subtech
古いバージョンをサポートしているといった状況だと使うことが難しくなります
かんたんに連携を行いたい!セキュリティを意識したくないと行ったときにalert
を使った方法が使えます
実装方法
WebChromeClientを継承したクラスでonJSAlert
をoverrideします
@Override public boolean onJsAlert(WebView view, String url, final String message, JsResult result) { if (message != null && message.length() > 0) { if (message.equals("click#button")) { onClickHogeHoge(); result.confirm(); return true; } } }
JS側
$("#button").click(function() { alert("click#button"); });
解説
message
にalertのメッセージが渡ります
この文字列を判定し、任意の処理に流します
result.confirm
を実行することにより、アラートダイアログを終了させます
戻り値をtrue
にすることで、JS側のアラート表示を抑制できます
注意事項
- result.confirmは必ず実行する
これを実行しない場合、アラートが閉じられずアプリがフリーズします
- JSのalertの実行はアプリからの
ブラウザでも同じアプリケーションを提供している場合、当然ながらこのjsをそのまま仕込むとボタンをクリックするたびにアラートが表示されます UA等でアプリからのアクセスかどうかをチェックしJSを実行しましょう (余計なお世話でしょうか)
IPC::Cmdの使い方など
少しハマったので整理
使い方の基本
use IPC::Cmd qw[can_run run]; $command = 'ls'; #コマンドのパスを取得 my $full_path = can_run($command) or die 'ls can\'t use!'; my $buffer; my($success, $error_message, $full_buf, $stdout_buf, $stderr_buf) = run(command => $command, buffer => \$buffer); if (!$success) { die @$stderr_buf[0]; } print $buffer;
文字列を渡す場合の注意
echo "1 2 3 | cut -d ' ' -f1
これをrunに落とし込む場合、
run(command => ['echo', "1 2 3", '|', 'cut', '-d', ' ', '-f1'], buffer => \$buffer);
となる
区切り文字の指定は"' '"
ではない
バッファーについて
実行の戻り値として取得する各種バッファーは配列リファレンスとなっている この配列は実行環境のバッファサイズ(バイト数)で区切られている
改行ではないので、CSV等を取得しループでsplitするといったときにはバッファ同士を結合する事前処理が必要になる
引数で渡した$bufferはすべての出力が入っているのでこっち使うほうが楽
自作のマグネットづくり
かんたんにマグネット作ってみた
用意するもの
- よくポストに入っている水道業者のなどのマグネット
- 好きな画像
- 両面テープ
- カッター
作り方
1. マグネットを水に浸す
用意したマグネット、業者の情報が書いて合って使えたものではありません なのでこれを水に浸しましょう 1時間もずれば表面をはがせ、マグネットだけ残ります
2. 画像をプリント
プリンターを持っている場合は写真プリントなど表面がつるつるした紙にプリントしましょう ない場合も大丈夫 ローソンが使えます
ローソンではプリントに光沢紙が使えます 詳しくはこちら
A4サイズ(3508 × 2480くらい)の画像を用意しスマホ等で持ち込みます
3. 画像を切り取り貼り付ける
あとはかんたんです - プリントした画像を切り抜く - マグネットに両面テープで貼り付ける - マグネットを切り抜く
これで終わりです
そして出来上がったのがこちら
(初めて作ったものなので結構雑…)
GoogleAppEngineでPerlを動かす
GoogleAppEngineは5年前に使ったきり Dockerはよく知らない Perlもまだまだ しかし、ローカル以外の何処かでとりあえず動かしておきたい
こちらを参考にさせていただきました qiita.com
gcloudのインストール
GoogleCloudSDKをインストールします
Google Cloud SDK Documentation | Cloud SDK | Google Cloud Platform
https://cloud.google.com/sdk/docs/#install_the_latest_cloud_tools_version_cloudsdk_current_version
$ tar xvzf google-cloud-sdk-137.0.1-darwin-x86_64.tar.gz $ ./google-cloud-sdk/install.sh $ source .bash_profile #認証 $gcloud auth login
GoogleCloudConsole
プロジェクトを作っておきましょう console.cloud.google.com
gcloudにプロジェクトを設定します(やらなくても大丈夫かと思います)
$ gcloud config set project プロジェクト名
デプロイする
サンプルを利用します ここまでは一緒
$ git clone git@github.com:aql/perl-appengine-sample.git $ cd perl-appengine-sample
SDKの変更があったのか、gcloud preview app --project "foo-bar" deploy .
は動きません
app.yamlの設定を2箇所修正します
diff --git a/app.yaml b/app.yaml index 5ca2107..592d919 100644 --- a/app.yaml +++ b/app.yaml @@ -1,6 +1,5 @@ -version: 1 runtime: custom -vm: true +env: flex api_version: 1
修正後、以下のコマンドでデプロイします
$ gcloud app --project "プロジェクト名" deploy app.yaml
デプロイが完了したら以下のコマンド、またはブラウザから直接開いて確認ができます
$ gcloud app browse
手軽にDockerでperlの環境をGAEに上げることができました perl以外にもdockerコンテナを設定すれば任意の言語等が動きます ちなみにGKE(GoogleComputeEngine)でもDockerを利用できますが、GAEのほうがかんたんにセットアップをすることができました