20220223のiOSに関する記事は7件です。

個人開発で初めてiOSアプリをリリースした備忘録

目次 はじめに 私のスキル 難しかった点 良かった点 さいごに はじめに 先日、初めて個人としてiOSアプリをリリースしました。 リリースまでの期間は約3ヶ月でした。まだまだ知らないことも多く、大変学びのある経験でした。 そこで今回は、リリースまでの過程で感じたことや気づいた点について書きました。 これから個人開発をしてみたい方、現在個人開発をしている方の役に立つかもしれません。 私のスキル まずは簡単に私のスキルについて紹介します。 個人開発は前提知識がどれくらいあるかで難易度が変わるので、参考になれば幸いです。 現役のiOSエンジニア。iOSアプリの開発やリリース経験あり。 基礎的なSwiftの記法、Xcodeの使い方、リリース方法について理解している。 エラーや分からない事があっても、検索等を駆使して多くの場合は解決できる。 難しかった点 ⭐️スケジュール管理が難しい 私の場合、基本的には平日仕事をしながら隙間時間で個人開発を進めていました。 基本的には仕事の状況を見ながら、ちょこちょこ進めていくのですが、時間の使い方が難しかったです。 個人開発はリリースするタイミングが完全に自分次第なので、 時間を割けず開発が長期間になってモチベーションが続かなくなったり、 反対に「早く出したい」という気持ちが先行してつい睡眠時間を削ってしまうこともありました。 実際にリリースして感じましたが、開発ペースに波があることはあまり気にしなくて良いと思います。良いものをしっかり考えて十分に時間をかけた方がユーザーに喜ばれるサービスになるはずです。 ⭐️デザイン難しい アプリをリリースする為には、App Storeに提出するスクリーンショットやアプリアイコン等の準備が必要になります。思っていたよりもこれらの準備に時間がかかりました。そしてデザインを自力で全てやろうとすると結構難しいです。 私はデザインの知識がほとんどなく、ツールの使い方もあまり詳しくありませんでした。 私の場合は、デザイナーさんに依頼したり、便利なツールを駆使することでこれらを解決しました。 ココナラなどデザイナーさんに依頼できるサービスもあるので、上手に活用したいですね。 画面のデザインについても素人なので、どういう風にすべきかかなり悩みましたが、こちらはAppleのHuman Interface Guidlinesや様々なアプリのUIを参考にしました。 アプリのUIについては、Playというアプリで様々なUIをお試し作成しましたが、とても良いサービスなのでぜひ使ってみてください。 ⭐️細かい部分が気になってしまう 開発を進めていると、既にできている箇所に対して「ボタンの配置を変えたい」「この機能も追加したい」という様な思いが出てくることがあります。こうなるといつまでもリリースまで辿り着けません。 もしアプリをリリースしたいと考えている方は以下の2点を意識すると良いです。 設計やデザイン、提供したい機能を明確にしてから実装する。最初にしっかり時間をかけた方が良いです。結果的に手戻りが減って早くリリースできます。 最低限の機能だけを実装する。まずはリリースして改善していく方がユーザーの反応も分かります。 ⭐️サービス名を考えるのが難しい サービス名考えてくれるサイトもあるので、必要に応じて活用すると良いです。 良かったこと ⭐️自分が作ったアプリがApp Storeに並ぶ達成感を味わえる。自信になる。 自分の作ったアプリがApp Storeに並ぶまでは数多くの壁があります。 アプリの企画・設計から開発、リリース審査に向けた対応など。個人開発ではこれらを一人で解決しながら進めていく必要があります。その為、無事に審査が通った時にはうれしくて感動します。そしてこれらを成し遂げたということが自信になります。 ⭐️とにかく楽しい 自分のペースで開発を進めたい。新しい技術を試したい。自分で考えたサービスを出してみたい。このような思いを持ったエンジニアにとって個人開発は最高です。 好きなだけコードを書けますし、どんな書き方も出来ます。コードを書くのが好きな人だったら個人開発は楽しくて仕方ないです。 ⭐️技術力がアップする 新しい技術を試したりリリースまでの準備をしていると必ず壁にぶつかります。 これらを自力で解決したり自分の頭で考えることで課題解決能力や開発の技術力が向上します。 一人で全てやることでリリースまでの一連の流れをしっかり理解できますし、チーム開発のありがたさも感じます。 さいごに アプリの開発をひとりでやるのは大変な点もありますが、学びが多くエンジニアとしての自信にもなるのでかなりオススメです! 最後に私がリリースしたアプリのリンクを記載するので、もし興味をもってくださった方がいたら、覗いてみてください! DIG IT(ディグ イット)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

On Demand Resourcesを使う(Swift Concurrency対応)

個人アプリでOn Demand Resourcesを使いたいところがあり、以下の記事を参考に導入してみました。 https://qiita.com/kukimo/items/39a0eeb40626a4cd364f https://www.raywenderlich.com/520-on-demand-resources-in-ios-tutorial 仕組みや手順は公式ドキュメントと上記記事を参照するのが早いと思います。 Swift Concurrencyで以下のようなユーティリティを作っておくとより簡単に導入できるよというお話。 ResourceLoader.swift import Foundation /// On Demand Resourceの読み込みを支援 final class ResourceLoader { static let `default` = ResourceLoader(bundle: .main) private let bundle: Bundle private init(bundle: Bundle) { self.bundle = bundle } /// tagで指定されたOn Demand Resourceを読み込む /// onSuccessで、実際のリソース読み込み処理を実装する func load<R>( tag: String, onSuccess: () throws -> R ) async throws -> R { let request = NSBundleResourceRequest(tags: [tag], bundle: bundle) if await request.conditionallyBeginAccessingResources() { // リソースは端末にダウンロードされている } else { // 端末にリソースをダウンロード try await request.beginAccessingResources() } return try onSuccess() } } 使い方はこんな感じ。 let image = try await ResourceLoader.default.load( tag: "MoreImages", onSuccess: { UIImage(named: "more_image1") } ) let url = try await ResourceLoader.default.load( tag: "MoreSounds", onSuccess: { Bundle.main.url(forResource: "sound", withExtension: "mp3") } )
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Android/iOS】Webブラウザのアドレスバーを非表示にする方法

はじめに Android/iOSのWebブラウザのアドレスバーを非表示にする方法です。 ネットで調べて出てくることには出てくるのですが、なかなかたどり着かなかったのでQiitaに投稿しておきます。 やりたいこと 据え置きのタブレット端末でWebアプリを動作させるときに、アドレスバーを非表示にしたい。 ↓ 調べたところ、Webブラウザの設定でフルスクリーン(アドレスバー非表示)にするのは無理そう。 (フィッシングサイトによる悪用などを考慮している?) ↓ Webブラウザの設定変更以外の方法でアドレスバーを非表示にしたい。←今回やりたいこと 結論 以下のサイトを参考にしました。 [HTML5] フルスクリーンの開始と解除 対象ページのheadタグ内に以下のmetaタグを記述します。 <!-- iOS用 --> <meta name="apple-mobile-web-app-capable" content="yes"> <!-- Android用 --> <meta name="mobile-web-app-capable" content="yes"> 対象ページへのショートカットをホーム画面に追加し、ホーム画面から対象ページに移動するとアドレスバーが表示されなくなります。 AndroidのChromeブラウザであれば、対象ページを開いた状態でブラウザのメニューから「ホーム画面に追加」を選択することでショートカットを作成できます。 作成したショートカットから対象ページに移動するとアドレスバーが非表示になります。 (スクショ撮るのにXperia 1を使ってるので画面が長い。。。) アドレスバーが非表示になりました。 ちなみに、普通に表示したとき(アドレスバーあり)はこんな感じです。 Androidを例にしましたが、iOSでも同様です。 おわりに Android/iOSのWebブラウザのアドレスバーを非表示にすることで、Webアプリをネイティブアプリっぽくすることができました。 初めからネイティブアプリで作っていれば、こんなことに煩わされなくて済むんですけどね。 モバイルアプリ開発の知見がまだないので、時間があるときにUdemyあたりで勉強してみようと思います。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

SwiftUI Tutorial の復習

記事の内容 SwiftUI Tutorial の復習 アプリの内容 阪急神戸線の駅一覧 駅一覧のデータは JSON で用意した JSON をアプリで解析する 駅周辺の地図と駅名・駅ナンバーを表示 iPhoneSE(2nd Generation) ライトモード iPhoneSE(2nd Generation) ダークモード Mac 開発環境 ハードウエア 項目 PC MacBook Air(M1,2020) メモリ:16GB ストレージ:1TB 実機 iPhoneSE(2nd Generation 128GB iOS 15.3.1) PCと実機を接続する USB-C Digital AV Multiportアダプタ ソフトウエア 項目 言語 Swift 5.5.2 IDE Xcode Ver 13.2.1 その他 Visual Studio Code Ver 1.64.2 バージョン管理 GitHub サンプルデータ(JSON)を作成する際の注意点 JSON のキーと Codable のプロパティの表記を揃える Codable Station.swift struct Station: Hashable, Codable, Identifiable { var id: String var name: String var nameEnglish: String var latitude: String var longitude: String // メソッド等は省略 } 正しいサンプルデータ(JSON) JSON [ { "id": "01", "name": "大阪梅田", "nameEnglish": "Osaka-umeda", "latitude": "34.705326", "longitude": "135.498398" }, { "id": "02", "name": "中津", "nameEnglish": "Nakatsu", "latitude": "34.709851", "longitude": "135.492499" } ] Codable のプロパティと表記が一致しないためエラーが発生する JSON [ { "ID": "01", "駅名": "大阪梅田", "駅名(英語)": "Osaka-umeda", "緯度": "34.705326", "経度": "135.498398" }, { "ID": "02", "駅名": "中津", "駅名(英語)": "Nakatsu", "緯度": "34.709851", "経度: "135.492499" } ] NavigationLink は NavigationView の中に書く StationListView.swift import SwiftUI struct StationListView: View { var body: some View { NavigationView { List(stations){ station in NavigationLink { StationDetail(station: station) } label: { StationRow(station: station) } } .navigationTitle("阪急神戸線") // navigationTitle は List の } 直後に書く } } } struct StationListView_Previews: PreviewProvider { static var previews: some View { StationListView() } }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Flutter-iOS】【GithubActions】flutterのCD環境を整備してみた

はじめに 普段仕事ではiOSアプリを開発していますが、 昨年5月頃からFlutterに興味を持ち始め、趣味の時間でFlutterアプリの勉強を始めました。 アプリの配信は毎回手間に感じていて自動化できないか?と調査をしていた内容を共有します。iOS編とAndroid編で分けようと思っていて、今回はiOS編です。 目標 「Githubにコードがpushされたときに、iOSアプリをTestFlightへのビルドのアップロードする。」 ことが目標です。 TestFlightへのアップロードが自動化できるだけでもかなり作業が楽になると思います。 Storeにビルド配信する。 では作業を開始します。 最終的なフォルダ構成 今回追加するファイル、フォルダを含めた最終的なフォルダの構成です。 . ├── .github │ └── workflows │ └── cd_ios.yml・・・・iOS用githubActionsの設定ファイル ├── ios │ └── fastlane │ ├── Appfile・・・・Store関係の設定が書かれたファイル │ ├── Fastfile・・・・fastlaneの設定ファイル │ └── Matchfile・・・証明書関係の設定が書かれたファイル └── 以下省略 注意!! ~今回説明しないもの~ 申し訳ないのですが、今回は以下の環境設定方法については省略します。 - AppStore(deveploper)の登録や設定方法 - Githubの登録や設定方法 - GithubActionsの知識 作業の流れ fastlaneを用意する Storeに配信するための設定 Fastfileを設定する github actionsを準備 あとはコミット!! 1. fastlaneを用意する ※作業ディレクトリは、/ios/ で実施します。 今回は署名の管理や面倒なビルドコマンドの省略のためにfastlaneを使用しました。 (xcodebuildやgradleなどのコマンド、flutterのコマンドからでもビルドが作成できれば、それでも良いと思います) fastlaneには多くの便利な"アクション"が定義されています。アプリのビルドであったり、配信であったり、単体テストなども、fastlaneに定義されているアクションを利用可能です。 1-0. 証明書を管理するリポジトリを用意する 証明書を管理するためのリポジトリを用意します。 もちろん証明書と開発用のソースコードを一緒に管理することも可能です。 1-1. fastlaneを準備する fastlaneは、iOSアプリ開発 及び Androidアプリ開発をサポートするツールです。 https://docs.fastlane.tools/ fastlaneの導入は以下のコマンドより実行します。 xcode-select --install sudo gem install fastlane -NV fastlane init fastlane/にファイルが作成されたでしょうか? 作成されたAppfileやFastfileに設定を書き加えていきます。 1-2. fastlaneでmatchを使う fastlaneは、4つの署名方法があります。 https://docs.fastlane.tools/codesigning/getting-started/ 今回はmatchを使います。 ・match について matchはprivate keysと証明書をgit リポジトリー上に管理する。 端末間で証明書を共有できる(githubActions上の端末も然り、エンジニア間でも共有可能!) なお、match以外の方法は選択しませんでした。 一応、他の方法と自分が使わないと判断した理由を記載しますが、もし判断が違うなどあればコメントください! ・certとsighを使う方法・・・この方法の場合は現行の証明書ファイルをrevokeしたくないなら使うとある。が、今回はgithub上でビルドからリリースまでを行いたい。certとsighは、どちらもlocal環境に証明書ファイル、プロビジョニングプロファイルがあれば有効な方法になるが、今回はremoteのため選択しなかった。 ・XCodeのAuto Signingを使う方法・・・この方法はXCodeのAuto Siginingを使用する方法になるが、公式サイトにも記載されるように、自分が使用したいプロビジョニングプロファイルが選択されるとは限らないため選択しなかった。 ・Manualで行う方法・・・この方法は、Apple Developer Portalから証明書ファイルやプロビジョニングプロファイルを操作してビルド環境を構築するが、p12ファイルを適切に管理することなどが記載されており、remote環境には不向きと判断して選択していない。 【参考】 fastlane matchの簡易使い方 fastlane match を使用して iOS の証明書管理を行う iOSアプリ開発自動テストの教科書 1-3. Matchfileの作成 matchの設定はMatchfileに記載します。そのためのMatchfileを作成します。 fastlane match init 上記を実行します。コマンド実行後にいくつか質問されます。  storageは何を使うか?→今回はgit管理と思うので「1.git」を選びます。  storageのURLは?→「1-0. 【iOS】証明書を管理するリポジトリを用意する」で作成したリポジトリのURLを入力します。「https://」「git」いずれもOKです。 1-4. SSHの設定 githubにはSSH接続をしていると思います。github内で証明書を管理しているリポジトリから証明書情報を取得する際にSSH接続を行うためのいくつかの設定を行います。 basic authorizationの設定 自身の認証情報を元にCD用の認証情報を作成します。 echo -n your_github_username:your_personal_access_token | base64 上記の値をgithub secretsに定義します。「MTACH_GIT_BASIC_AUTHORIZATION」など。 またlocal環境での動作の確認のためにMatchfileに値を設定します。 match(git_basic_authorization: '<YOUR BASE64 KEY>') 上記の設定は、localでの動作確認が終わったら、リポジトリにpushするときには、secretsに定義している変数に戻します。 もし認証情報の取得(echoコマンド)に失敗する場合はgithubのドキュメントを確認してください SSH Key(DeployKey)の生成と設定 もし証明書用のリポジトリを作成していなければ不要です!!! fastlaneがSSH経由でgithubリポジトリから証明書情報を落とすために必要です。 matchで証明書を管理しているリポジトリでDeployKeyを生成します。 公式手順の通りに進めます。 この時に生成するKeyにはCIから接続するためパスフレーズを設定しないようにして下さい。 上記の手順に従って、作成された「公開鍵」を、Github上のDeployKeyとして設定します。権限はRead権限で良いと思います。 作成された「公開鍵」は、Github上のDeployKeyとして設定します。 作成された「秘密鍵」は、Github上のSecretsに設定します。例えば「SSH_PRIVATE_KEY」など。 【参考記事】GitHub ActionsでPrivate RepositoryをSSH接続でnpm installしてハマった話 1-5. 証明書の作成 matchで使用する証明書を作成します。 ここで作成する証明書が暗号化されてリポジトリ上で管理されます。 fastlane match appstore 上記のコマンドを実行するとmasterブランチに「/cert」「/profile」が作成、それぞれ暗号化された証明書とプロビジョニングプロファイルが作成されます。 ここでstorageのPASSWORDを設定しますが、この設定値は後ほどGithubSecrets上に定義するので控えておいて下さい。 また、AppleDeveloper上でも証明書とプロビジョニングプロファイルが作成されていることを確認できます。matchから始まるものがそれです。 1-6. 【iOS】Matchfileの設定の確認 ここまでの作業でMatchfileの設定不足がないか、確認します。 以下の設定があればOKです。 git_url("{証明書を管理しているリポジトリのURL}") storage_mode("git") type("appstore") app_identifier(["{bundleIdentifer}"]) username("{APPLE ID(Developer potalにログインするやつ)}") 2. Storeに配信するための設定 いよいよfastlaneを使って、ビルドから配信を行うまでの設定を行います、fastlaneの細かな設定はFastfileで行います。 と、、その前に更にいくつかの設定を行います。Storeに配信するための設定です。 2-1. AppStoreConnect APIの設定 iOSの配信はupload_to_testflightを使います。 このアクションの説明でも述べられていますが、GithubActionsでiOSを自動ビルドしたときに、課題となるのが「2FA」です。 Developerログインで2FAを設定していない場合は関係ないですが。。。そういった人は少ないと思ってます。 2FAを回避する方法は、 AppStoreConnect API(推奨) fastlane spaceauth で FASTLANE_SESSION を発行して利用する App用パスワードを使う 2FAを無効にする(非推奨) とあるようですが、「fastlane spaceauth」は上手くいかず(設定しても2FAが要求された)、 公式で推奨されている「AppStoreConnect API」を使うこととしました。 APIの作成手順ですが、かなり簡単です。 ただし、"AppleDeveloperでの権限"が"AccountHolder"でないと作成できません。 appstoreconnect を開きます 「ユーザーとアクセス」を開きます 「キー」を選択します 「キータイプ」で「App Store Connect API」を選びます 「+」でキーを作成します。 作成後の画面はこんな感じです。 キーID、IssuerID、APIキー(.p8)の内容をコピーしておきGithub Secretsに設定します。 ※p8ファイルは大事に保管します。 ASC_API_KEY_ID -> キーID ASC_API_ISSUER_ID -> Issuer ID ASC _API _KEY_CONNECT -> APIキーの内容 【参考】 Authenticating with Apple services 2FAが有効なアカウントで fastlane を使ってApp Store Connectへアプリをアップロードする方法 3. Fastfileを設定する fastlaneでは、Fastfileに自動化タスクを「レーン」として定義することで、1コマンド(fastlane {レーン名})でタスクが実行できるようになります。 今回は以下のようなFastfileを用意していました。 「build_testflight」というlaneを用意しています。 githubActionsからは、以下のように呼び出すことができるようになります。 fastlane build_testflight Fastfileの中では、「build_testflight」以外のprivateのlaneを用意しています。 privateのlaneには、ビルド環境準備、ビルド、配信をそれぞれ用意することにしました。 設定内容なのですが、公式ドキュメントを参考に値を変更しながらfastfileの設定値を決めています。 今後のXCodeやfastlane、AppStoreの仕様変更によって、設定内容が変わる可能性があります。 default_platform(:ios) platform :ios do desc "testflight配信" lane :build_testflight do prepareBuild buildIpa deployTestFlight end end ############### # private lane ############### private_lane :prepareBuild do # CIにはデフォのキーチェーンがないため新規作成 create_keychain( name: ENV['MATCH_KEYCHAIN_NAME'], password: ENV['MATCH_KEYCHAIN_PASSWORD'], timeout: 1800 ) # apikeyの設定 api_key = app_store_connect_api_key( key_id: ENV['ASC_API_KEY_ID'], issuer_id: ENV['ASC_API_ISSUER_ID'], key_content: ENV['ASC_API_KEY_CONNECT'], in_house: false ) # アクションの呼び出し match(api_key: api_key, type: "appstore", readonly: true, git_basic_authorization: ENV['MATCH_GIT_BASIC_AUTHORIZATION']) # Manualに変更https://docs.fastlane.tools/actions/update_code_signing_settings/ update_code_signing_settings( path: "Runner.xcodeproj", use_automatic_signing: false, team_id: ENV['TEAM_ID'], code_sign_identity: "Apple Distribution", profile_name: "match AppStore *", bundle_identifier: "com.hoge.hoge" ) end private_lane :buildIpa do # https://docs.fastlane.tools/actions/build_ios_app/ build_ios_app( workspace: "Runner.xcworkspace", scheme: "Runner", configuration: "Release", clean: true, output_directory: "build", output_name: "hogehoge.ipa", export_method: "app-store" ) end private_lane :deployTestFlight do upload_to_testflight(skip_submission: true) end 以下がGithubSecretsに定義する内容です。 MATCH_KEYCHAIN_NAME:githubで立ち上げるmacのKeychainの設定です。特に指定はないため自由に設定してください。 MATCH_KEYCHAIN_PASSWORD:githubで立ち上げるmacのKeychainの設定です。特に指定はないため自由に設定してください。 ASC_API_KEY_ID:AppStoreConnectAPIKeyのKeyのIDを設定します。 ASC_API_ISSUER_ID:AppStoreConnectAPIKeyのISSUERのIDを設定します。 ASC_API_KEY_CONNECT:AppStoreConnectAPIKeyのp8ファイルの中身を設定します。 MATCH_GIT_BASIC_AUTHORIZATION:GithubへのPersonalAccessTokenから生成して下さい。 TEAM_ID: Apple Developerにログインして、Membershipより、TeamIdを確認してください。 補足 fastlaneでキーチェーンの設定がないことを怒られました。 72[14:03:12]: Checking out branch master... 73[14:03:12]: ? Successfully decrypted certificates repo 74[14:03:12]: Verifying that the certificate and profile are still valid on the Dev Portal... 75[14:03:12]: Installing certificate... 76[14:03:13]: There are no local code signing identities found. 77You can run `security find-identity -v -p codesigning` to get this output. 78This Stack Overflow thread has more information: https://stackoverflow.com/q/35390072/774. 79(Check in Keychain Access for an expired WWDR certificate: https://stackoverflow.com/a/35409835/774 has more info.) こちらを参考にして以下の処理を追加することで解決しています。 # CIにはデフォのキーチェーンがないため新規作成 create_keychain( name: ENV['MATCH_KEYCHAIN_NAME'], password: ENV['MATCH_KEYCHAIN_PASSWORD'], timeout: 1800 ) 【参考】 fastlane docs/upload_to_testflight 4. github actionsを準備 ルートの直下に、以下の構成でファイルを用意します。 .github/workflows/{githubActionsの設定ファイル名}.yml yamlファイルの中身は以下を設定しました。 # This is a basic workflow to help you get started with Actions name: CD_iOS on: push: branches: [ master ] workflow_dispatch: jobs: # This workflow contains a single job called "build" ios_distribution: runs-on: macos-11 if: | contains(github.event.head_commit.message, '[Release]') == true && contains(github.event.head_commit.message, '[iOS]') == true name: Distribution(iOS) steps: - uses: actions/checkout@v2 - name: Show Xcode list run: ls /Applications | grep 'Xcode' - name: Select Xcode version run: sudo xcode-select -s '/Applications/Xcode_13.2.app/Contents/Developer' - name: Setup flutter uses: subosito/flutter-action@v1 with: flutter-version: '2.5.3' - name: Set up tools run: | flutter pub get - name: ExportPath run: | export PATH=$PATH:${FLUTTER_HOME}/bin/cache/dart-sdk/bin export PATH=$PATH:${FLUTTER_HOME}/.pub-cache/bin - name: Pod cache uses: actions/cache@v2 with: path: Pods key: ${{ runner.os }}-pods-${{ hashFiles('**/Podfile.lock') }} restore-keys: | ${{ runner.os }}-pods- - name: Pod Install if: steps.cache-cocoapods.outputs.cache-hit != 'true' run: | cd ios/ pod install # fastlaneで必要なため、SSHキーのセットアップをする. - name: Setup SSH Keys and known_hosts for fastlane match # Copied from https://github.com/maddox/actions/blob/master/ssh/entrypoint.sh run: | SSH_PATH="$HOME/.ssh" mkdir -p "$SSH_PATH" touch "$SSH_PATH/known_hosts" echo "$PRIVATE_KEY" > "$SSH_PATH/id_ed25519" chmod 700 "$SSH_PATH" ssh-keyscan github.com >> ~/.ssh/known_hosts chmod 600 "$SSH_PATH/known_hosts" chmod 600 "$SSH_PATH/id_ed25519" eval $(ssh-agent) ssh-add "$SSH_PATH/id_ed25519" env: # 秘匿情報の受け渡し PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }} - name: Run build and Deploy (fastlane) run: | cd ios/ ls fastlane build_testflight env: MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }} TEAM_ID: ${{ secrets.TEAM_ID }} FASTLANE_PASSWORD: ${{ secrets.FASTLANE_PASSWORD }} MATCH_KEYCHAIN_NAME: ${{ secrets.MATCH_KEYCHAIN_NAME }} MATCH_KEYCHAIN_PASSWORD: ${{ secrets.MATCH_KEYCHAIN_PASSWORD }} MATCH_GIT_BASIC_AUTHORIZATION: ${{ secrets.MATCH_GIT_BASIC_AUTHORIZATION }} ASC_API_KEY_ID: ${{ secrets.ASC_API_KEY_ID }} ASC_API_ISSUER_ID: ${{ secrets.ASC_API_ISSUER_ID }} ASC_API_KEY_CONNECT: ${{ secrets.ASC_API_KEY_CONNECT }} こちらもGithubSecrets上に環境変数を定義します。 SSH_PRIVATE_KEY:matchで証明書管理しているリポジトリへのDeployKeyの値を設定します。 MATCH_PASSWORD:matchの証明書をdecryptを行うときのパスワードを設定します。 FASTLANE_PASSWORD:ApppleIDのパスワードを設定します。 簡単な説明 flutterのリポジトリのため、コミットメッセージに[Release]と[iOS]がある場合にTestFlightへのアップロードを行うこととしました。 if: | contains(github.event.head_commit.message, '[Release]') == true && contains(github.event.head_commit.message, '[iOS]') == true githubActions上では実行環境のOSを設定する必要がありますが、iOSアプリの場合はmacOSが必要なため、macOSを設定します。 runs-on: macos-11 XCodeのlistをログ出力するようにしています。githubActions上のmacOSでどのXCodeが利用できるかを確認するためです。XCodeのバージョンアップがあった時などに、ログ出力しておくと役立ちます。 - name: Show Xcode list run: ls /Applications | grep 'Xcode' Podに関する以下のエラーが発生したため、「Pod install」のjobを追加して解決しました。 エラー: error: Unable to load contents of file list: '/Target Support Files/Pods-Runner/Pods-Runner-resources-Release-output-files.xcfilelist' (in target 'Runner' from project 'Runner') - name: Pod cache uses: actions/cache@v2 with: path: Pods key: ${{ runner.os }}-pods-${{ hashFiles('**/Podfile.lock') }} restore-keys: | ${{ runner.os }}-pods- - name: Pod Install if: steps.cache-cocoapods.outputs.cache-hit != 'true' run: | cd ios/ pod install flutterの設定を行なってからgithubActions上でCDを実行したところ以下のエラーが発生したため、 をpub get のjobを追加して解決できました。 エラー: Invalid `Podfile` file: /Users/runner/work/hoge/huge/ios/Flutter/Generated.xcconfig must exist. If you're running pod install manually, make sure flutter pub get is executed first. - name: Setup flutter uses: subosito/flutter-action@v1 with: flutter-version: '2.5.3' - name: Set up tools run: | flutter pub get - name: ExportPath run: | export PATH=$PATH:${FLUTTER_HOME}/bin/cache/dart-sdk/bin export PATH=$PATH:${FLUTTER_HOME}/.pub-cache/bin 5. あとはコミット。祈るだけ。 あとはコミットしてみて祈るだけです。 よくあるエラーは、 ERROR ITMS-90189: "Redundant Binary Upload. You've already uploaded a build with build number こちらは、同一バージョンでUploadしているためエラーとなっています。バージョン番号を更新して再度実行します。 おまけ deploygateへの配信も試してみていました。 private_lane :deployToDeploygate do # http://docs.fastlane.tools/actions/deploygate/#deploygate # 配布ページのhashを入れるとそこを更新してくれる! deploygate( api_token: ENV['DEPLOYGATE_API_TOKEN'], user: "USERNAME", ipa: "./build/sample_cd_debug.ipa", message: "Deploygate test", distribution_key: "ENV['DEPLOYGATE_DIST_KEY']" ) end こちらもGithubSecrets上に環境変数を定義しています。 - DEPLOYGATE_API_TOKEN:Deploygateのページで自身のアカウントページにあるAPIKeyを設定してます。 - DEPLOYGATE_DIST_KEY:Deploygateで配布ページを作っている場合、そのページの末尾のハッシュ値を設定してください。もし配布ページを用意していない場合は設定不要です。 【参考】fastlaneでアップロード さいごに お疲れ様でした。 今回の記事が皆さんのflutterのCD環境の環境構築に役立てば幸いです。 iOSの環境構築では2FAの回避のところ、Keychainの設定が必要だということ、が解決に時間がかかった箇所です。 一度環境構築の方法がわかれば、以後どのFlutter / iOS nativeのプロジェクトがあっても役に立つと思うので、まずはTestFlightのビルドアップロードまで、本記事がお役に立てば幸いです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【SwiftUI】Toggleを用いてチェックボックスを作る

SwiftUIでチェックボックスを実装する方法の1つとして、ToggleStyleのカスタムクラスを追加する方法があります。 ToggleStyleとは、Toggleの外観と動作を定義するモディファイアです カスタムクラスを実装する struct CheckboxStyle: ToggleStyle { func makeBody(configuration: Configuration) -> some View { // チェックボックスの外観と動作を返す return HStack { Image(systemName: configuration.isOn ? "checkmark.circle.fill" : "circle") .foregroundColor(configuration.isOn ? .blue : .black) .font(.system(size: 28, weight: .semibold, design: .rounded)) configuration.label } .onTapGesture { configuration.isOn.toggle() } } } configurationからisOnやlabelが取得できるので、Toggleがオンとオフの時の外観をmakeBody(configuration:)に書いています。 onTapGestureを追加してタップされた時にisOnを更新します。 カスタムスタイルを指定する @State private var isChecked: Bool = false var body: some View { Toggle(isOn: $isChecked) { Text("チェックボックス") .font(.system(.title2, design: .rounded)) .fontWeight(.heavy) .foregroundColor(isChecked ? .blue : .black) .padding(.vertical, 12) } .toggleStyle(CheckboxStyle()) } .toggleStyleに作成したカスタムクラスを指定します。 実行結果 isOn = false isOn = true makeBody(configuration:)の返すViewを変更することで色々な見た目のチェックボックスを実装することができます。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

torchvisionの画像分類モデルをCoreMLに変換する

事前トレーニング済みモデルをCoreMLの画像分類モデルに変換してiOSで使う方法です 画像分類モデルを変換したい そのままTorchVisionの画像分類モデルを変換すると、出力は1000の数値になります。 これを、信頼度のパーセンテージに直し、画像分類モデルとしてプレビューできるようにしたい。 クラス名とソフトマックス層を追加する クラス名とソフトマックス層を追加すれば、1000クラス内のクラスごとの信頼度のパーセンテージが得られ、xcodeのプレビューも使えます。 方法 torchvisionからモデルをダウンロード。 import torchvision.models as models regnet_y_400mf = models.regnet_y_400mf(pretrained=True) %表示のためにソフトマックス層を追加したラッパーモデルクラスを作る。 import torch.nn as nn class RegNetClassificationModel(nn.Module): def __init__(self): super(RegNetClassificationModel, self).__init__() self.layers = nn.Sequential( regnet_y_400mf, nn.Softmax(dim=1) ) def forward(self, x): return self.layers(x) model = RegNetClassificationModel().eval() ImageNetのクラスラベルをダウンロードして、リストにし、リストからCoreMLのClassifierConfigを作る。 import urllib import coremltools as ct label_url = 'https://storage.googleapis.com/download.tensorflow.org/data/ImageNetLabels.txt' class_labels = urllib.request.urlopen(label_url).read().splitlines() class_labels = class_labels[1:] # remove the first class which is background assert len(class_labels) == 1000 for i, label in enumerate(class_labels): if isinstance(label, bytes): class_labels[i] = label.decode("utf8") classifier_config = ct.ClassifierConfig(class_labels) 変換。 ex_input=torch.randn((1,3,224,224)) traced = torch.jit.trace(model,ex_input) mlmodel = ct.convert(traced,inputs=[ct.ImageType(shape=ex_input.shape,bias=[-0.485/0.229,-0.456/0.224,-0.406/0.225],scale=1.0/255.0/0.226)],classifier_config=classifier_config) mlmodel.save("regnet_y_400mf.mlmodel") これでXcodeでプレビューできます。 iOSでの使い方 let model = try! regnet_y_400mf(configuration: MLModelConfiguration()).model let vnModel = try! VNCoreMLModel(for: model) let request = VNCoreMLRequest(model: vnModel) let handler = VNImageRequestHandler(ciImage: ci1, options: [:]) try! handler.perform([request]) let result = request.results?.first as! VNClassificationObservation print(result.identifier,result.confidence) king penguin 0.61... ? フリーランスエンジニアです。 お仕事のご相談こちらまで rockyshikoku@gmail.com Core MLやARKitを使ったアプリを作っています。 機械学習/AR関連の情報を発信しています。 Twitter Medium
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む