Using Azure CLI

There are two tools az (Azure CLI) and azd (Azure Developer CLI). Both serve different purposes but are complementary to each other.
Azure CLI Azure Developer CLI
Purpose General-purpose command-line tool High-level developer-focused CLI
Use Case Manages Azure resources and configurations. Manages end-to-end Azure workflows and applications.

1. Azure CLI

1.1 Install

Install it:
 brew install azure-cli
Check it works:
az --version
It should show the installed version. As of 2025/01/01 my Azure CLI version is 2.67.0.

1.2 Login

To login do the following command. It will open a browser where you can login. When the login is done it will communicate the CLI.
az login
Since Azure CLI version 2.61.0, you are able to select the Subscription at login time. Just follow the instructions in the CLI and input the number that corresponds to the desired subcription. More in the official docs.

1.3 List Resource Groups

List resorces groups in a nice table. If you prefer the json format just omit --output table.
az group list --output table

2. Azure Developer CLI

2.1 Install

Install it (More in the official docs.):
brew tap azure/azd && brew install azd
Check it works:
azd version

2.2 See help

There are various subcommands like init, up, etc. See a list of them in the help:
azd --help

Flutter installation

This is a summary of what this YouTube video explains. Recommended. Youtube - Install Flutter macOS - Derek Banas

1. Install Flutter

brew install --cask flutter
flutter doctor
flutter upgrade

2. Optional: Install Android Studio

Install Android studio if you plan to target Android devices.
Download latest Android Studio from https://developer.android.com/studio and install Flutter plugin
Settings > Plugins > Flutter In Settings > System Settings
  • In SDK Platforms tab, make sure at least one API level is installed. This is needed for running apps.
  • In SDK Tools tab, make sure Android SDK Command Line Tools (latest) is installed. This is needed by flutter.
  • Set ANDROID_HOME Get your Android sdk location from Android Studio
    echo export ANDROID_HOME="/Users/ignacio/Library/Android/sdk" >> ~/.zshrc
    If needed, restart terminal to get settings applied.
In recent versions of Android Studio jre directory has been renamed to jbr so Flutter gets confused. To solve this we create a link. (Thanks to this Stackoverflow answer!)
cd /Applications/Android\ Studio.app/Contents
ln -s jbr jre
Now Flutter show be able to fully recognize Android, we run the doctor:
flutter doctor -v
flutter doctor --android-licenses
Last step on Android Studio: The first time we create a Flutter project we need to setup Flutter SDK path. We get it from flutter doctor -v command. Just look for a line like this:
• Flutter version 3.7.1 on channel stable at /opt/homebrew/Caskroom/flutter/3.7.0/flutter

3. Optional: Install CocoaPods

I suspect this is only required if you target iOS devices.
brew install cocoapods

4. Final check

At the end we should have everything setup. Run the doctor:
flutter doctor -v

Aggregate target to create xcframework

It has been a while I create an xcframework from scratch so these is hopefully a all-mighty script that will work with a framework target.
Create an aggregate target and add a "Run Script" like below.
set -e

N_SCHEME_NAME=MySchemeNameHere
N_BUILD_DIR="build"
N_IOS_XCARCHIVE="${N_BUILD_DIR}/${N_SCHEME_NAME}-iphoneos.xcarchive"
N_SIM_XCARCHIVE="${N_BUILD_DIR}/${N_SCHEME_NAME}-iphonesimulator.xcarchive"
N_XCFRAMEWORK="${N_BUILD_DIR}/${N_SCHEME_NAME}.xcframework"

rm -rf "$N_BUILD_DIR"

echo "🚀 Building $N_IOS_XCARCHIVE"
xcodebuild archive \
    -scheme "$N_SCHEME_NAME" \
    -archivePath "$N_IOS_XCARCHIVE" \
    -sdk iphoneos \
    BUILD_LIBRARY_FOR_DISTRIBUTION=YES \
    SKIP_INSTALL=NO

echo "🚀 Building $N_SIM_XCARCHIVE" 
xcodebuild archive \
    -scheme "$N_SCHEME_NAME" \
    -archivePath "$N_SIM_XCARCHIVE" \
    -sdk iphonesimulator \
    BUILD_LIBRARY_FOR_DISTRIBUTION=YES \
    SKIP_INSTALL=NO
 
echo "🚀 Building $N_XCFRAMEWORK"
xcodebuild -create-xcframework \
    -framework "${N_IOS_XCARCHIVE}/Products/Library/Frameworks/${N_SCHEME_NAME}.framework" \
    -framework "${N_SIM_XCARCHIVE}/Products/Library/Frameworks/${N_SCHEME_NAME}.framework" \
    -output "${N_XCFRAMEWORK}"

echo "🚀🟢 Build SUCCESS"

Hope it helps.

Convert old FAT .framework to .xcframework

Sometimes when working with old fat frameworks they can cause warnings in Xcode. By using lipo and xcodebuild they can be converted to the new format and Xcode will not complain anymore!

See Usage at the bottom of the script

Note:

In below script bash is required because I use automatic word splitting for REMOVE_FOR_IOS and REMOVE_FOR_SIM expansion. Using word splitting is probably no the best option however simplicity wins here. Specially in a script that is supposed to be executed only a couple of times in the time of our lifes.

#! /bin/bash
# Bash (not zsh) is required for word splitting for REMOVE_FOR_IOS and REMOVE_FOR_SIM inside make_part function

make_part() {
    FRAMEWORK_NAME=${1%.framework}
    TEMP_DIR=$2
    ARCHS_TO_REMOVE=$3

    rm -rf "$TEMP_DIR"
    mkdir $TEMP_DIR
    cp -R "${FRAMEWORK_NAME}.framework" "$TEMP_DIR"
    pushd "${TEMP_DIR}/${FRAMEWORK_NAME}.framework" > /dev/null || return
    #xcrun lipo -info "${FRAMEWORK_NAME}"
    mv "${FRAMEWORK_NAME}" "${FRAMEWORK_NAME}_original" 
    # xcrun lipo "${FRAMEWORK_NAME}_original" -remove i386 -remove x86_64 -output "${FRAMEWORK_NAME}"
    xcrun lipo "${FRAMEWORK_NAME}_original" $ARCHS_TO_REMOVE -output "${FRAMEWORK_NAME}"
    xcrun lipo -info "${FRAMEWORK_NAME}"
    rm "${FRAMEWORK_NAME}_original"
    popd > /dev/null
}

make_xcframework () {
    FRAMEWORK_NAME=${1%.framework}
    REMOVE_FOR_IOS=$2
    REMOVE_FOR_SIM=$3
    DIR_IOS=temp_ios
    DIR_SIM=temp_sim
    
    echo "Processing framework: ${FRAMEWORK_NAME}.framework"

    echo "Creating ios part"
    make_part "$FRAMEWORK_NAME" "$DIR_IOS" "$REMOVE_FOR_IOS"

    echo "Creating simulator part"
    make_part "$FRAMEWORK_NAME" "$DIR_SIM" "$REMOVE_FOR_SIM"

    echo "Creating xcframework"
    rm -rf "${FRAMEWORK_NAME}.xcframework"
    xcodebuild -create-xcframework \
        -framework "${DIR_IOS}/${FRAMEWORK_NAME}.framework" \
        -framework "${DIR_SIM}/${FRAMEWORK_NAME}.framework" \
        -output "${FRAMEWORK_NAME}.xcframework"
    
    rm -rf "$DIR_IOS" "$DIR_SIM"
    #tree "${FRAMEWORK_NAME}.xcframework"
    echo 'OK!'
}

# First parameter: name of the framework to convert
# Second parameter: architectures to remove for ios (device) in the form: "-remove ABC -remove XYZ"
# Third parameter: architectures to remove for ios simulator  in the form: "-remove ABC -remove XYZ"

Examples: 
make_xcframework MyOldFramework.framework "-remove i386 -remove x86_64" "-remove armv7 -remove arm64"
make_xcframework OtherFramework.framework "-remove i386 -remove x86_64" "-remove armv7 -remove arm64"
make_xcframework AnotherFramework.framework "-remove i386 -remove x86_64" "-remove armv7s -remove armv7 -remove arm64"

Using periphery

Periphery is a promissing looking tool for finding dead code!. I have unsuccessfully tried it the past and finally I found a way to build my project correctly with it.

Short explanation, CODE_SIGNING_ALLOWED=NO is set by default however in some xcode projects some files (usually old .frameworks) might have the "Code Sign on Copy" setting set to YES (on Target > Build Phases > Copy files). This kind of projects need CODE_SIGNING_ALLOWED=YES.

Below is an example of my .periphery.yml file:

project: MyProject.xcodeproj
retain_objc_accessible: true
retain_public: true
schemes:
- MyScheme
targets:
- MyTargetTests
- MyTarget
verbose: true
clean_build: true
build_arguments:
- -destination
- platform="iOS Simulator,name=iPhone 8,OS=latest"
- CODE_SIGNING_ALLOWED="YES"

Run it

periphery scan --config .periphery.yml
Default ouput format is xcode which is good for xcode integration and for humans that like to read the terminal. Probably json output is probably easier for integrate with other services like Sonarqube custom issues, etc :)

SwiftUI Notes

I will add a bunch of little notes as I read all the tutorials in the internet. (Yep, ALL the tutorials in the internet)

Ignoring Safe Area

Apparently ignoresSafeArea and edgesIgnoringSafeAreaboth do the same.
let colors = [Color.init(red: 0.1, green: 0.1, blue: 0.6), Color.blue]
LinearGradient(gradient: Gradient(colors: colors), startPoint: .topLeading, endPoint: .bottomTrailing)

// This is the preferred way: `@available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *)`
.ignoresSafeArea(SafeAreaRegions.all, edges: [Edge.Set.top, .bottom])

// Header says deprecated: `@available(iOS, introduced: 13.0, deprecated: 100000.0, message: "Use ignoresSafeArea(_:edges:) instead.")`
.edgesIgnoringSafeArea(Edge.Set.all)

'kSecUseNoAuthenticationUI' is deprecated: first deprecated in iOS 9.0 - Use kSecUseAuthenticationUI instead.

This is a very old warning found in some old versions of some old libraries.
I just copy the link of of what it should a fix should look like: AWSUICKeyChainStore fix
- query[(__bridge __strong id)kSecUseNoAuthenticationUI] = (__bridge id)kCFBooleanTrue;
+ query[(__bridge __strong id)kSecUseAuthenticationUI] = (__bridge id)kSecUseAuthenticationUIFail;

This work is licensed under BSD Zero Clause License | nacho4d ®