忘れてしまったAndroidの署名情報は見つかるかもしれない
Androidのアプリの署名に使う情報を忘れてしまうことが、稀にあります。
やってはいけないことですが、稀にあります。
別PCで作業してていつもMaster Passwordに任せっきりだったりとか、久しぶりに更新をかけようとしたアプリで起きたりします。
同じ署名のkeystoreファイルが使えないとなると、別アプリ扱いとなるので同じアプリのストアの更新はできなくなります。なので、別アプリとしてストアに上げ直すことになります。
もちろんそれは意図した場合を除いては避けたいことなので、なんとか署名情報を思い出します。
これが助けになるかもしれないし、助けにならないかもしれません。 藁にもすがる思いでこの投稿をみつけた方には一度試してもらいたいと思います。
keystoreファイルをなくしてしまった方には今回の方法は使えません。教訓として同じことを繰り返さないようにしましょう。
署名情報
それぞれをなんと呼ぶのかわかりにくいと思ったので、この投稿では次のように扱います。
画像のまんまですが、
1に入力するものを Key store password
2に入力するものを Key alias
3に入力するものを Key password
とします。
プロジェクトルートから探る
アプリのプロジェクトルートに.gradle
という隠しフォルダがあると思います。
その中の、Gradleのバージョン/taskArtifacts/taskArtifacts.bin
というファイルを、エディターなどで無理やり開きます。
signingConfig.storePassword
, signingConfig.keyAlias
あたりで検索すると、
Key store password
とKey alias
が見つかります。私の環境では、Key password
は見つかりませんでした。
Key password
は次のツールを使えば探すことができます。
力技をサポートしてくれるツールです。
Android-keystore-password-recover by MaxCamillo
パスワードに使われていそうな文字列にあたりがある場合は見つけられる確率は少しあると思いますが、非常に時間がかかります。
上のツールを使うと、Key alias
はすぐに表示してくれます。
Android Studioのログから探る
~/Library/Logs/
に、いろんなアプリケーションのログがあります。AndroidStudio
のものは複数見つかると思いますが、Releaseビルドを成功させたバージョンのログをみます。idea.log
というファイルをエディターで開きます。こちらもidea.log.1
など複数あると思いますが、大まかに日ごとに分かれているので、作成日などをヒントにあたりをつけましょう。
android.injected.signing.store
と検索すると、近くに見つかると思います。GUI上で****と入力された履歴の下に、実際に入力されていた文字列がそのまま表示されています。
こちらは、Key store password
, Key alias
, Key password
すべてが見つかります。
まとめ
keystoreファイルと同じく、それに使う署名情報もバックアップが取れる形で保存しておきましょう。
GUIでapkを生成するのではなく、CLIで生成できるようにしておき、人力による入力漏れを無くすのも効果的です。
Please Advice Needed, Lost KeyStore password / StackOverFlow
android KeystorePassとaliasPassを忘れた時の対処法 / Game Factory
jsoupのデフォルトのUser-Agentはなんなのか。
jsoup
JavaでHTMLをいい感じにParseできる便利なライブラリです。 WebページにアクセスしてHTMLを取得し、それを加工することでWebページ内のコンテンツを簡単に取得することができます。
スクレイピング先が、User-Agent(UA)によって表示を変えている場合、それに応じてjsoupのUAを変更しなければ、思っていたコンテンツが取得できない場合があります。
User-Agentの設定
Connection#userAgent(String)
で設定できます。次のようにすることで設定されたUAを確認できます。
String url = "http://www.useragentstring.com/"; Connection con = Jsoup.connect(url); con.userAgent("Mozilla/5.0 (Windows NT 6.1; WOW64; rv:23.0) Gecko/20100101 Firefox/23.0"); Doc doc = con.get(); doc.getElementById("uas_textfeld").val());
メソッドで指定した通り、
Mozilla/5.0 (Windows NT 6.1; WOW64; rv:23.0) Gecko/20100101 Firefox/23.0
が設定されているのがわかります。
未設定時
未設定のときにどうなるのか調べてみました。 Androidのエミュレータで前述のようにし、UAの設定をしないと次のようになりました。
- Genymotion
Dalvik/2.1.0 (Linux; U; Android 5.0; Nexus 5 - 5.0.0 - API 21 - 1080x1920_1 Build/LRX21M)
どこで誰が設定しているんだろうと思い、jsoupのコードを見ていたのですが、AndroidのSDKHttpURLConnection
が使われているところで詰んでしまいました。
frameworkのところまで調べていくと、 RuntimeInit
というクラスで、デフォルトのUAに使われる値が生成されていました。
- RuntimeInit.java
/** * Returns an HTTP user agent of the form * "Dalvik/1.1.0 (Linux; U; Android Eclair Build/MASTER)". */ private static String getDefaultUserAgent() { StringBuilder result = new StringBuilder(64); result.append("Dalvik/"); result.append(System.getProperty("java.vm.version")); // such as 1.1.0 result.append(" (Linux; U; Android "); String version = Build.VERSION.RELEASE; // "1.0" or "3.4b5" result.append(version.length() > 0 ? version : "1.0"); // add the model for the release build if ("REL".equals(Build.VERSION.CODENAME)) { String model = Build.MODEL; if (model.length() > 0) { result.append("; "); result.append(model); } } String id = Build.ID; // "MASTER" or "M4-rc20" if (id.length() > 0) { result.append(" Build/"); result.append(id); } result.append(")"); return result.toString(); }
他のやり方ではどのように表示されるのか、いろんな方法でUAが確認できるサイトにアクセスしてみました。
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.110 Safari/537.36
Mozilla/5.0 (Linux; Android 6.0.1; Nexus 6 Build/MMB29V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.105 Mobile Safari/537.36
curl/7.43.0
- httpie
HTTPie/0.8.0
httpieが一番わかりやすく、ソースを見ると、
... DEFAULT_UA = 'HTTPie/%s' % __version__ ... def get_default_headers(args): default_headers = { 'User-Agent': DEFAULT_UA } ...
となっていたので、アクセスするプログラムが決めているのだとわかりました。 curlやブラウザなどは中がわからなかったのですが、おそらく内部で同じように自分のUAを設定しているのだと思います。
間接的で、直接はわかっていないのですが、少しスッキリしました。
jsoupのデフォルトのUA
Androidから使うときは、Android SDKのHttpURLConnection
のデフォルトのUAが適応され、Android端末のUAとなります。
参考
jsoup: Java HTML Parser / jsoup
JSoup UserAgent, how to set it right? / StackOverFlow
User Agent String.Com / UserAgentString.com
What's the default Jsoup User Agent string? / StackOverFlow
Instagramのユーザページと詳細ページへ暗黙的Intentで遷移する。
普段アプリで表示しているであろうページに、ブラウザで表示する場合があります。
ブラウザアプリを作っていて、何もしないままだとWebページが表示してしまうので、普段表示している方であるアプリへ遷移させます。
ユーザページと詳細ページを表示する時に、Instagramのアプリで表示できるようにします。
ユーザページ
詳細ページ
検索ページ
Instagramがリダイレクトを行い、ログインなどを除けば最終的に上のURLになります。 検索ページはログインしていないとうまくリダイレクトされない場合があります。
ユーザページはそのままのURLだと、Instagramアプリが反応してくれません。
ユーザページをInstagramアプリで開くときは、パスに_u
を挟む必要があります。
つまり、ユーザページは次のようになります。
コード
this.packageName()
にはcom.instagram.android
this.url()
にはhttps://www.instagram.com/
が入っています。
public void instagram(Activity activity, String url) throws ActivityNotFoundException { Intent toInstagram = new Intent(); toInstagram.setAction(Intent.ACTION_VIEW); toInstagram.setPackage(this.packageName()); Uri uri = Uri.parse(url); List<String> paths =uri.getPathSegments(); switch (paths.size()) { case 1: String profile = this.url()+ "_u/" + paths.get(0); toInstagram.setData(Uri.parse(profile)); break; default: toInstagram.setData(uri); break; } activity.startActivity(toInstagram); }
URLのpathを取得して、一つしかpathがない場合にURLをInstagramアプリが反応できるユーザページに置き換えています。
このコードだと、URLが
https://www.instagram.com/
https://www.instagram.com/accounts/login/?next=/explore/
などの場合にActivityNotfoundException
を投げるので適切にハンドリングしてください。
また、https://www.instagram.com/explore/
のときは、explore
という存在しないユーザページに遷移するので、特殊な処理を入れてもいいかもしれません。
注意
Instagramのバージョンは7.20.0
, 検証した日は2016/4/10
のものですので、仕様変更やアプリのバージョンによっては思った通りに動かない場合もあるのでご了承ください。
以前紹介した方法の方が、変更には強いです。
素直なURLでInstagramのアプリで開けないということは、開いて欲しくない、もしくは無くしていく方針なのかもしれません。
以上。
参考
Intent to open Instagram user profile on Android / StackOverFlow