読者です 読者をやめる 読者になる 読者になる

aswww log

Webエンジニアの技術録。Linuxとかウェブ制作・ソフト開発とか

AdMob実装で大いにハマった備忘録

AndroidAVD AndroidStudio AdMob Java

AdMobに関係あるのからないのまで。
何日もハマった上にいろんな設定を色々いじって何やったか忘れてしまったので、雑な感じですが備忘録的な感じでなにとぞ。

1).AdMobの実装を一通り終えてbuildしようとしたら以下のエラーが出た。

java.lang.ClassNotFoundException: Didn't find class "com.google.firebase.provider.FirebaseInitProvider" on path: DexPathList[[dex file "/data/data/[パッケージ名].debug/files/instant-run/dex/slice-com.google.firebase-firebase-iid-9.6.1_17f9eed5e9c1fe52c568855cb2090871a90f4031-classes.dex", dex file "/data/data/[パッケージ名].debug/files/instant-run/dex/slice-com.google.android.gms-play-services-ads-9.6.1_1aa317fdb75c8fb2b8ae8bfdfb55c4013d6bc40a-classes.dex"],nativeLibraryDirectories=[/vendor/lib64, /system/lib64, /vendor/lib64, /system/lib64]]

よくわからないけどDexファイルがなんとか?
メモによると以下のとおりMultiDexを設定ファイルに書き加えたらエラー解消したらしい。

build.gradle

android {
    compileSdkVersion 21
    buildToolsVersion "21.1.0"

    defaultConfig {
        ...
        minSdkVersion 14
        targetSdkVersion 21
        ...

        // Enabling multidex support.
        multiDexEnabled true
    }
    ...
dependencies {
  compile 'com.android.support:multidex:1.0.0'
}


AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.android.multidex.myapplication">
    <application
・・・
        android:name="android.support.multidex.MultiDexApplication"
・・・
    >

参考:
http://qiita.com/nshmura/items/c7e8faa05c5ad4a66b3d#_reference-91cadc916c4dc5fe7d87
https://developer.android.com/studio/build/multidex.html?hl=ja#dev-build


2.)メソッド数が64k(65536)を超えるとビルドエラーになる

具体的なログはロストしてしまったが、65536という数字が出たらきっとこのエラー。
以下のとおり対処を調べた。このうちの1,2,4を実施。
どれかでエラーが解消された。(4かな)

[対処1]. メソッド数の確認
以下、リンク先より抜粋

http://qiita.com/konifar/items/d98c78facbaae63badca
実際どのくらいのメソッド数なのかを確認します。dex-method-countというツールを使うと、簡単にapkのメソッド数を確認できます。

$ git clone https://github.com/mihaip/dex-method-counts.git
$ ./gradlew assemble # ビルド
$ ./dex-method-counts path/to/app.apk # or .zip or .dex or directory
こんな感じで出力されます。まずは出力してみると、節約できるところが見つかるかもしれません。
Read in 60366 method IDs.
<root>: 60366
    : 8
    android: 10815
        accessibilityservice: 6
        accounts: 8
        animation: 2
        app: 351
        bluetooth: 2
        content: 303

...(略)...

    com: 39448

...(略)...

        google: 18513
            ads: 165
                mediation: 134
                    admob: 24
                    customevent: 40
                    jsadapter: 38

[対処2].google playSDKのインストールはやめる
以下、リンク先より抜粋
http://qiita.com/garlicG/items/fac54cf96d66cfcb4b8d

play-service全体のライブラリは少し巨大なので、AdMobだけが必要であれば以下のような記述でおKです。
build.gradle(AndroidStudio利用時)

compile 'com.google.android.gms:play-services-ads:7.3.0'

[対処3].ProGuardを導入する
もうしてました。(デフォルトでそうなってる?)

[対処4]. gradleでjumboModeオプションを有効にする
また以下のリンク先のとおりに修正。
http://qiita.com/konifar/items/d98c78facbaae63badca


3).support-appcompat-v7のFile size 0 byteエラー
buildも通るようになったので、Android Studioからエミュレータ(ADV)起動して確認しようとしたらエラーった。

10-28 22:38:19.568 2306-2306/[パッケージ名].debug E/System: Unable to load dex file: /data/data/[パッケージ名].debug/files/instant-run/dex/slice-com.android.support-appcompat-v7-23.3.0_e72ec210e17d195522eaa56b35521a9733e3c94a-classes.dex
10-28 22:38:19.569 2306-2306/[パッケージ名].debug E/System: java.io.IOException: Failure to verify dex file '/data/data/[パッケージ名].debug/files/instant-run/dex/slice-com.android.support-appcompat-v7-23.3.0_e72ec210e17d195522eaa56b35521a9733e3c94a-classes.dex': Bad file size (32768, expected 550080d)
                                                                         at dalvik.system.DexFile.openDexFileNative(Native Method)


                                                                      Caused by: java.io.IOException: Failed to find dex file 'x-classes.dex' in oat location 'x': Failed to find existing oat file at x: File size of 0 bytes not large enough to contain ELF header of 52 bytes: '/data/data/[パッケージ名].debug/cache/slice-com.android.support-appcompat-v7-23.3.0_e72ec210e17d195522eaa56b35521a9733e3c94a-classes.dex'
	

原因不明。Android Studioの設定から見なおしたけど一向に治らなかった。
AVDを新規作成したらこのエラーが出なくなった。(ソースとかのせいとかじゃなかった。)
こんなのに2日も振り回されて私ってホント馬鹿。

4.)AdMobの実装エラー
やっとまともに起動したAVDで出たエラー。

java.lang.IllegalStateException: The ad size can only be set once on

ad size がなんたら。
以下のとおり、content_main.xml(active_main.xml)とソース内両方でAdsizeを指定したのがまずかった。

content_main.xml

    <com.google.android.gms.ads.AdView
	・・・
        ads:adSize="SMART_BANNER" //これと
	・・・

MainActivity.java

        MobileAds.initialize(this, getString(R.string.banner_ad_unit_id));
        adView=(AdView) findViewById(R.id.adView);
        adView.setAdSize(AdSize.SMART_BANNER);   //これ
	・・・

ソースの方をコメントアウトしたら表示できたよ!
http://stackoverflow.com/questions/23337802/ad-size-and-ad-unit-id-must-be-set-before-loadad-is-called

広告表示でここまで大変なんだなー。AdMob仕様変わらないでほしいな。。。もうやりたくない。。。

AndoroidアプリにAdMobバナー広告を設定するときにハマった

andoroidアプリ(andoroidSDK) AndroidStudio

AdMobを設定するために以下のサイトを参考にbuild.gradleを実装したり、google-services.jsonを設置したりした。

https://firebase.google.com/docs/admob/android/quick-start?hl=ja

すると例のR.が読めなくなるエラーとともに以下のエラーが出力された。

エラー :Execution failed for task ':app:processDebugGoogleServices'. > No matching client found for package name '[パッケージ名].debug'

原因は先日追加した開発用モジュールdebugが原因らしい。
そこで、以下のとおり修正したgoogle-services.jsonを/debug/配下に設置した。

  "client": [
    {
      "client_info": {
        "mobilesdk_app_id": "1:209109689792:android:463e3def0de05f38",
        "android_client_info": {
          "package_name": "[パッケージ名].debug"
        }

するとR.が読み込めなくなる例のエラーは解消された。

参考:
http://stackoverflow.com/questions/34990479/no-matching-client-found-for-package-name-google-analytics-multiple-productf

WebView内で通信エラーでエラー画面表示さす

andoroidアプリ(andoroidSDK) AndroidStudio Java Gradle

WebView内で通信エラーになった場合(net::ERR_CONNECTION_TIMED_OUT)、エラーページを表示さすようにハンドリング
#WebViewClient生成時に定義してあげる

○準備(既にassetsディレクトリがある場合は不要)
HTMLを置くassetsディレクトリを作成する。
AndroidStudioのプロジェクトのappを右クリック→[新規]→[New]→[Folder]→[Assets Folder]を選択。
app/src/main/asestsディレクトリが作成される。
また、build.gradleに以下のとおり追記する。(自動挿入されることもあるので、既にあったら編集不要)

android {
    sourceSets{
        main{
            assets.srcDirs=["src/main/assets"]
        }
    }
・
・
・

app/src/main/asestsにエラー画面のHTML(network_error.html)を配置して準備終了

○WebViewクラスにコーディング

次のとおりWebView生成時にオーバーラードして実装する。

WebView webView = (WebView) findViewById(R.id.webView);
webView.setWebViewClient(new WebViewClient() {
    @Override
    public void onReceivedError(WebView webview, int errorCode, String description, String failingUrl) {
        if(errorCode < 0){
            // 自作のエラーページを表示
            webView.loadUrl(“file:///android_asset/network_error.html”);
        }
    }

参考URL
http://www.hangout.co.jp/blog/archives/148
http://stackoverflow.com/questions/4997677/android-webview-onreceivederror
http://growsic.com/blog/androidlocalhtml/

Andoridアプリの開発と本番の取扱をGradleでどうにかする

andoroidアプリ(andoroidSDK)

参考にしたサイトは以下。
https://firespeed.org/diary.php?diary=kenz-1824

Andoroidアプリ界隈で開発と本番は

開発=debug、本番=release

っぽいので以下はそれに則って記載する。

○一つの端末にデバッグバージョンアプリとリリースバージョンアプリを共存させたい
Module内にあるbuild.gradleを以下のとおり修正する。

    buildTypes {
        debug{
            applicationIdSuffix ".debug"
        }
        release {
		・
		・
		・

ビルド時にデバッグバージョンアプリの時は、アプリIDに.debugがつくので、アプリバージョンIDがリリースバージョンと被らない=共存できる

○開発と本番で設定ファイルを切り替えたい。
以下のとおり設定ファイルを切り替えられる。

  • 本番用定数

/src/main/res/values/strings.xml

<resources>
    <string name="app_name">Sample application</string>
    <string name="url">http://gati.net</string>
</resources>

/src/debug/res/values/strings.xml

<resources>
    <string name="url">http://uso.net</string>
</resources>

Javaソースコード内で参照する際は普通にR.string.urlでOK。

WEBアプリのようにENVで切り替えられないのは少し不便。

MacVimでfileformat=unixのファイルで改行を変換するには\n

GVIM Mac OSX 雑記

WindowsGVimだと例えばfileformat=unixのファイルで改行を空白に変換したいときは

:%s/^M/ /g

もしくは

%s/¥(半角円マーク)n/ /g

でできた。
自分の今のMacOSX上にインストールしたMacVimの場合は

%s/\(半角バックスラッシュ)n//g

※\(半角バックスラッシュ)=option+¥(円マーク)

じゃないと変換できなかった。
他のサイトの記事によると¥nで置換できている人もいるので同じMacでもバージョンとか環境によって違うのかも?

Dockerで共有ディレクトリのパーティションを変更する方法

Docker Mac OSX 環境構築

Docker上で以下を行っても反応無し。パーミッションも変わらない。

chmod -R 777 cache

共有ディレクトリはローカル側のディレクトリのパーミッションもそのまま共有されるようなので、ローカル側を以下のとおり変更

chmod -R 777 cache

dockerにsshしてみると777になっているはず

Stringの文字列中に複数個の文字列が一個でも含まれている場合、continueする

PHP 雑記

Q.$taisyoStringの文字列中に"ダメ"または"いらない"文字が含まれている場合、continueするphpプログラムを書きなさい。

A.
phpの文字列検出系関数の中で一番処理効率がいいのはstrpos関数らしいのでできるだけそれを使う。

  • 回答1.一番シンプルif文だけ
const DAME_MOJI="ダメ";
const IRANAI_MOJI="いらない"

if(strpos($taisyoString, self::DAME_MOJI) !== false or strpos($taisyoString, self::IRANAI_MOJI) !== false){
    continue;
}
  • 回答2.php5.6からconstでarray使えるようになったらしいからarrayで定義
const HUYOU_MOJIS = array("ダメ","いらない");

foreach(self::HUYOU_MOJIS as $huyouMoji){
   if(strpos($taisyoString, $huyouMoji) !== false){
        continue 2;
    }
}
  • 回答3.preg_matchで判断。一番短くてすむ
const HUYOU_MOJIS = "ダメ|いらない";

if(preg_match($taisyoString, self::HUYOU_MOJIS) === 0){
    continue;
}
//もちろん3項演算子でも可

and etc...