とにかく安いRN79.3

# 目的

iPhoneアプリを可能な限り金をかけずに作成する

## RN77時代から変更になったこと

eas(expo)経由の場合、
有料のApple Developper Accountが無いと
ビルドも出来なくなりました

# 確認した環境

- iMac 2015 + Sonoma
- iPhone SE3

マシンの調達は[この辺](https://qiita.com/t-yano-tryhard/items/7c3e775b189daed5e2b5)参照

iPhoneは SE2なら ~~GEOで2万円以内で買える~~
個人取引除いたらイオシスが多分一番安い



# iPhoneとMacOSの接続

iphoneとMacOSはUSBで接続する
信頼をタップする

iPhoneで 
`設定` -> `プライバシーとセキュリティー` -> `デベロッパーモード` を ONにする
 -> 再起動
 
# 事前準備
 
cocoapods は cask から除外されたらしいので
インストール手順が変わっている


https://qiita.com/ta_yano/items/f5d356f2384f66c78d84

# プロジェクトの作成

```shell
npx @react-native-community/cli init [プロジェクト名]
```
公開するかわからないうちにAppleアカウントに13000円も払えないのでここはexpoを使わないですむ方法をとる

# 実機でのデバッグ実行

## ライブラリインストール

```
cd [プロジェクト名]
npm install
```

## ios用コードのインストール
Pod のインストール

```
bundle install
pushd ios
bundle exec pod install
popd

```

## metroの起動

```
npx react-native start --reset-cache
```

## Xcodeでのビルド

`xxxxx/ios/xxxxx.xcworkspace` を Xcodeで開く
Xcodeでビルドする
 Product -> Build
(マシンによるけど、Buildは多分10分以上かかる)

Xcodeで実行すると
-> iPhoneでポップアップ出てエラーになる
-> `キャンセル`

iPhoneで 設定 -> 一般 -> VPNとデバイス管理
-> インストールしたアプリのデベロッパーアカウントがあるので信頼をタップする

Xcodeでもエラーになっているので `OK` 押して再度実行

![スクリーンショット 2025-06-11 16.00.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3786381/44af1ff4-77c3-465d-9199-188f67f411d7.png)

# githubでのストア公開用ビルド

こちらは有料の開発者アカウントがあって、ストア公開用のビルドをgithubのCIで行う方法です

要は手元のマシンを使わずに無料環境でビルドしようという内容です

## githubにプロジェクトの登録
今更なので適当に調べてください

new repositoryして名前つけて
ローカルで `git push --set-upstream origin main`するだけです

ちなみにPublicじゃないとCIビルドは有料になるようです


## appleサイトで作成するべきもの
### Team IDとbundle ID

以下でアプリの bundle IDを作成します
https://developer.apple.com/account/resources/identifiers/list

Xcodeでアカウント設定してビルドしたなら勝手に作られるのでそれで良いです

10桁の`App ID Prefix`(Team ID) と `Bundle ID` をメモっておきます

### 配信用Certificate

#### オレオレ秘密鍵
キーチェーンアクセスを開いて
メニューのキーチェーンアクセス -> 証明書アシスタント -> 認証局に証明書を要求
`ユーザのメールアドレス`、`通称` は何でも良いらしいって聞いたけどとりあえず自分の入力するのが無難と思う
`CAのメールアドレス` は空のままで `ディスクに保存` を選択してあとは流れで

#### 配信用Certificate

以下で配信用の証明書を作成します
https://developer.apple.com/account/resources/certificates/list

＋を押した後、
`iOS Distribution`ではなく、`Apple Distribution`を選びます

`Choose File` で先ほど作成した
オレオレ秘密鍵つまり `CertificateSigningRequest.certSigningRequest` を選び
証明書をダウンロードします
`distribution.cer` というファイルがダウンロードされるので
キーチェーンアクセスを開いて `ログイン` を選び、D&Dなどで取り込みます



書き出すを選んでp12形式で保存します
そしてbase64変換します

例えば `distribution.p12`　という名前で `~/Downloads` に保存したのであれば
```
base64 -i ~/Downloads/distribution.p12 > ~/Downloads/distribution.b64
```
などとしておきます

p12作成時のパスワードも控えておきます

また、取り込んだ証明書の中間証明書も確認します
キーチェーンアクセス内で該当の証明書をダブルクリックなどで開いて
発行者名の部署を確認します

以下で該当の発行者の証明書をダウンロードします
https://www.apple.com/certificateauthority/
G3の場合は以下です
```
wget https://www.apple.com/certificateauthority/AppleWWDRCAG3.cer
```

適当な場所に置いてリポジトリに含めます
例）
```
mkdir -p .github/certificates
mv AppleWWDRCAG3.cer .github/certificates/
```

ちなみにRunnerから直で wgetは弾かれるようです

### Provisioning Profile

以下でプロファイルを作成します

https://developer.apple.com/account/resources/profiles/list

`Distribution` の `App Store Connect` を選択します
名前も控えておきます
ダウンロードして同じようにbase64エンコードします

例)
```
base64 -i ~/Downloads/xxxxx.mobileprovision > xxxxx.b64
```


## github Secret

[github](https://github.com/)に行き、プロジェクトのリポジトリで `Settings` -> `Secrets and variables` -> `Actions`
と進み `New repository secret` をクリックして以下を作成します

| 変数名 | 内容 |
| - | - |
| IOS_DIST_CERT | p12 から変換したb64の中身貼り付け |
| IOS_DIST_CERT_PASSWORD | p12作成時のパスワード |
| IOS_PROVISIONING_PROFILE | mobileprovisionから変換したb64の中身貼り付け |
| APPLE_DEVELOPMENT_TEAM | 10桁のチームID |
| APPLE_PROVISIONING_PROFILE_SPECIFIER | プロファイル名 |
| PRODUCT_BUNDLE_IDENTIFIER | BundleID|

## CI スクリプト

プロジェクトルートから見て以下の場所にファイルを作成します
```
mkdir -p .github/workflows/
vim .github/workflows/ios-build.yml
```

.github/workflows/ios-build.ymlの中身(❗をつけた部分は修正してください)
```yml
name: iOS Build

on:
  push:
    branches: [❗自分のブランチ名]
  pull_request:
    branches: [❗自分のブランチ名]

jobs:
  build:
    name: Build iOS App
    runs-on: macos-15(❗バージョンは2025/6月時点)

    steps:
      - uses: actions/checkout@v4

      - name: Select Xcode 16.4(❗バージョンは2025/6月時点)
        run: sudo xcode-select -s /Applications/Xcode_16.4.app

      - name: Decode provisioning profile
        run: |
          mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles/
          echo "${{secrets.IOS_PROVISIONING_PROFILE}}" | base64 -d > ~/Library/MobileDevice/Provisioning\ Profiles/[❗元のファイル名].mobileprovision

      - name: Decode certificate
        run: |
          echo "${{secrets.IOS_DIST_CERT}}" | base64 -d > ios_dist.p12

      - name: Import certificate
        run: |
          mkdir -p ~/Library/Keychains
          security create-keychain -p "${{secrets.IOS_DIST_CERT_PASSWORD}}" ~/Library/Keychains/build.keychain-db
          security unlock-keychain -p "${{secrets.IOS_DIST_CERT_PASSWORD}}" ~/Library/Keychains/build.keychain-db
          security set-keychain-settings ~/Library/Keychains/build.keychain-db
          security list-keychains -s ~/Library/Keychains/build.keychain-db
          security default-keychain -s ~/Library/Keychains/build.keychain-db

          ❗自分の置いた場所のパスを指定してください
          security import .github/certificates/AppleWWDRCAG3.cer -k ~/Library/Keychains/build.keychain-db -T /usr/bin/codesign
          security import ios_dist.p12 -k ~/Library/Keychains/build.keychain-db -P "${{secrets.IOS_DIST_CERT_PASSWORD}}" -T /usr/bin/codesign
          security set-key-partition-list -S "apple-tool:,apple:," -s -k "${{secrets.IOS_DIST_CERT_PASSWORD}}" ~/Library/Keychains/build.keychain-db
          security find-identity -v -p codesigning ~/Library/Keychains/build.keychain-db

      - name: Install Node.js
        uses: actions/setup-node@v4
        with:
          node-version: "24.2.0" ❗バージョンは任意

      - name: Install npm dependencies
        run: npm install

      - name: Setup Ruby
        uses: ruby/setup-ruby@v1
        with:
          ruby-version: 2.6.10 ❗バージョンは任意

      - name: Install Ruby gems
        run: bundle install

      - name: Install CocoaPods dependencies
        run: |
          rm -rf ~/Library/Developer/Xcode/DerivedData/*
          rm -rf ios/Pods
          cd ios
          bundle exec pod install

      - name: Build IPA with Fastlane
        env:
          MATCH_PASSWORD: ${{ secrets.IOS_DIST_CERT_PASSWORD }}
          APPLE_PROVISIONING_PROFILE_SPECIFIER: ${{secrets.APPLE_PROVISIONING_PROFILE_SPECIFIER}}
          APPLE_DEVELOPMENT_TEAM: ${{secrets.APPLE_DEVELOPMENT_TEAM}}
          CODE_SIGN_IDENTITY: "Apple Distribution"
          PROVISIONING_PROFILE_SPECIFIER: ${{secrets.APPLE_PROVISIONING_PROFILE_SPECIFIER}}
          DEVELOPMENT_TEAM: ${{secrets.APPLE_DEVELOPMENT_TEAM}}
          PRODUCT_BUNDLE_IDENTIFIER: ${{secrets.PRODUCT_BUNDLE_IDENTIFIER}}
          binary_archs: "arm64"
          stripped: ""
        run: |
          cd ios
          bundle exec fastlane build_only

      - name: Upload IPA artifact
        uses: actions/upload-artifact@v4
        with:
          name: [❗️アプリ名].ipa
          path: ios/[❗️アプリ名].ipa

```

## fastlane用ファイル

`ios/fastlane/FastFile` を作成します

```ruby
default_platform(:ios)

lane :build_only do
  gym(
    scheme: "❗️アプリのスキーム名",
    workspace: "❗️ワークスペース名.xcworkspace",
    export_method: "app-store",
    export_options: {
      method: "app-store",
      teamID: ENV["DEVELOPMENT_TEAM"],
      uploadBitcode: false,
      uploadSymbols: true,
      compileBitcode: true,
      destination: "export",
      signingStyle: "automatic",
      stripSwiftSymbols: true,
      thinning: "<none>"
    },
    clean: true,
    silent: false,
    xcargs: "-verbose",
  )
end
```
アプリのスキーム名は通常RNで最初に作成したアプリ名になっています
ワークスペース名もアプリ名と同じになっていると思います

## ビルド

普通にcommitしてpushしたら勝手にビルドされます

## ipaのダウンロード

githubのプロジェクトのリポジトリを開いて
`Actions` -> 該当のAction　-> 該当のJobを選ぶと さらにステップ一覧が表示されます
特に変更してなければ `Upload IPA artifact` なので、タップしてログを表示し
downloadと表示されているリンクをクリックすればダウンロードできます

例)
```
Run actions/upload-artifact@v4
With the provided path, there will be 1 file uploaded
Artifact name is valid!
Root directory input is valid!
Beginning upload of artifact content to blob storage
Uploaded bytes 8388608
Uploaded bytes 14296244
Finished uploading artifact content to blob storage!
SHA256 digest of uploaded artifact zip is 8cda17ef73593a31545e4f7662405df0e74e61f7a929ad8e7567400e7b21429a
Finalizing artifact upload
Artifact xxx.ipa.zip successfully finalized. Artifact ID 3336780156
Artifact xxx.ipa has been successfully uploaded! Final size is 14296244 bytes. Artifact ID is xxxxxxx
Artifact download URL: https://github.com/tyano463/xxx/actions/runs/xxxxx/artifacts/xxxxx
```

あとは解凍してTransporter(App Storeからインストールする)などでアップするだけ

# Appleサイトでのビルド

github ciはまさかの集ストシステムでした
MicrosoftはGoogleに屈してから堕ちる一方だな

というわけでAppleのサイトでビルドすれば信頼性もあるし早いんじゃね？
という内容です

当然ですが有料アカウントがあること前提です

## アプリの登録

ストアコネクトに行きます

https://appstoreconnect.apple.com

アプリを選んで自動ビルド対象のアプリを選択します
まだ登録していないのなら新規アプリで作成して保存してください

## React Native 特有の追加作業

Xcodeでプロジェクトを選んで右クリ -> New Groupで `ci_scripts`を作成します
作成できたら、また右クリ -> New File で `ci_scripts` 内に `ci_pre_xcodebuild.sh` という名前で
シェルスクリプトを作成します

シェルスクリプトの内容は以下です
`nodejs` は `nvm` にすることで対話型の入力を省きます
`nodejs` と `ruby` のバージョンは任意です

```shell
#!/bin/bash

set -x
set -e

brew install nvm
export NVM_DIR="$HOME/.nvm"
source $(brew --prefix nvm)/nvm.sh
nvm install 24.2
nvm use 24.2

echo "node version: $(node -v)"

brew install rbenv ruby-build
export RBENV_ROOT="$HOME/.rbenv"
eval "$(rbenv init -)"

rbenv install -s 3.3.3
rbenv global 3.3.3

echo "Ruby version: $(ruby -v)"

CUR=`pwd`
echo "current directory is ${CUR}"
cd /Volumes/workspace/repository && npm install
echo "npm installed"

cd "${CUR}/../../" && bundle install
echo "bundle installed"
cd "${CUR}/../" && bundle exec pod install
echo "pod installed"

cd ${CUR}
```

一応コマンドラインから実行権限を与えておきます
```
chmod +x ios/ci_scripts/ci_pre_xcodebuild.sh
```

これでワークフローのビルド前にスクリプトが実行されるようになります

なお、expoの場合はコマンドが異なるので
expoの場合に応じたコマンド( `prebuild` など)を記載してください

`CUR` の位置は `ios/ci_scripts` です

## XCodeでのワークフローの作成

１回作成すると以降はWeb上で触れるようだけど
初回だけはローカルでやらないとダメっぽい

左のサイドバーの９つ並んでいるうちの リストみたいなアイコン( `Show the Report navigator` ) から作成します

`Cloud`タブ を選択し、 `Creat Workflow` をクリックします

こんな感じのが表示されるので迷うことはないと思います

![workflow](https://developer.apple.com/xcode-cloud/get-started/images/xcode-cloud-workflow-large_2x.png)

## ビルド

どういう原理か、App Store Connectへは勝手にWorkflowの内容が送信されて追加されています

先ほど追加したciスクリプトやそれに関連して変更になったファイルなどを
`add` して `commit` 、`push`すれば勝手にビルドしてくれます

ここまでちゃんと読んだ人はわかると思いますが
Appleでビルドする場合、鍵とか証明書とか
そういう面倒なのはXcodeの設定(*1)だけちゃんとやってれば
全部Apple側でやってくれます

(*1)
スキームをリリースビルドにして、プロファイルを選択する
Product -> Scheme -> Edit Schemeから編集できます

# ストア公開その他

## アプリ紹介画像

6.9インチの1290x2796のアプリ紹介画像が必要です
iPhone SEではダメなのでシミュレータで撮るしかありません
シミュレータの場合、マイクやBTなどは使用できない(エラーになる)ので
該当の機能を使用している場合、該当部分をスキップする画面取得のためのコードを作成する必要があります

シミュレータのスクショは `⌘ + s` です

## ポリシーサイト

アプリのポリシーサイトをリポジトリにしてgithub pagesにする場合は
アプリのリポジトリと分けた方が良いと思います
ポリシーサイトの編集でcommitしたときに自動ビルドが走って
CIの無料枠を使ってしまうからです
    
# その他

ストア公開前でも、結局5万円くらいは必須（iPhone持ってるなら3万円）っぽい 
ストア公開用アカウント(+13000)と合わせて６万３千円くらいですね

metroの実行中に直しながら反映ってのは ~~出来ない~~
~~使いたかったら13000円/年 払ってexpoで実行する~~
`npx react-native start` してからXcodeでRunして10分くらい放っておけば繋がるみたい

他にマシンがあって画面の確認をしたいだけなら
android用にビルドしてNative部分は無視して確認するという方法もある

ちなみにandroidならマシンとスマホ合わせて1万ちょっと超えるくらい
登録は4000円くらいなので2万あればお釣りくる
というかandroidは公開しなくても野良でインストールすれば良いだけ
だけど、androidは集スト御用達なので日本人には難しい

# 参考サイト

https://developer.apple.com/xcode-cloud/get-started/