Citrus-Field TECH BLOG.

フリーランスのITエンジニア、iOSアプリの個人開発、業務委託(小売、ヘルスケア)を行っています。お仕事については、メールもしくはXのDMでご相談ください

iOS開発環境の構築を半自動化するヒント

環境構築めんどくさいですよね。 だからシェルを流してバババってやりたいと思っています。

osascriptとはAppleScriptを実行するためのコマンドです

まずはカレントディレクトリでのシェル

#!/bin/sh

echo "\n**********************"
echo "Xcodeのセットアップ"
echo "************************\n"
xcode-select --install


echo "\n**********************"
echo "Homebrewのインストール"
echo "************************\n"
which -s brew
if [[ $? != 0 ]] ; then
    # Install Homebrew
    /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
else
    brew update
fi


echo "\n**********************"
echo "Carthageのインストール"
echo "************************\n"
which -s carthage
if [[ $? != 0 ]] ; then
    brew install carthage
else
    echo "Carthage Found, Skipping Install. \n"
    echo "Updating Carthage if Necessary. \n"
    brew upgrade carthage
fi


echo "\n**********************"
echo "Checking for SwiftFormat and SwiftFormat Plugin for Xcode"
echo "(you can access from xcode→editor→swift format menu item)"
echo "************************\n"
which -s swiftformat
if [[ $? != 0 ]] ; then
    brew install swiftformat
    brew install --cask swiftformat-for-xcode
else
    brew upgrade swiftformat
    brew upgrade --cask swiftformat-for-xcode
fi


echo "\n**********************"
echo "Xcode用SwiftFormatとSwiftFormatプラグインのチェック"
echo "(xcodeの[editor]-[swift format menu item]で確認できます"
echo "************************\n"
which -s swiftlint
if [[ $? != 0 ]] ; then
    brew install swiftlint
    brew install --cask swiftformat-for-xcode
else
    brew upgrade swiftlint
    brew upgrade --cask swiftformat-for-xcode
fi

# SwiftLintForXcodeのファイルが残っている場合は、ダウンロードを続行する前に削除
rm "SwiftLintForXcode.zip"

# SwiftFormat xcode プラグインをダウンロード
wget https://github.com/norio-nomura/SwiftLintForXcode/releases/download/0.1/SwiftLintForXcode-0.1.zip -O SwiftLintForXcode.zip


# 前のバージョンがインストールされている場合は上書き
unzip -o SwiftLintForXcode.zip -d /Applications/

sleep 1;

# SwiftLintForXcodeのファイルを削除
rm "SwiftLintForXcode.zip"

open -a Finder /Applications/SwiftLintForXcode.app;

sleep 3;

# xcodeで使用する前に、これらのアプリを一度開く必要がある
open ".swiftformat" -a "SwiftFormat for Xcode";
osascript -e 'tell application "Terminal" to activate'; sleep 3;  osascript -e 'tell application "SwiftFormat for Xcode" to quit';

open -a "SwiftLintForXcode";
osascript -e 'tell application "Terminal" to activate'; sleep 3;  osascript -e 'tell application "SwiftLintForXcode" to quit';


# プラグインを有効にする
osascript -e 'tell application "System Preferences" to activate'
osascript -e 'tell application "System Preferences" to set current pane to pane "com.apple.preferences.extensions"'
osascript -e 'display alert "Please Check `SwiftFormat` to Enable  XcodePlugin!"'

echo "\n**********************"
echo "初期設定完了"
echo "************************\n"

そのあと、プロジェクフォルダに移動して以下を実行します

cd [プロジェクフォルダ]

#!/usr/bin/env sh

if ! command -v carthage > /dev/null; then
  printf 'Carthage is not installed.\n'
  printf 'See https://github.com/Carthage/Carthage for install instructions.\n'
  exit 1
fi

set -euo pipefail

xcconfig=$(mktemp /tmp/static.xcconfig.XXXXXX)
trap 'rm -f "$xcconfig"' INT TERM HUP EXIT

CURRENT_XCODE_VERSION=$(xcodebuild -version | grep "Build version" | cut -d' ' -f3)
echo "EXCLUDED_ARCHS__EFFECTIVE_PLATFORM_SUFFIX_simulator__NATIVE_ARCH_64_BIT_x86_64__XCODE_1500__BUILD_$CURRENT_XCODE_VERSION = arm64 arm64e armv7 armv7s armv6 armv8" >> $xcconfig

echo 'EXCLUDED_ARCHS__EFFECTIVE_PLATFORM_SUFFIX_simulator__NATIVE_ARCH_64_BIT_x86_64__XCODE_1500 = $(EXCLUDED_ARCHS__EFFECTIVE_PLATFORM_SUFFIX_simulator__NATIVE_ARCH_64_BIT_x86_64__XCODE_1500__BUILD_$(XCODE_PRODUCT_BUILD_VERSION))' >> $xcconfig
echo 'EXCLUDED_ARCHS = $(inherited) $(EXCLUDED_ARCHS__EFFECTIVE_PLATFORM_SUFFIX_$(EFFECTIVE_PLATFORM_SUFFIX)__NATIVE_ARCH_64_BIT_$(NATIVE_ARCH_64_BIT)__XCODE_$(XCODE_VERSION_MAJOR))' >> $xcconfig

export XCODE_XCCONFIG_FILE="$xcconfig"
carthage "$@"
# Workaround for Carthage build error END

carthage bootstrap --platform iOS --cache-builds --no-use-binaries

抜け、漏れがあるかもしれません Carthageや、その他、プロジェクトに応じて、修正してみてください。

Play Console 要件対応、D-U-N-S ナンバー登録を行う。

Androidアプリのリリースに、D-U-N-S ナンバー(DUNS ナンバー)が必要になりました。

詳しくは、以下に記載されています。

support.google.com

 

これまでも、Apple Bussiness Manager対応などで企業様のD-U-N-Sナンバーを聞くことはありましたが、私のような個人事業主のアプリ屋がD-U-N-Sナンバーを登録する時代になったということは、悪質アプリ対策の一環だと思います。

D-U-N-S® Numberとは、世界5億件超の企業を一意に識別できる9桁の企業識別コードです。D&Bが独自に管理をしており、国内企業についてはTSRが管理しています。

東京商工リサーチ様より引用

 

D-U-N-Sナンバー取得については、こちらに素晴らしい記事があります。

blog.katsubemakito.net

 

上記の時期では、FAXが必要となっていますが、今も同様か確認したいと思います。また、決済は銀行振り込みらしいので、法人口座も整理しようと思っています。

 

不確定な部分もあるので全て完了したら、この記事を更新したいと思います。

モダンプログラミング言語 vs C言語 - シニアプログラマーの感じた違い

現役ソフトウェアエンジニアが、C言語後発の言語と、どちらが大変か不毛な議論をしていたので、 現役プログラマー目線で比較してみるという不毛な検証をしてみた。

ただ、C言語の開発環境は無いので、現在でも見かける古いコードとモダンプログラミングの違いしか比べるしかできなかったので勘弁して欲しい。

なお、C言語は、命令型プログラミング、構造化プログラミング、手続き型プログラミングなどと言われているが、 それらは後発の言語の登場によって、生まれた概念なので、モダンプログラミングの概念と 何が違っているのかを比べることで楽かどうを決めたい。

プログラミングを生業としているものが開発言語を選べないのは承知の上での不毛な議論である。

比較する言語、フレームワークは手元で確認できる以下4種類を選んだ。

古めの言語、フレームワーク

  • JavaScript
  • Swift+UIKit

モダンな言語、フレームワーク

  • React+TypeScript+NodeJS
  • SwiftUI

上記4種類に限定する。

開発するもの

交通量調査をやっているような人が車の台数を数えるために持っているようなカウンター

それぞれの言語のソースコードと動作

JavaScript
<!DOCTYPE html>
<html lang="jp">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Tap Counter (JavaScript)</title>
</head>
<body>
    <h1 id="countDisplay">Count: 0</h1>
    <button id="incrementButton">Increment</button>
  
    <script>
      // HTML要素を取得
      const countDisplay = document.getElementById('countDisplay');
      const incrementButton = document.getElementById('incrementButton');
  
      // カウントを保持する変数
      let count = 0;
  
      // ボタンがクリックされたときの処理
      incrementButton.addEventListener('click', () => {
        count += 1;
        countDisplay.textContent = `Count: ${count}`;
      });
    </script>
</body>
</html>

動作

www.youtube.com

好印象ポイント

  • ファイル1つに全てが収まる

悪印象ポイント

  • 型定義が弱く下手に触ると動作しなくなる
  • コードにUIとロジックが混ざっていて見づらい
Swift+UIKit
import UIKit

class ViewController: UIViewController {

    // カウントを保持する変数
    var count = 0

    // ラベルとボタンを表示するための変数
    let countLabel: UILabel = {
        let label = UILabel()
        label.font = UIFont.systemFont(ofSize: 24)
        label.textAlignment = .center
        label.text = "Count: 0"
        return label
    }()

    lazy var countButton: UIButton = {
        let button = UIButton(type: .system)
        button.setTitle("Increment", for: .normal)
        button.titleLabel?.font = UIFont.systemFont(ofSize: 20)
        button.addTarget(self, action: #selector(incrementCount), for: .touchUpInside)
        return button
    }()

    override func viewDidLoad() {
        super.viewDidLoad()

        // ラベルとボタンをビューに追加
        view.addSubview(countLabel)
        view.addSubview(countButton)

        // 制約を設定
        setupConstraints()
    }

    // 制約を設定するメソッド
    private func setupConstraints() {
        countLabel.translatesAutoresizingMaskIntoConstraints = false
        countButton.translatesAutoresizingMaskIntoConstraints = false

        NSLayoutConstraint.activate([
            countLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            countLabel.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: -50),

            countButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            countButton.topAnchor.constraint(equalTo: countLabel.bottomAnchor, constant: 20)
        ])
    }

    // ボタンがタップされたときに呼ばれるメソッド
    @objc func incrementCount() {
        count += 1
        countLabel.text = "Count: \(count)"
    }
}

動作

www.youtube.com

好印象ポイント

  • ボタンを押すロジックと、画面を描画するコードがなんとなくわかる

悪印象ポイント

  • コードが長い
  • UIのコードが超絶に見づらい
  • コードにUIとロジックが混ざっていて見づらい
React+TypeScript+NodeJS
import React, { useState } from 'react';

const CounterApp: React.FC = () => {
  // カウントを保持するステート
  const [count, setCount] = useState<number>(0);

  // ステートされたsetCountをインクリメントする
  const incrementCount = () => {
    setCount(count + 1);
  };

  return (
    <div>
      <h1>Count: {count}</h1>
      <button onClick={incrementCount}>Increment</button>
    </div>
  );
};

export default CounterApp;

動作 www.youtube.com

好印象ポイント

  • コードが短い

悪印象ポイント

  • 宣言型プログラミング(or リアクティブプログラミング)のため、どこで画面表示されているか慣れるまで分かりにくい
SwiftUI
import SwiftUI

struct ContentView: View {
    @State private var count = 0

    var body: some View {
        VStack {
            Text("Count: \(count)")
                .font(.largeTitle)
                .padding()

            Button("Increment") {
                count += 1
            }
            .padding()
        }
    }
}

#Preview {
    ContentView()
}

動作

www.youtube.com

好印象ポイント

  • コードが短い

悪印象ポイント

  • 宣言型プログラミング(or リアクティブプログラミング)のため、どこで画面表示されているか慣れるまで分かりにくい

結論

宣言型プログラミングのリアクティブな部分は、それなりにコメントや、仕様書が無いとわかりにくいものの、 その他のモダンプログラミング言語の明示的な型の定義や、コード修正によって意図しない動きを防ぐ安全性などの面で総合的に優れている。

と、今は感じている。

2023年12月Update : Apple Developer Programの証明書を作成する

Apple Developer Programの作成方法、Provisioning Profileの更新方法

Apple Developer ProgramとApple Developer Enterprise Programのメンバーに発行されるDeveloper ID証明書は、アプリを配信する際に使用する、配布用証明書の一種です。

Developer ID証明書でアプリを署名すると、アプリがマルウェアなどでないこと、また第三者によって改ざんされたものでもないことが証明されます。

それでは、アプリ開発や配布に必要な証明書の作成方法を見ていきましょう。

1.キーチェーンアクセスから証明書署名要求(CSR)を作成する

1-1.キーチェーンアクセスを起動

ファインダーで、アプリケーションユーティリティーキーチェーンアクセスを探して、起動します。

キーチェーンアクセスが起動すると、次のような画面が表示されます。

1-2.認証局に証明書を要求を選択

証明書署名要求(CSR)を作成するためには、キーチェーンアクセスのメニューから以下を選択します。

「メニュー」→「キーチェーンアクセス」→「証明書アシスタント」→「認証局に証明書を要求..」

選択すると、「証明書アシスタント」の画面が表示されます。

・証明書アシスタント

・証明書アシスタントで必要情報を入力します

ユーザーのメールアドレス: Apple Developerに登録したApple IDと同じメールアドレス 通称: なんでもよいが覚えやすい名前を入力する CAのメールアドレス: 空白 要求の処理: 「ディスクに保存」を選択 する 「鍵ペア情報を指定」をチェックする

続けるボタンを押す。

「鍵ペア情報」画面が表示されます。

変更せずに、「続ける」ボタンを押す

「設定結果」画面が表示されます。

「完了」ボタンを押す

証明書要求がディスク上に作成されました。

これで証明書のリクエストファイルの作成は完了です。

開発用の証明書を作成する

・Apple Developerサイトへサインイン

・Certificates,Identifiers&Profilesをクリック

・Certificatesの+ボタンを押す

・Create a New Certificate

「Apple Development」を選択

「Cotinne」を押す

「choose File」から証明書のリクエストファイル(CertificateSigningRequest.certSigningRequest)を選択する。

「Cotinne」を押す

開発用証明書の作成完了

「Download」ボタンを押して保存する。

配布用の証明書を作成する

開発用証明書を作成する時と同様、Apple Developerサイトへサインイン

  • development.cer
  • distribution.cer

・ダウンロードした開発用と配布用の証明書をクリックしてMacのキーチェーンに登録します。

Provisioning Profileの更新

・Profiles

更新するProfilesを選択する

・Review Provisioning Profile

「Edit」ボタンを押す

・Certificatesを変更

更新した証明書に「チェック」

「Save」ボタンを押す

・Generate a Provisioning Profile

Downloadして保存します。

Xcodeの「Prefrence」で

「Accounts」から「Download Manual Plofiles」をクリックしてダウンロードして完了です。

Macに開発用証明書(CER)を登録

ダウンロードした開発用証明書(CER)を選択

ダウンロードした、保存先にある「development.cer 」「distribution.cer 」ファイルをダブルクリックし、

キーチェーンアクセスに証明書が登録を行います。

キーチェーンアクセスに読み込めているか確認

読み込まれた「development.cer 」「distribution.cer 」ファイルは、

ログインキーチェーンに登録されているか確認します。

No. ファイル名 内容
1 CertificateSigningRequest.certSigningRequest 証明書署名要求(CSR)
2 development.cer 開発用証明書(CER)
3 distribution.cer 配布用証明書(CER)
4 Push_AdHoc.mobileprovision 検証用アプリのビルドに利用する証明証
5 Push_AppStore.mobileprovision ストア公開する本番アプリのビルドに利用する証明証
6 Push_Develop.mobileprovision 開発・デバッグ用アプリのビルドに利用する証明証
7 証明書.p12 開発用、配布用の個人情報交換ファイル

本番環境でのLog収集を容易にするOSLogの使い方について

はじめに

iOSのログは、古くから存在しますNSLogや、iOS14で導入されましたOSLogなどさまざまなものが存在します。 こういったログ収集はソフトウェア開発において重要な側面であり、開発者がアプリケーションの動作を理解します貴重な情報源です。 OSLogは、macOS、iOS、watchOS、tvOSのログ収集は様々な点で進化していますので、今後はOSLogを使っていきましたいと思っています。 そこで、OSLogの利点、実用的な使用法を理解しましょう。

Appleのリファレンス

https://developer.apple.com/documentation/os/oslog

OSLogsを理解する

最初に注意しておきましたいのは、アップルのOSLogにも、iOS10以降でサポートされましたものと、iOS14、iPadOS14でサポートされましたものがあります。 ここでは、iOS14、iPadOS14でサポートされましたOSLogsについて書いています。

アップルのOSLogは、アップルプラットフォーム全体のログメッセージを合理化し、一元化しますために設計されましたシステム全体のログインフラストラクチャでUnified Logging System(ULS)の一部です。要約すると、アップルのmacOS、iOS、watchOS、tvOSなどでデバイスが変わっても同様に使用できます。

OSLogsの主な利点

1. アップルが提供する統一されたログシステム OSLogはアップルが提供する統一されたログシステムのため、開発者が異なるソースからのログメッセージの統一されたストリームにアクセスすることを可能にし、 システムの動作について全体的な理解に役立ちます。

2. 高速かつ軽量 OSLogは非常に高速で軽量な設計がされており、ログ収集がシステムやアプリケーションのパフォーマンスに与えます影響を最小限に抑えます。 そのため、本番環境やリリースビルドに適しています。

3. プライバシーとセキュリティへの配慮 OSLogsは、Default、Info、Debug、Error、Faultといった異なるログレベルを導入し、開発者が機密情報を適切なレベルでログに記録できるようにしています。 これにより、特定のログエントリが、明示的に要求された場合にのみ表示されるようになります。

OSLogsを使ってみる

それでは、OSLogをアップルアプリケーションで使い始めますための手順を確認しますが、先にサンプルコードを見てみます。

import OSLog

extension Logger {
    /// アプリを特定するユニークな識別子には、アプリ固有のバンドル識別子を設定します
    private static var subsystem = Bundle.main.bundleIdentifier!

    /// ビューサイクルをログに記録する
    static let viewCycle = Logger(subsystem: subsystem, category: "viewcycle")

    /// トラッキングとアナリティクスに関連するすべてのログを記録する
    static let statistics = Logger(subsystem: subsystem, category: "statistics")
}

OSLogはインスタンスにはサブシステム名とカテゴリ名が必要です。 コンソール アプリ内のログをフィルター処理しますときに認識できます、サブシステムの一意の識別子としてバンドル識別子を使用しますことをお勧めします。 インスタンスの生成が完了しますと、さまざまなログレベルの方法のいずれかを使用してログを開始できます。

1. OSLogのインポート

Swiftのコードで OSLogをインポートします。

import OSLog

2. OSLogオブジェクトの作成

OSLog オブジェクトをサブシステム識別子でインスタンス化します。 サブシステム識別子は通常、アプリやフレームワークに固有の逆 DNS 形式の文字列です。

let log = OSLog(subsystem: "com.yourcompanyname.yourappname", category: "general")

3. ログの記録

OSLog が提供するさまざまなログ収集機能を利用して、さまざまなレベルでメッセー ジをログに記録するします。

os_log("This is a default log message", log: log)
os_log("An error occurred: %@", log: log, type: .error, error.localizedDescription)

OSLogsの高度な使い方

ログレベルと重大度

OSLogsのログレベルは、ログメッセージの重要度を表します。これは、開発者が重要度に基づいてログエントリを分類し、優先順位をつけるのに役立ちます。OSLogsを含むAppleのUnified Logging System (ULS)には、いくつかの標準的なログレベルがあります。

以下はその概要です。

1. Default

Defaultレベルは、一般的なメッセージに使用され、一般的に情報的なものです。

os_log("Application started successfully", log: log)

2. Info

Infoレベルは、アプリケーション・フローを追跡するのに有用な、より詳細な情報に使用されます。

os_log("Processing data: %@", log: log, type: .info, data)

3. Debug

Debugレベルは、開発やデバッグには役立つが、本番では詳細すぎるメッセージに使用されます。

os_log("Debugging information: %@", log: log, type: .debug, debugInfo)

4. Error

Errorレベルは、エラーが発生したことを示しますが、アプリケーションの動作に致命的なものではないものも含まれることがあります。

os_log("Error occurred: %@", log: log, type: .error, error.localizedDescription)

5. Fault

Faultレベルは、早急な対応が必要な重大なエラーに使用されます。 これらは、アプリケーションの不安定性につながる深刻な問題です。

os_log("Critical fault: %@", log: log, type: .fault, criticalError.localizedDescription)

ログメッセージの性質と重大性に基づいて、適切なログレベルを選択することができます。 この柔軟性により、特に開発、テスト、本番のような異なる環境において、効果的なログ収集の実践が可能になります。 また、動的なログのフィルタリングを支援し、ユーザーがニーズに基づいてログのレベルを調整できるようにします。

ログのフィルタリングについて

Unified Loggingシステムは、ユーザーが特定のサブシステムやカテゴリーに対するログ収集のレベルを調整できるように、動的なログ・フィルタリングをサポートします。 この機能は、特に本番環境において、収集されるログデータの量を微調整するのに役立ちます。

ログのメタデータをカスタマイズすることについて

カスタム・メタデータでログ・エントリーを拡張し、デバッグや分析時にログ・メッセージのコンテキストを簡単にトレースできるようにします。

os_log("Processing request", log: log, type: .debug, metadata: .dictionary(["RequestID": requestID]))

OSLogsの確認方法

収集されたOSLogsは、「Xcodeのコンソール」や「コンソールアプリ」から確認できます。

OSLogsの有効な利用について

以下の点に注意して、役にたつログ収集を行いましょう。

1. サブシステムとカテゴリーの定義を整理して必要なログを探しやすくする 意味のあるサブシステムとカテゴリー識別子を選択し、アプリケーションに関連するログエントリーの識別とフィルタリングを容易にします。

2. 機密データの慎重な取り扱いに注意する 機密情報をログに記録する際には注意が必要です。さまざまなログレベルを活用して、そのようなデータの可視性を制御し、本番環境でのビルドで機密情報を公開しないようにします。

3. 性能に影響しないように考慮する ログの詳細量とパフォーマンスへの影響のバランスをとる。アプリケーションの効率を損なうことなく、包括的なログ収集を目指しましょう。

まとめ

Apple公式のOSLogsは、OSレベルで統一されたログの一部として、Appleエコシステム全体の開発者に洗練された効率的なログ収集ソリューションを提供します。 OSLogを採用することで、デベロッパはアプリケーションの動作に関する貴重な洞察を得ることができ、デバッグプロセスを強化し、ログの詳細とシステムパフォーマンスのバランスを維持することができます。 OSLogsを活用することで、より堅牢で保守性の高いiOSやiPadOS、さらにはWatchOS、tvOSに対応したアプリを開発できます。 ぜひ技術選定、設計フェーズで検討して頂きたいと思います。

参考にした記事

Logging Made Easy: Exploring Apple’s OSLogs | by Evangelist Apps | Evangelist Apps Blog | Nov, 2023 | Medium

Cyberduckで隠しファイル、隠しフォルダが表示されない時の対処方法

新規インストールしたCyberduckを使い始めて、
リモートファイルの一覧画面に隠しファイル、隠しフォルダが表示されず、
すぐには表示方法が分からなかった。

 

メニューバーより、
[Cyberduck]-[設定]を開き、[環境設定設定-ブラウザ]タブの真ん中あたり、
','で始まるファイルを表示 にチェックを付け、Cyberduckを再起動したら解決した。

ほんの少しだけ、.htaccessファイルを書き換えたかっただけなのに、設定の場所が分からずに困った。