著者アーカイブ asaba

asaba 著者:asaba

【androidJava】ads.MobileAdsInitProvider(ADMOB)を使おうとしてはまったこと

MobileAdsInitProviderは、アプリに広告を表示させることができるライブラリで、ブログやショッピングサイトを取り扱うアプリではよくお目にかかります。

今回はこのライブラリが必要になったので導入してみたのですが、下のエラーを出した後に落ちてしまいました。

 


java.lang.RuntimeException: Unable to get provider com.google.android.gms.ads.MobileAdsInitProvider: java.lang.IllegalStateException

 

どうやら、今までのライブラリと違い単にグレイドルにいれただけでは使えないもよう。

調べてみるとMobileAdsInitProviderを使うには、マニフェストへの記述が必要みたいです。アプリケーションタグを閉じる前に

こんな感じでいれてあげれば解決できます。

 


<meta-data
android:name="com.google.android.gms.ads.AD_MANAGER_APP"
android:value="true"/>

 

こちらの記事のurlを参考にしました

グレイドル関係のエラーが出るたびにこのブログに載せている気がします。ですがグレイドル関係の記事は数が少ないのに対して同じよう

なエラーで困っている人が多くいるので少しでも助けになれたらなと思っております。

なお、日本語版の公式ではこの記事の対策方法が書いていないので注意してください。(見るなら英語版で)

asaba 著者:asaba

【ButterKnife】バターナイフは明示的にgradleに書くべき

viewのメソッドを簡潔にかくことが出来るライブラリです。一般的なviewを使いたい時は、findViewByIdで紐付けるだけで使うことが

できますが、これが複数のviewとなると、同じようなコードができてしまいこれでは可読性に欠けてしまいます。

バターナイフは、このダブつくview定義を事前に定義させることでsetContentViewの下からviewの操作を可能にしてくれるので、複数の

ビューを使いたいけど管理が大変なエンジニアさんには重宝されています。こんな感じ↓

class ExampleActivity extends Activity {
@BindView(R.id.title) TextView title;
@BindView(R.id.subtitle) TextView subtitle;
@BindView(R.id.footer) TextView footer;

@Override public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.simple_activity);
ButterKnife.bind(this);
// TODO Use fields...
}
}

 

今自分が開発しているアプリもバターナイフを使って管理しているのですが、グレイドル(また出たなお前)のバージョンを上げたら

やっぱりというべきかエラーに通せんぼされてしまいました。

 


Error:Execution failed for task ':app:javaPreCompileDebug'.
&gt; Annotation processors must be explicitly declared now. The following dependencies on the compile classpath are found to contain annotation processor. Please add them to the annotationProcessor configuration.
- butterknife-6.1.0.jar (com.jakewharton:butterknife:6.1.0)
Alternatively, set android.defaultConfig.javaCompileOptions.annotationProcessorOptions.includeCompileClasspath = true to continue with previous behavior. Note that this option is deprecated and will be removed in the future.
See https://developer.android.com/r/tools/annotation-processor-error-message.html for more details.

訳してみました。

プロセッサは明示的に宣言されなければなりません。次のコンパイルクラスパスへの依存関係に、注釈プロセッサが含まれています。 annotationProcessor設定にそれらを追加してください。

 

どうやらバターナイフはグレイドルのバージョンに合わせてannotationProcessorとして定義しなければいけないみたいです。グレイドル

アップデート前は普通に定義しなくても使えていたのに・・・。

まあもうできたのが6年前なので仕様が変わっていても不思議じゃないですよね。という訳でannotationProcessorにバターナイフを定義してあと残り

なく解決です。

 

annotationProcessor "com.jakewharton:butterknife:6.1.0"
compileOnly "com.jakewharton:butterknife:6.1.0"

このライブラリに変わるものがすでに出てきているか分かりませんが、ライブラリとしては書くことが少なく学習コストも低いので

いとまがあれば使ってみたいと思います。

asaba 著者:asaba

【javaScript fetch】fetchApiで素のデータを送っても何も返ってこない罠にはまったお話

fetchApiは、通信が成功した際にはpromise型で値を返します。が、スコープで囲んで変数に入れて飛ばすと、サーバーに要求した

値が返ってこない事態にハマってしまいました。ajaxだとdata:{“key”,value}みたいにまとめてからプロパティに入れて取ってくることが

できるのですがこっちでは仕様のせいか受け取ってくれません。

調べてみると、そのままbodyに入れるのではなくformDataというfetchから新しく使えるようになったApiを使って送り込むみたいです。

ajaxではdocumentというxmlを取り扱うことができるオブジェクトがあったのですが、こっちではそれが使えないのでこちらを代わりに

使ってくださいということだと思います。

fetchってもうリリースされてから数年経つのですが、国内の記事を探しても全然見つからないのでみんなまだajax使ってるのかなと

思ってしまいます。

ajaxと違いdomをいちいち掘削しないので、通信速度の向上は期待してもいいと思います。ですが、取ってきたxmlから各タグを取り出すメソッド

とかがめんどくさい感じでしたので、そこらが原因で手が出にくいのかなと思いました。前述の処理だけはjqueryに任せて通信だけ

fetchで賄うことができますが、試していないので速さの保証は実装してみないと分からないです。


var formData = new FormData() ;
var id = this.props.match.params.id;
var followMember = window.localStorage.getItem("member_no");
formData.append( "name", "asaba" ) ;
formData.append( "location", "shizuoka" );
formData.append( "gender", "male" );

var url = 'https://hottomotto';
fetch(url,
{ body: formData,
method: "POST",
})
//通常のレスポンスを返す
.then(function (response) {
return response.text();
})
.then(function(text) {
var xml = new DOMParser().parseFromString(text, "text/xml");
console.log(xml);
});


asaba 著者:asaba

Atomを使っていてメニューバーが消えてしまったときの対処法

いつも通りにソースファイルを立ち上げて作業を始めようとしたのですが、何かの拍子でメニューバーがごっそり消えてしまいました。

メニューバーにはファイルを開いたり保存したりなど普段の作業に必須な項目が入っています。さすがにこのままでは気持ち悪いし

効率が落ちるので元に戻そうと決めたのですが、英語表記なのでわかりにくくかなり苦労してしまいました。

方法としましては、まず今回の目的であるメニューバーを手っ取り早く探すためにCtrl + Shift + pコマンドを押してモーダルを出します。

そこで、toggleと検索します。すると、下の画面のようになると思います。

この画面の一番下のWindow Toggle Menu Barという項目をクリックしてみましょう。すると、上からメニューバーがにゅっと出てくる

のが確認できると思います。

何もなければこれでいつも通りにメニューバーを使うことができます。余談ですが、ファイルを開くと、開いたファイルの一覧が

見ることができるバーも同じように復元しようとしたのですがこちらは元に戻りませんでした・・・。

厳密に言うと形だけは直ったのですが、ファイルの一覧が見れなくなってしまい非常に不便な思いをしています。こちらはツイッターやgit

などで情報収集して修正の目途が立てばまたアップしていきたいと思います。

 

asaba 著者:asaba

【javaScript】fetchApiでレスポンスをxmlに変換する方法

ajaxのように手軽に書けつつ早いapiであるfetchApiでxmlを取ってくる方法を探していたのですが、中々見つからなかったので

こんな感じで仕立ててみました。基本的な書き方はJqueryのajaxと変わらないので、ajaxを使ったことのある方ならばすぐに要領を掴め

そうですね。


postfetch() {

//通常のレスポンスを返す
.then(function (response) {
console.log(response);
})
//xmlに変換
//.then(function (response) {
//const text = new DOMParser().parseFromString(response, "text/html")
//console.log(text);
//})
}

レスポンスで受け取ったデータを即座にDOMParserでxmlで変換するだけなので、コンソールで確認できたら後は自由に使うことが
できます。
最後に言うのもアレなのですが、fetchでxmlを扱う場合は、速度にこだわらない場合はajaxでも代用が利きます。

asaba 著者:asaba

【androidJava】BroadcastReceiverを試しに使ってみる

BroadcastReceiverとは、何かのタイミングで端末に特定の処理を通知するときによく使われる便利なライブラリです。

軽い機能であればfirebaseよりも手軽に実装することができるので、息抜きにミニアプリを作ってみたいと思ったときに試してみて

ください。

自分が書いたコードはこんな感じに仕上がりました。まずボタンを押すと、pickerがでてきます。そのpickerを使って時間を指定して、その時間になったらトーストで時間ですよ~とお知らせするシンプルなものになっております。お休みのときにささっと書いたので情報少しが古い&コードが乱雑ですがご容赦くださいまし。

MainActivity↓

</pre>
<pre>public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Button button = findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                TimePicker();
            }
        });
        }
        public void TimePicker(){
            final Calendar calender = Calendar.getInstance();
            int hour = calender.get(Calendar.HOUR_OF_DAY);
            int minute = calender.get(Calendar.MINUTE);

            TimePickerDialog dialog = new TimePickerDialog(
                this,
                new TimePickerDialog.OnTimeSetListener() {
                    @Override
                    public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
                        System.out.println(hourOfDay);
                        calender.setTimeInMillis(System.currentTimeMillis());
                        calender.add(Calendar.SECOND, 5);

                        Intent intent = new Intent(getApplicationContext(),
                                AlarmBroadcastReceiver.class);
                        PendingIntent pending = PendingIntent.getBroadcast(
                                getApplicationContext(), 0, intent, 0);
                        // アラームをセットする
                        AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
                        if (am != null) {
                            am.setExact(AlarmManager.RTC_WAKEUP, calender.getTimeInMillis(), pending);

                            Toast.makeText(getApplicationContext(),
                                    "Set Alarm ", Toast.LENGTH_SHORT).show();
                        }
                    }
                },
                hour,minute,true) ;
            dialog.show();
        }
}</pre>
<pre>

今回のお題であるBroadcastReceiverです。

</pre>
<pre>public class AlarmBroadcastReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        // ここに端末に対してしたい処理を書きます。例ではトーストになっているので変えても構わないです。
        Toast.makeText(context, "Received ", Toast.LENGTH_LONG).show();
    }
}</pre>
<pre>

マニフェストには、パーミッションでWAKE_LOCKを設定しておきます。

その後に、applicationタグのすぐ上に”AlarmBroadcastReceiver”を定義しておきます。これがないとBroadcastReceiverが反応しない

ので忘れないでくださいね。

</pre>
<pre><uses-permission android:name="android.permission.WAKE_LOCK"/></pre>
<pre><application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
    <activity android:name=".MainActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN"/>

            <category android:name="android.intent.category.LAUNCHER"/>
        </intent-filter>
    </activity>
    <receiver android:name=".AlarmBroadcastReceiver"
              android:process=":remote" />
</application></pre>
<pre>

レイアウトのほうはボタンだけなので割愛させていただきました。コードの量も少なめで実装できるので、メンテナンスにも苦労しなさそうです。おすすめです。

asaba 著者:asaba

【androidGradle】minSDKVersionの重要性

前にも似たような話題を振ったような・・・グレイドル系の記事って何回出したか分からないので記憶が曖昧になっております。

問題のエラーはこちらです。↓


Error:Execution failed for task ':processDebugManifest'.
> Manifest merger failed : uses-sdk:minSdkVersion 1 cannot be smaller than version 8 declared in library [com.twitter.sdk.android:twitter:1.4.0] C:\Users\swift0910\.gradle\caches\transforms-1\files-1.1\twitter-1.4.0.aar\54bb48e8e15821fe4455ab493a1ff43e\AndroidManifest.xml as the library might be using APIs not available in 1
Suggestion: use a compatible library with a minSdk of at most 1,
or increase this project's minSdk version to at least 8,
or use tools:overrideLibrary="com.twitter.sdk.android" to force usage (may lead to runtime failures)

 

見かたはシンプルで、今のままではminSdkVersionのレベルが1になっており、バージョン8以上のライブラリを使うことはできませんという感じです。

もしmisSDKVersionが現存のライブラリよりバージョンが低かった場合は、そのライブラリより上の数字で設定するとビルドできると

思うので試してみてください。何も設定していない場合はデフォルトでnullになるので当然ライブラリも使えません。なので

minSDKVersionは、仕様が変わってくるAndroid5.0・API21辺りで設定しておきましょう。

 

参考サイトー>http://y-anz-m.blogspot.com/2015/09/minsdkversion.html

 

asaba 著者:asaba

【npm】cordovaでうまくcordova platforms add browserできない時の対処法

cordova platforms add browserでブラウザを追加しようとしたらAdding browser project…Project already exists! Delete and recreate

で返されてしまいました。あぁ既に追加したブラウザがあったのかと思いcordova platforms rm browserをしたのですが今度はそんなファイルないよ!とエラーを吐き続ける始末・・・。

platformsディレクトリを見ましたが、browserフォルダは存在しなかった。(存在してこのエラーが出るのが普通)ということは

何かの手違いでbrowserフォルダが存在していることになっている。似たようなファイルのplatformフォルダに追加していると思ったの

ですが探してみても該当フォルダはなし。ダメもとでキャッシュを全て消してからビルドしてみようと思いnpm cache verify –forceで

キャッシュを削除したあとにnpm installを実行。その後にさっきのcordova platforms add browserを実行。すると上手くいきました・・・!!

よく考えるとnpm installはただnode_moduleにパッケージをインストールしているだけですよね・・・・今回の事象とは関係ないのでは

と思いましたが、よく考えたらこちらでもパッケージを入れ直せとエラーがでていたので手間が省けました。

コルドバにおいてnpmのパッケージを新しく追加したいけどエラーが出て先に進めないという時はキャッシュを消してみると景色が

晴れてくるかもしれませんね。存在しないファイルも、見えないキャッシュ上で残っている場合があるのでプラットフォームの追加/削除

は計画的に実行するべきですね~。

 

asaba 著者:asaba

【npm】Error: Cannot find module ‘webpack-cliから抜け出す方法

npm uninstall react-tabsをしたら警告が出てしまいました。found 14 vulnerabilities (5 low, 2 moderate, 7 high)と書いてあったので恐らく非推奨のパッケージだと思いすぐにnpm iでまとめてインストールし直したのですが、インストールしたのにも関わらず存在しないことになっている・・・。よく見ると、npm auditを入力して脆弱性のあるパッケージを調査しろとメッセージがあったので急いでリトライをしました。lowが脆弱性が低くてhighが危険ですよってことですね。vulnerabilitiesと書いてあったのに見落としてしまいました・・・。

auditとは、npm installでnode_modules配下にインストールしたpackageの脆弱性をチェックしてくれるプロパティです。元々liftsecurity.ioという企業の技術でした。が、セキュリティノウハウをnpm側が取得したことによりふろんとpackageの脆弱性のチェックが手軽にできるようになりました。

npm auditで検知されたパッケージは、脆弱性を含んでいると見なされ、これらを解決させない限りはビルドを通すことができない仕組みになっています。

npm auditをして下にスクロールしていくと、画像のようにnpm install 〇〇をインストールしてねというメッセージが表示されます。

このメッセージに従ってnpm install 〇〇を追加していけばhighやmoderateの数が減っていくので、0になったらまたビルドをして通るかどうか確認してみてください。流れとしては、npm run buildをするー>found 〇〇 vulnerabilities(4 low,4,moderate,10high)のようにメッセージが出るー>npm install 〇〇コマンドでメッセージに従ってパッケージをいれていくー>解決

ここで脆弱性について問いただされるとは思いませんでした。ですが直す個所は決まっているのでさくっと修正してしまいましょう。

asaba 著者:asaba

【androidJava】LocationManagerで現在位置が取れない時の処理

現在地を取得したい時はLocationManagerで取ることができますが、gpsの情報が不正確だったりgpsの許可が下りていなかった場合は nullで帰ってきてしまい正しい位置情報を取得することができません。しのぐ方法はいくつかあるのですが、自分はまず最初に位置情報を 取得させ、nullだった場合はLocationManager.NETWORK_PROVIDER(基地局からの現在位置の情報)を使いネットワークから取得 させています。

最初からgpsの設定していない場合はSettings.ACTION_LOCATION_SOURCE_SETTINGSを使ってgpsを使うように促して設定ページに移動 させます。これで最小限の設定が出来るので、後は端末のバージョンと相談しながら必要なパーミッションや機能をつければ実装完了です。


Location location = mLocationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);

if (location != null) {

  System.out.println(location + "there");

  onLocationChanged(location);

  GeoPoint homeposition = new GeoPoint(location.getLatitude(),location.getLongitude());

  mapController.setCenter(homeposition);

} else { location = mLocationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);

  System.out.println(location+ "null");

  onLocationChanged(location);

  GeoPoint homeposition = new GeoPoint(location.getLatitude(), location.getLongitude());

  mapController.setCenter(homeposition);

}
// GPSを設定するように促す
Intent settingsIntent =
        new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivity(settingsIntent);