CatHand Blog

アプリ開発やMac弄り

gStat

gStatというアプリをリリースしました。

GitHub Actions のステータスを表示したり、実行したりできるアプリです。

play.google.com

最近 CI/CD 環境をBItriseからGItHub Actionsに移行しています。BitriseはbStatというアプリをリリースしていましたが、それのGitHub Actions版になります。

FlutterなのでiOS, macOS, Androidアプリがあります。特にmacOSアプリはメニューバーにステータスを表示してそこからアクセスできるので便利かと思います。

FailedToLaunchAppError で SwiftUI のプレビューが表示されない問題の解消法

SwiftUIのプレビューが表示されないことはよくありますが、原因が特定しづらいので困ります。今回は failed to launch... というエラーで表示されない問題が解決できたケースを紹介します。

環境:

エラーは以下です。

    FailedToLaunchAppError: Failed to launch app.bundle.id
    
    ==================================
    
    |  RemoteHumanReadableError: 操作を完了できませんでした。Transaction failed. Process failed to launch. (process launch failed)
    |  
    |  BSTransactionError (1):
    |  ==NSLocalizedFailureReason: Transaction failed. Process failed to launch. (process launch failed)
    |  ==error-description: Process failed to launch.
    |  ==transaction: <FBApplicationProcessLaunchTransaction: 0x600003b08460>
    |  ==precipitating-error: Error Domain=FBProcessExit Code=64 "The process failed to launch." UserInfo={NSLocalizedFailureReason=The process failed to launch., BSErrorCodeDescription=launch-failed, NSUnderlyingError=0x600000c4da70 {Error Domain=RBSRequestErrorDomain Code=5 "Launch failed." UserInfo={NSLocalizedFailureReason=Launch failed., NSUnderlyingError=0x600000c4da10 {Error Domain=NSPOSIXErrorDomain Code=111 "Unknown error: 111" UserInfo={NSLocalizedDescription=Launchd job spawn failed}}}}}
    |  ==error-reason: process launch failed

いろいろ調べたところ、Excluded Architecturesの設定が怪しいようです。

これは、シミュレータ向けのApple Siliconバイナリがまだあまり出揃っていないころにビルドを通すために行った設定ですね。

www.cathand.app

Podfileの該当部分は↓。

post_install do |installer|
  installer.pods_project.build_configurations.each do |config|
    config.build_settings["EXCLUDED_ARCHS[sdk=iphonesimulator*]"] = "arm64"
  end
end

この設定は今はほとんど必要ないので外してみます。

ですが、これを外してもapp側のExcluded Architecturesの設定が消えません。

使っているライブラリの中ではOpenCVが怪しそうです。podspecを確認するとEXCLUDED_ARCHSを設定しています。

github.com

OpenCVをcocoapodsで入れるのをやめて、以前作成したxcframeworkを参照するようにしてみます。

www.cathand.app

これによりExcluded Architecturesの設定が消え、プレビューが表示されるようになりました。

↑で作ったxcframeworkは少しバージョンが古いのですが、最新のものを使いたい場合は以下の方法でできるようです。

dev.classmethod.jp

AppStore Connect APIを使わずにfastlaneでAppStore Connectへバイナリをアップロードする

fastlaneでAppStore Connectへアップロードする方法を検索すると、AppStore Connect APIを使う方法ばかり出てきますが、Apple IDのアプリ用パスワード(Application Specific Password)のみを使ってアップロードする方法があります。

まあドキュメントに書いてあるんですが…。

pilot - fastlane docs

Use an Application Specific Password to upload

pilot/upload_to_testflight can use an Application Specific Password via the FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD environment variable to upload a binary if both the skip_waiting_for_build_processing and apple_id options are set. (If any of those are not set, it will use the normal Apple login process that might require 2FA authentication.)

  • 環境変数 FASTLANE_USERFASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD を設定
  • apple_id を設定
  • skip_waiting_for_build_processing を true にする

で、AppStore Connect APIを使わずにアップロードできます。

Github Actionsでビルドナンバーにオフセットを設定する

Github Actionsでいいかんじのビルドナンバーをつけたいとき、 github.run_number が使えます。これはworkflowの実行番号を表しています。

これをそのままではなく、オフセットをつけたい場合は以下のようにコマンドでできます。↓の例では +2000 しています。

      - name: make build number
        env:
          NUM: ${{ github.run_number }}
        run: |
          echo "BUILD_NUMBER=$(($NUM + 2000))" >> $GITHUB_ENV
      - name: fastlane
        env:
          BUILD_NUMBER: ${{ env.BUILD_NUMBER }}
        run: |-
          bundle install
          bundle exec fastlane ios release

これでfastlane側では ENV["BUILD_NUMBER"] でビルドナンバーを参照できます。

PX-M6010F

A3プリンター複合機を買いました。

A3スキャンができる複合機だとほぼこれしか選択肢がありません。久しぶりにプリンターを買ったんですが最近の機種はすごいですね。両面印刷や両面スキャンできるし、スキャンしたものはそのままGoogle Driveとかに保存できたりすごい便利です。

設定忘れてスキャン後のpdfが別の方向向いてたりすることがたまにあるんですが、そういう場合にプレビューで開いて回転させるのはめんどいので、Automaterのワークフローを作りました。

pdfを回転させるのは pdftk コマンドでできます。pdftk はhomebrew等でインストールしてください。

例えば、全てのページを左回転させるのは以下のスクリプトでできます。pdftkコマンドでは上書きができないっぽいので一度テンポラリファイルに書き出してからmvしています。

#!/bin/zsh

PDFTK="/opt/homebrew/bin/pdftk"

INPUT=$@

FILENAME=${INPUT##*/}
FILENAME_WITHOUT_EXT=${FILENAME%.*}
DIRNAME=${INPUT%/*}
OUTFILE="${DIRNAME}/${FILENAME_WITHOUT_EXT}.tmp.pdf"

$PDFTK $INPUT cat 1-endleft output $OUTFILE
mv $OUTFILE $INPUT

右回転の場合は 1-endleft1-endright に変えればOKです。

で、これをAutomaterのワークフローとして保存します。

保存した.workflowファイルを ~/Library/Services/ に保存するとFinderのコンテキストメニューの「クイックアクション」から上記スクリプトを呼び出せるようになるんですが、複数ファイルを選択して実行したときに1つのファイルしか処理してくれません。

複数ファイルを処理するために、上記ワークフローを呼び出すワークフローを作成します。

この.workflowファイルを ~/Library/Services/ に保存することで、Finderのコンテキストメニューから複数pdfの回転処理ができるようになります。

ついでに、画像のpdfファイルを文字認識して検索可能にするスクリプトも置いておきます。文字認識には tesseract を使っていて、こちらもhomebrewでインストールできます。

#!/bin/zsh

tesseract="/opt/homebrew/bin/tesseract"
pdftk="/opt/homebrew/bin/pdftk"

target="$@"
targetwithoutext="${@%.pdf}"

# pdftoppm
mkdir "${targetwithoutext}.d"
# - png
$pdftoppm -png "${target}" "${targetwithoutext}.d/page"

# tesseract
# - png
find "${targetwithoutext}.d" -type f -name "*.png" | sed 's/\.png$//' | xargs -P8 -n1 -I% $tesseract %.png % -l eng+jpn pdf

# Merge to one pdf file
$pdftk "${targetwithoutext}.d"/*.pdf cat output "${targetwithoutext}-ocr.pdf"

# Clear
rm -r "${targetwithoutext}.d"

これもワークフローにすればFinderのコンテキストメニューから使うことができます。

Cycle inside ... building could produce unreliable results.

Xcode15でArchiveするとCycle inside ... building could produce unreliable results.のようなエラーが発生する場合があります。

App Extensionを含むプロジェクトで起きることが多いようなのですが、

  • Embed Foundation Extensions ステップを Copy Bundle Resources ステップの後へ移動する

と直るようです。

↓こうする。

大きな画像をリサイズして読み込む

Share Extension等、メモリ制約が大きい場合に、大きな画像を普通にUIImage(contentsOfFile:)で読み込むとメモリ不足でクラッシュする場合があります。

そのような場合には、リサイズしつつCGImageで読み込んでからUIImageに変換するとよいです。

gist.github.com

Twitter API v2 で画像付きポストをする

先日、Twitter API v1.1 がcloseされました。アクセスすると↓のようなエラーになります。

投稿APIについてはv2 APIが無料で提供されているので、投稿のみなら無料でできます。ただし、画像などを添付したい場合、v2 APIではメディアアップロードAPIが提供されていないのでテキストの投稿しかできません。

ではどうするかというと、v1.1のメディアアップロードAPIはまだcloseされていないので、v1.1 APIでメディアをアップロードして、そのidを使ってv2 APIで投稿することで画像付きの投稿ができます。

また、v2 APIでは認証方式としてOAuth2.0 PKCEが利用できますが、OAuth2.0 PKCEのtokenでv1.1 APIは呼べないので、両方のAPIを一つのtokenで呼ぶにはOAuth1.0aで認証する必要があります。

まとめると↓のようになります。

  投稿API メディアアップロードAPI OAuth1.0a OAuth2.0 PKCE
v1.1 × ×
v2 ×

以上より、↓の方法で画像付きの投稿が実現できます。

  • OAuth1.0aで認証
  • v1.1のメディアアップロードAPIで画像をアップロード
  • v2 APIで投稿

firebase functions から firebase functions を呼ぶ

firebase function から firebase function を呼びたい場合があると思います。

呼ばれる方の function が公開されている場合は簡単ですが、呼ばれる方を公開したくない場合は呼ばれる方の function を要認証にして、bearer tokenを指定して呼ぶことができます。

gist.github.com

今回はTypescriptからgoを呼びたかったのでこのような方法で安全に呼ぶことができました。

Illustail v5.3.0 (macOS)

でてます。

apps.apple.com

macOS版のみですが、タイムラインのメディアを自動ダウンロードする機能をつけました。

設定の↓ここからいけます。

  • タイムライン
  • 保存先フォルダ
  • メディアの種類(動画、画像、全て)

を設定できます。

ダウンローダーを設定すると、アプリを起動している間、10分間隔で新着のメディアを指定されたフォルダにダウンロードします。

タイムラインをうまく設定しないとゴミばかりダウンロードすることになる場合もありますが、定点観測したい場合などに使えるかと思います。