MacでHomebrewを使用したDocker Desktopのインストールエラー対処法(xattr: [Errno 1])

はじめに

MacにHomebrewでDocker Desktopをインストールしようとすると、以下のようなエラーが発生しました。

% brew install --cask docker

Error: Failure while executing; /usr/bin/sudo -E -- /usr/bin/xattr -w com.apple.metadata:kMDItemAlternateNames \(\"docker\"\) /opt/homebrew/Caskroom/docker/4.38.0,181591/Docker.app/Contents/Resources/etc/docker.bash-completion exited with 1. Here's the output:
xattr: [Errno 1] Operation not permitted: '/opt/homebrew/Caskroom/docker/4.38.0,181591/Docker.app/Contents/Resources/etc/docker.bash-completion'

対策

いろいろと調べた結果、「[HomebrewでDocker Desktopを再インストールするときに注意すること][1]」というページを見つけました。

–forceをつけて全部削除してインストールし直すだけで解決できるようです。

brew uninstall --cask docker --force
brew install --cask docker

これで無事にDocker Desktopをインストールすることができました。

ありがとうございました。

Android14のSelected Photos Accessについて

問題

AndroidManifest.xmlの下記の行で警告が表示されます。

<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />

警告メッセージは以下の通りです。

Your app is currently not handling Selected Photos Access introduced in Android 14+ More... (⌘F1) 
Inspection info:Selected Photo Access is a new ability for users to share partial access to their photo library when apps request access to their device storage on Android 14+.  Instead of letting the system manage the selection lifecycle, we recommend you adapt your app to handle partial access to the photo library.

このエラーの原因と対策を調べました。

原因

この警告メッセージは、Android 14(APIレベル 34)で導入された「Selected Photos Access(選択した写真へのアクセス)」に対応していないことを指摘しています。

Android 14以降、ユーザーはアプリがデバイスのストレージにアクセスを要求する際に、写真ライブラリ全体へのアクセスを許可する代わりに、選択した写真への部分的なアクセスを共有する新しい機能を利用できます。

android.permission.READ_MEDIA_IMAGESパーミッションを使用することで、アプリはユーザーのデバイス上の画像にアクセスできますが、Android 14+では、ユーザーが選択した写真へのアクセスのみをアプリに許可するオプションが追加されています。この変更により、ユーザーのプライバシーがさらに強化され、アプリは必要な写真にのみアクセスできるようになります。

この警告に対処するためには、アプリを「Selected Photos Access」に対応させる必要があります。具体的には、アプリが選択した写真への部分的なアクセスを管理し、この新しいアクセス権限に適応するようにする必要があります。

Selected Photos Accessの特徴と動作

  • 部分的なアクセス許可:ユーザーはアプリに対して、写真ライブラリ全体ではなく、選択した写真にのみアクセスを許可できます。これにより、ユーザーはプライバシーを保護しつつ、アプリの機能を利用できます。

  • 動的なアクセス管理: ユーザーはいつでも設定を変更し、アプリがアクセスできる写真を追加または削除できます。アプリは、これらの変更をリアルタイムで反映する必要があります。

  • ユーザーインターフェースの調整: アプリは、選択された写真へのアクセスが許可された場合、ユーザーが新たにアクセスを許可した写真に簡単にアクセスできるようにユーザーインターフェースを調整する必要があります。

対応

Selected Photos Access を利用する

アプリで Selected Photos Access を利用するには、以下の手順が必要です。

  1. アプリのターゲット API レベルを 33 に設定します。
  2. アプリの AndroidManifest.xml ファイルに以下の権限を追加します。
    <uses-permission android:name="android.permission.READ_MEDIA_VISUAL_USER_SELECTED" />
    
  3. アプリで PhotoPicker クラスを使用して、ユーザーが写真や動画を選択できるようにします。

PhotoPicker クラスの使用

PhotoPicker クラスは、ユーザーが写真や動画を選択するための UI を提供します。このクラスを使用するには、以下の手順が必要です。

  1. PhotoPicker.Builder クラスのインスタンスを作成します。
  2. Builder インスタンスに、ユーザーが選択できる写真や動画の種類を指定します。
  3. Builder インスタンスの build() メソッドを呼び出して、PhotoPicker インスタンスを作成します。
  4. PhotoPicker インスタンスの start() メソッドを呼び出して、写真選択画面を表示します。

ユーザーが選択した写真や動画へのアクセス

ユーザーが写真や動画を選択した後、アプリは PhotoPicker インスタンスの getSelectedPhotos() メソッドを使用して、選択された写真や動画への URI を取得できます。

Selected Photos Access の制限事項

Selected Photos Access には、以下の制限事項があります。

  • ユーザーが選択した写真や動画のみアクセスできる
  • ユーザーがアプリをアンインストールすると、アプリは選択された写真や動画へのアクセス権を失う

「Build Type ‘debug’ contains custom BuildConfig fields」エラーの対策

問題

Android Studioでアプリをビルドすると、以下のようなエラーが発生しました。

Build Type 'debug' contains custom BuildConfig fields, but the feature is disabled.
To enable the feature, add the following to your module-level build.gradle:
android.buildFeatures.buildConfig true

このエラーは、build.gradle 内でBuildConfigにカスタムフィールドを追加しようとした際に、buildConfig機能が無効になっているために発生します。

このエラーの原因と解決方法を解説します。

エラーの原因

Android Gradle Plugin (AGP) 8 以降では、buildConfig機能がデフォルトで無効になっています。
つまり、カスタムBuildConfigフィールドを使用すると、エラーが発生します。

例えば、以下のようにbuild.gradle (Module: app)にbuildConfigFieldを追加している場合、このエラーが発生します。

android {
    buildTypes {
        debug {
            buildConfigField "String", "API_URL", "\"https://api.example.com\""
        }
    }
}

このエラーを解決するためには、buildConfig機能を有効にする必要があります。

解決策

1. buildConfigを有効にする

build.gradle (Module: app)を開き、以下の設定を追加してください。

android {
    buildFeatures {
        buildConfig true
    }
}

2. Gradle Syncを実行

設定を追加した後、Android Studioの「Sync Project with Gradle Files」を実行し、build.gradleの変更を反映します。

3. プロジェクトをリビルド

次に、プロジェクトをリビルドします。

  • メニューから Build → Rebuild Project を実行
  • または、ターミナルで以下のコマンドを実行
    ./gradlew clean
    ./gradlew build
    

これでエラーが解消されました。

LaravelでStorageのtemporaryUrlをモック化する方法

Laravelを使用していると、S3ストレージのtemporaryUrlメソッドを利用する場面が出てきます。

しかし、ユニットテスト環境では実際のS3にアクセスするのではなく、このtemporaryUrlをモック化してテストを行いたい場合があります。

本記事では、LaravelのStorageファサードを使用してtemporaryUrlをモック化する方法をご紹介します。

動機

通常、StoragetemporaryUrlは指定したファイルに対する一時的なアクセスURLを生成します。

しかし、ユニットテストでは外部サービス(この場合はAWS S3)に依存することなくテストを完結させたいものです。

そのため、temporaryUrlメソッドをモック化し、意図した値を返すように設定する必要があります。

モック化の手順

以下のコードスニペットは、Storageファサードをモック化し、temporaryUrlメソッドが指定したURLを返すように設定する方法を示しています。

Storage::shouldReceive('disk')
        ->with('s3')
        ->andReturnSelf();

Storage::shouldReceive('temporaryUrl')
        ->with('example.jpg', Mockery::type(\DateTimeInterface::class))
        ->andReturn('https://example.com/temp-url/example.jpg');

解説

  1. Storage::shouldReceive('disk')->with('s3')->andReturnSelf();
    Storage::disk('s3')が呼び出されたときに、Storageのモックインスタンス自身を返します。これにより、チェーンメソッドを使用する際にモックを適切に動作させることができます。

  2. Storage::shouldReceive('temporaryUrl')
    temporaryUrlが呼び出されたときに、指定したURLを返すように設定します。引数としてファイル名(example.jpg)とDateTimeInterface型のインスタンスが期待されます。

モック化を活用したテスト例

以下は、StoragetemporaryUrlをモック化し、ユニットテストで利用する例です。

public function testTemporaryUrl()
{
    // モック設定
    Storage::shouldReceive('disk')
        ->with('s3')
        ->andReturnSelf();

    Storage::shouldReceive('temporaryUrl')
        ->with('example1.jpg', Mockery::type(DateTimeInterface::class))
        ->andReturn('https://example.com/temp-url/example1.jpg');

    Storage::shouldReceive('temporaryUrl')
        ->with('example2.jpg', Mockery::type(DateTimeInterface::class))
        ->andReturn('https://example.com/temp-url/example2.jpg');

    // テスト: モック化されたURLの確認
    $url = Storage::disk('s3')->temporaryUrl('example1.jpg', now()->addMinutes(5));
    $this->assertEquals('https://example.com/temp-url/example1.jpg', $url);

    $url = Storage::disk('s3')->temporaryUrl('example2.jpg', now()->addMinutes(5));
    $this->assertEquals('https://example.com/temp-url/example2.jpg', $url);
}

テストのポイント

  • モック化により、実際にAWS S3に接続することなくテストを実行できます。
  • ファイル名や日付の引数ごとに返されるURLを自由に設定可能です。
  • テストの結果を保証するため、モック化したURLをassertEqualsで検証します。

まとめ

Laravelのユニットテストで外部ストレージの依存を排除することは、テストの信頼性とスピードを向上させます。

今回紹介した方法を活用すれば、簡単にtemporaryUrlメソッドをモック化でき、ストレージ関連のコードを効率よくテストできるようになります。