2023年10月6日金曜日

Android ファイルアクセスが拒否されるせいでビルドが全然通らない問題と解決方法を紹介

どうも。どっことです。今回ですが、ここ2,3年、AndroidStudioでのビルドが20回に1回程度しか成功しなくなり開発モチベが著しく低下していたが、ついにその問題を解決することができたので備忘録として記載します。

現象と根本の原因

How to solve this error app:packageDebug FAILED

A failure occurred while executing com.android.build.gradle.tasks.PackageAndroidArtifact$IncrementalSplitterRunnable java.io.FileNotFoundException: C:\Users\HP\AndroidStudioProjects\Chatter\app\build\intermediates\incremental\packageDebug\tmp\debug\zip-cache\androidResources (Access is denied)

このエラーが解決できずに、この2,3年本当に困っていました。「はー。もうダルイし、Macでも買うか。」とここぞとばかりに物欲全開に検討していました。

そして解決へ

そんなこんなでPCのリプレースも検討していたのですが、上記のページをみていくとコメント欄に以下の記述がありました。

The actual problem is that your anti-virus is preventing the access to the files. Make the Android Studio application as trusted application(recommended) or try turning off your antivirus.(おまえのPCのウイルス対策ソフト、ちゃんと設定しとるんか?AndroidStudioを信頼できるアプリに設定しとるか?あとは試しにソフトの機能をOFFにしてビルドしてみ?)

私「...」
私「...」
私「それだわー」

ウイルス対策ソフトの機能をOFFにしてビルドしたところ、何事もなかったかのようにビルドが成功しました。

ウイルス対策ソフトをインストールしてからすぐのAndroid Studio起動で「なんか知らんツールがアクセスしたがってるけどええか?」という警告が表示されていたので脳死でOKを設定していましたが、それだけじゃ足りなかったようです。公式サイト(参考に記載)にも「ビルドのパフォーマンスが著しく低下するで?ちゃんと設定するんやで?」というアナウンスがされていました。

原因が分かったので、ウイルス対策ソフトの設定に対象外フォルダを設定することで無事に解決しました。本当に良かった。

最後に

私のPCではソースネクスト社のウイルスセキュリティソフトをインストールしています。絶対にツッコませない。このソフトでの対象外フォルダ指定手順を紹介して終了したいと思います。

  1. ウイルスセキュリティソフト のホーム画面を開く
  2. 設定 > ウイルス・スパイウェア対策 >設定(セクションタイトル下部に導線有)
  3. ウイルス自動検知タブ > 検査したくないファイル、フォルダを指定する
  4. ファイルやフォルダを追加で検査対象外のフォルダを追加する。以下にチェックを入れる。
    • ウイルス自動検知の対象にしない
    • サブフォルダも含む

参考

2023年10月4日水曜日

Android gradleのキャッシュを削除するコマンドを紹介

どうも。どっことです。今回は、毎回忘れるGradleのキャッシュ削除のコマンドを備忘録として紹介します。

gradleのキャッシュを削除するコマンド

早速ですが、コマンドを載せます。

rm -rf ~/.gradle/cashes

~/となっていることを見ても分かる通り、削除するディレクトリはアプリプロジェクトにあるディレクトリではなくユーザディレクトリにあるキャッシュのディレクトリになります。これを実行すると、次回ビルドは非常に時間がかかるのが見込まれますので、「PCやプロジェクトがおかしいな?」と思った時にやるのがちょうどいいと思います。

ちなみに .gradle フォルダを削除しても、Gradle がビルドする時に再構築してくれるらしいので気にすることは全くありません。

独り言

ただ、最近AndroidStudioのビルドが全く通らない。

C:\Users\XXXXX\Documents\project\sampleProject\app\build\intermediates\incremental\packageDebug\tmp\debug\zip-cache\androidResources (アクセスが拒否されました。)

いったいなんだってばよ。

追記。なんか解決した。新規に記事にした。

2023年9月1日金曜日

Python HTTP通信で情報取得

どうも。どっことです。通信取得する処理について紹介します。今回はPythonでサーバ通信・情報取得する処理です。

説明

さっそくサンプルを載せます。pythonをインストールできていれば、以下でOKです。

import sys
import json 
import urllib.request

# 取得したい情報のURL
url = "取得したい情報のURL"
header = {
  # 例えば header に仕込む key-value
  'key': 'value', 
  # 例えば header に仕込む 認証情報
  'Authorization': 'Bearer <YOUR TOKEN>'
}
req = urllib.request.Request(url, headers = header)

with urllib.request.urlopen(req) as res:
    body = json.load(res)
    print(body)

Android/iOSといったネイティブアプリのように、非同期処理などのことを考えなくていいので、とても簡単ですね(逆に不安になる)。巷ではrequestsといった、通信処理を簡単に実装できるようなライブラリはごまんとあるようですが、今回は「可能な限り簡単に使えるスクリプト」を意識したいので、標準のurllibを使いました。

参考

2023年8月10日木曜日

Android 通知チャンネルの設定画面を表示する実装方法について解説

どうも。どっことです。今回は、通知チャンネルの設定画面を表示するための実装方法について解説します。

通知チャンネルの設定画面を表示する

Android O から追加された通知チャンネルですが、アプリからは追加・削除以外は通知チャンネルの設定値を修正・変更することができません。その代わりに端末の設定画面に遷移させるための導線を具備することで、ユーザに通知チャンネルまで簡単にアクセスできるようにしてあげましょう。

実装方法

アプリが追加したチャンネルの設定画面に遷移する方法は以下となります。

val intent = Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS)
intent.putExtra(Settings.EXTRA_CHANNEL_ID, channelId)
startActivity(intent)

通常のstartActivityと同様に、必要なActionやパラメーターを設定することで通知チャンネルの設定画面に遷移することができます。

まとめ

今回は、通知チャンネルの設定画面を表示するための実装方法について解説しました。このブログでは、アプリで通知を表示するために必要な実装として他にも投稿しているので、もしよろしければそちらも参考にしていただけると幸いです。

参考

2023年8月9日水曜日

Android AndroidPでhttp通信に失敗する問題

targetSDKVersionをAndroidP以上に設定すると、セキュリティの問題でアプリでのhttp通信が失敗する。AndroidManifest.xml のapplicationタグに以下の属性を追加する。

<application
    ....
    android:usesCleartextTraffic="true">
</application>

開発段階ではローカル環境にサーバ立ててそこにスタブデータを置いて動作確認することが多いが、本番環境では回避すべき設定なので、debug/releaseでAndroidManifest.xmlを分けるなど、きちんと切り分けること。

2023年8月8日火曜日

HTML/CSS マウスオーバーしたときの表示をカスタマイズする

マウスオーバーしたときに表示を切り替えたいときは、CSSに疑似クラスを指定する。

a:hover {
  マウスオーバー中に表示したい内容
}

この指定を複数の要素に指定することで、例えばテキストやイメージの表示切替などもできる。

a:hover {
  マウスオーバー中に表示したい内容
}
.a-covered:hover {
  マウスオーバー中に表示したい内容
}

マウスオーバー以外にも疑似クラスの指定により表示を変えられるものは以下。

  • link:御訪問リンク
  • visited:訪問済みリンク
  • hover : マウスオーバー
  • active : リンククリック中

参考

2023年8月7日月曜日

Android Parcelableを実装する方法を解説

どうも。どっことです。今回はParcelableの実装方法について解説します。

Parcelableを実装する

ActivityFragmentなどの画面間におけるデータ受け渡しはアプリ全体の動きを考える上でなくてはならない処理ですが、自前で用意したデータクラスはそのままだとBundleに乗せることができません。

それではどうするかというと、そのデータクラスにParcelableSerializableを実装します。取り出すときにキャストが必要にはなるが、これでBundleに乗せることができるようになり画面間のデータ受け渡しができるようになります。

今回はその呪文の如きParcelableのインターフェース群の実装について、説明します。

実装

必要な実装ですが、データクラスに以下のクラス・メソッドを実装します。

  • Parcelableを実装する
  • describeContentsを実装する
  • 引数がParcelのコンストラクタを実装する
  • writeToParcel()を実装する
  • CREATOR : Parcelable.Creatorを実装する

サンプルとしてItemクラスにParcelableを実装する場合は以下となります。

data class Item(
    var title: String,
    var description: String,
) : Parcelable {
    constructor(parcel: Parcel) : this(
        parcel.readString()!!,
        parcel.readString()!!
    )

    override fun writeToParcel(parcel: Parcel, flags: Int) {
        parcel.writeString(title)
        parcel.writeString(description)
    }

    override fun describeContents(): Int {
        return 0
    }

    companion object CREATOR : Parcelable.Creator<Item> {
        override fun createFromParcel(parcel: Parcel): Item {
            return Item(parcel)
        }

        override fun newArray(size: Int): Array<Item?> {
            return arrayOfNulls(size)
        }
    }
}

あとは実装したデータクラスのオブジェクトをBundle#putParcelable()Bundleに詰め

val bundle = Bundle().apply {
    putSerializable("適当なキー", item)
}

Bundle#getParcelable()Bundleから取り出すことで

val item = bundle.getParcelable("適当なキー", Item::class.java)

画面間でデータクラスをやり取りすることができます。

ここまで書いててですが…

Percelableをいい感じに実装してくれるアノテーションがあると公式サイトが謳っていました。

Parcelable 実装生成ツール

アノテーション付けるだけで上記の面倒臭い実装をしなくてよくなるなんて、なんて素晴らしいんだ!!ありがとうGoogle様!!!

まとめ

今回はParcelableの実装方法について解説しました。ボイラープレートなParcelableの実装ですが、すでに自動生成してくれるツールがあるので、そちらを使う方が無難でしょう。今回の紹介した内容がほぼ無用なものになってしまいますが、必要なものが簡単に実装できることの方が重要だと思うので、まあ仕方ないでしょう笑

2023年8月3日木曜日

iOS TextFieldのキーボードを閉じる実装方法を解説

どうも。どっことです。今回はiOSでのキーボードを閉じる実装について解説します。

解説

iOSではアプリからキーボードを閉じるのは非常に簡単で、UITextField#endEditing(true)を呼び出すだけでOKです。

@IBOutlet weak var textField: UITextField!

func closeKeyboard() {
    // キーボードを閉じる
    textField.endEditing(true)
}

AndroidではInputManagerにアクセスしたり必要な情報を渡したりで面倒臭いのに、iOSはとにかくシンプルで羨ましいですね。

参考

2023年8月1日火曜日

CI/CD Bitriseでaabを生成する

前回の続きです。今回はリリースファイルを作るための各種設定を備忘録として記載したいと思います。

リリースファイル(aab)を生成するための設定

とはいえ、基本は以下の手順通りに設定すればOK。日本語ページはなかなか残念なことになっているので、英語ページをベースに作業したほうが結果的にストレスが少なくて済む。

Generating and deploying Android app bundles

ただし、少しだけハマりポイントがあるので注意が必要。ハマったポイントは以下。

gradlewのパス

唯一納得いかなかったハマりポイント。gradlewのパスがデフォルトのままだとビルドが通らない。

上記ページの手順で追加した「Gradle Runner」のステップ内にあるInput variables>gradlew file pathの項目に以下を設定する。

./gradlew

最小構成のプロジェクトなら、これだけ手直しすればビルドが通ってaabができるはず。

(追記)最新の設定だと、「Gradle Runner」を追加せずともaabファイルを生成できる模様...何のために試行錯誤したのか。。。

google-services.jsonの準備

google-services.jsonはFirebaseの機能を使うためにアプリに組み込む設定ファイル。秘匿情報が含まれるため、原則Gitには登録しない。しかし、Gitに登録しないとBitriseでビルドする時にこの設定ファイルが無いせいでビルドに失敗する。

この矛盾を解消するために、Bitriseに用意されているテキスト生成のステップを利用する。ざっくり書くと、以下。

  1. ファイルの中身をまるっとコピーする。
  2. コピーしたテキストをBitriseの定数として保存。
    • 定数の名前は適当でOK。例えば直感的にGOOGLE_SERVICES_JSONとか。
  3. テキストファイル生成のステップ(Generate Text File)を追加。
    • 定数として定義したテキストを使って、google-services.jsonファイルとして生成する。

「テキストファイルを生成する」ステップが用意されているのが、直感的で非常にわかりやすい。

センシティブな情報の設定

おそらくAndroidアプリ開発者ならほとんどの人がハマるポイント。build.gradleBuildConfigFieldを定義する際、ダブルクォーテーションを定義に含めないと、生成されるBuildConfigでいい感じに定義できない問題。これがBitriseでも(というより環境変数として定義する場合でも)同様に発生する。

何も考えないならbuild.gradle内で

buildConfigField "String", "AD_UNIT_ID", "\"広告ID\""

って形で定義すれば問題ない。

しかし、これを(センシティブな情報だから、外部に設定+それを参照するような形とするために)環境変数などに設定しそれを参照する形で

buildConfigField "String", "AD_UNIT_ID", System.getEnv(定義したキー)

って書くと残念ながらビルドに失敗する。設定値側(環境変数)にダブルクォーテーションを含めて定義するか、参照時に文字テンプレートを使うことで解消できる。

AndroidManifest.xmlも参照する必要が出てくるはずなので、文字テンプレートを使った方が無難。つまり以下。

buildConfigField "String", "AD_UNIT_ID", "${System.getEnv(定義したキー)}"

参考

2023年7月31日月曜日

CI/CD 各種サービスを比較し使うものを選定する

この前の続き。CI/CD環境の構築に向けて、良さそうなサービスを探す。

CI/CDと聞いて真っ先に思いつくのはJenkinsだが、オンデマンドに構築できるほど私のプライベート環境は充実していないので却下。外部サービスで検討する。

調査・知っている範囲で、以下のサービスをピックアップした。

  • Github Action
  • Circle CI
  • TravisCI
  • Bitrise

で、結論としてBitriseで進めることにした。

理由としては

  • Bitriseはモバイルアプリ(特にAndroid)のインテグレーション(単体テストなど)、デプロイ(apkやaabの生成、GooglePlayStoreへのアップロード)が初期状態でほぼ構築済み。ユーザーは必要なパラメーターを入力するだけでほぼ実現できる。

Bitrise以外のサービスについては

  • GitHubActionはリポジトリをpublicにしたいという要件を満たせない。署名キーや広告IDは秘匿にできるにせよ、それにより生成されたバイナリが表に丸見えになりうる。やり方次第かもだが、バイナリを生成するワークフローを表に見せたくない…。
  • CircleCIはfastlaneの導入が必要になる。iOSアプリ開発者だと、コマンド一つでipaを生成するために導入したりなど比較的馴染みのあるツールだが、AndroidでCI/CDするためだけにわざわざ導入したいと思わない。
  • 残るTravisCIがBitriseの対抗馬となったが、導入の容易さから結果としてBitriseに軍配があがることとなった。

ただし注意事項として、Bitriseは1アカウントにつき処理できるジョブやタスクの回数?リソースの使用量?に制限がある。無料アカウントでは、毎月「300クレジット」という単位でサービスを利用できるが、これを越えると次のクレジット支給まで使えなくなる様子。
正直どんなもん?というところだが、(構築後日談として)1回のワークフロー(ビルドをするためのセットアップからビルド完了までの一連の流れ)を処理するのに大体10クレジット程度を消費しているため、30日間ではおよそ30回しか利用できない、ということになる。
とはいえ「プライベートで回している開発フローで、複数のプロジェクトを加味する必要があるとはいえ1ヶ月に30回もリリースビルド→デプロイすることあるか…?」と考えると、これが制限となってしまうことは稀になりそうだ。

というわけで今回はCI/CD環境を構築するためのサービスの選定とその理由について投稿した。次回はBitriseを利用したAndroidアプリのデプロイ環境の構築について投稿予定だ。

移行予定

どうも。どっことです。 タイトルの通りですが、諸事情により GitHubPage に移行予定です。 https://mkt120.github.io/ この備忘録に記載の内容を転記しつつ、今後はこちらのページを更新していく予定です。