diff --git a/ios/README.md b/ios/README.md new file mode 100644 index 0000000..d2f6fa3 --- /dev/null +++ b/ios/README.md @@ -0,0 +1,8 @@ +今回の./ios (social-app)開発の要点をまとめます。 + +1. MITのライセンスを遵守すること、iosアプリとして出品しても問題ないようにすること +https://raw.githubusercontent.com/bluesky-social/social-app/refs/heads/main/LICENSE + +2. "Bluesky"という名称を使用しないこと。アイコンの変更。リンクの変更 + +3. selfhostでも動くこと。本来のsocial-appは動きませんので、これは不便なのでiosアプリに出品することにしました。なお、これはすでにpatchで実現しています。 diff --git a/ios/app.config.patch.js b/ios/app.config.patch.js index 136a4d9..f8fd036 100644 --- a/ios/app.config.patch.js +++ b/ios/app.config.patch.js @@ -1,9 +1,8 @@ // Aiat app configuration overrides module.exports = { - name: 'Aiat', - slug: 'aiat', - scheme: 'aiat', - owner: 'syui', // Your Expo account - bundleIdentifier: 'ai.syui.at', - // Icon will be set separately + name: 'syuis', + slug: 'syuis', + scheme: 'syuis', + owner: 'syui', + bundleIdentifier: 'is.syu' } diff --git a/ios/bin/build.zsh b/ios/bin/build.zsh deleted file mode 100755 index d1fe8ea..0000000 --- a/ios/bin/build.zsh +++ /dev/null @@ -1,44 +0,0 @@ -#!/bin/zsh -set -e - -d=~/ai/at/repos/social-app -APP_NAME=Aiat -PKG=aiat -TEAM_NAME= -TEAM_ID= -CERT="Apple Distribution: ${TEAM_NAME} (${TEAM_ID})" -MAIL=user@example.com -KEY_CHAIN=EXAMPLE - -cd $d -# npx expo prebuild --clean -# cd ios && pod install && cd .. - -## アーカイブ -xcodebuild -workspace ios/${PKG}.xcworkspace \ - -scheme ${PKG} \ - -configuration Release \ - -archivePath build/${APP_NAME}.xcarchive \ - -allowProvisioningUpdates \ - archive - -cd build - -# IPA作成 -rm -rf Payload ${APP_NAME}.ipa -mkdir -p Payload -cp -R ${APP_NAME}.xcarchive/Products/Applications/${PKG}.app Payload/ -cp ../store.mobileprovision Payload/${PKG}.app/embedded.mobileprovision - -# entitlements抽出 -security cms -D -i Payload/${PKG}.app/embedded.mobileprovision > /tmp/profile.plist -/usr/libexec/PlistBuddy -x -c "Print :Entitlements" /tmp/profile.plist > /tmp/entitlements.plist - -codesign -f -s "$CERT" Payload/${PKG}.app/Frameworks/*.framework 2>/dev/null || true -codesign -f -s "$CERT" --entitlements /tmp/entitlements.plist Payload/${PKG}.app - -zip -r ${APP_NAME}.ipa Payload - -xcrun altool --upload-app -f ${APP_NAME}.ipa -t ios -u "${MAIL}" -p "@keychain:${KEY_CHAIN}" - -echo "Upload complete" diff --git a/ios/bin/install.zsh b/ios/bin/install.zsh deleted file mode 100644 index 2e372c7..0000000 --- a/ios/bin/install.zsh +++ /dev/null @@ -1,86 +0,0 @@ -#!/bin/zsh - -if [ "$1" = "social-app-custom" ];then - at-social-app-custom-pages - at-social-app-custom-screens - at-social-app-aiat-config - at-social-app-aiat-logo - at-origin-social-app - exit -fi - -function at-social-app-custom-pages() { - d_=$d/repos/social-app - custom=$d/social-app-custom - - echo "copying custom components to social-app" - - # Create components directory if not exists - mkdir -p ${d_}/src/components/custom - - # Copy custom components - cp ${custom}/PrivacyContent.tsx ${d_}/src/components/custom/ - cp ${custom}/AppInfo.tsx ${d_}/src/components/custom/ - - echo "custom components copied successfully" -} - -function at-social-app-aiat-config() { - d_=$d/repos/social-app - custom=$d/social-app-custom - - echo "applying Aiat configuration" - - # Update app.config.js - cd ${d_} - - # Backup original - cp app.config.js app.config.js.orig - - # Apply changes using sed - sed -i "s/name: 'Bluesky'/name: 'Aiat'/g" app.config.js - sed -i "s/slug: 'bluesky'/slug: 'aiat'/g" app.config.js - sed -i "s/scheme: 'bluesky'/scheme: 'aiat'/g" app.config.js - sed -i "s/owner: 'blueskysocial'/owner: 'syui'/g" app.config.js - sed -i "s/bundleIdentifier: 'xyz.blueskyweb.app'/bundleIdentifier: 'ai.syui.at'/g" app.config.js - - # Update package.json name - sed -i 's/"name": "bsky.app"/"name": "aiat"/g' package.json - - echo "Aiat configuration applied" -} - -function at-social-app-aiat-logo() { - d_=$d/repos/social-app - custom=$d/social-app-custom - - echo "applying Aiat logo" - - # Create logo directory if not exists - mkdir -p ${custom}/assets - - # Copy logo if exists in custom folder - if [ -f ${custom}/assets/icon.png ]; then - cp ${custom}/assets/icon.png ${d_}/assets/app-icons/ios_icon_default_next.png - echo "Aiat logo applied" - else - echo "Warning: Logo file not found at ${custom}/assets/icon.png" - echo "Please add your logo file there" - fi -} - -function at-social-app-custom-screens() { - d_=$d/repos/social-app - custom=$d/social-app-custom - - echo "applying custom screens" - - # Copy custom screen files - cp ${custom}/PrivacyPolicy.screen.tsx ${d_}/src/view/screens/PrivacyPolicy.tsx - cp ${custom}/Support.screen.tsx ${d_}/src/view/screens/Support.tsx - cp ${custom}/LicenseNotice.tsx ${d_}/src/components/custom/ - - echo "custom screens applied" -} - - diff --git a/ios/config.zsh b/ios/config.zsh new file mode 100644 index 0000000..9bf6875 --- /dev/null +++ b/ios/config.zsh @@ -0,0 +1,14 @@ +APP_NAME="syuis" +DEVICE_ID="xxx" +REPO_DIR="../repos/social-app" +APP_SLUG="syuis" +APP_SCHEME="syui" +BUNDLE_ID="is.syu" +APP_GROUP="group.is.syu" +SERVICE_URL="https://syu.is" +HELP_URL="https://syu.is/help" +PRIVACY_URL="https://syu.is/privacy" +TERMS_URL="https://syu.is/terms" +REPO_DIR="../repos/social-app" +CONFIG_FILE="$REPO_DIR/app.config.js" +CONSTANTS_FILE="$REPO_DIR/src/lib/constants.ts" diff --git a/ios/icon.png b/ios/icon.png new file mode 100644 index 0000000..56f0a87 Binary files /dev/null and b/ios/icon.png differ diff --git a/ios/preview.zsh b/ios/preview.zsh new file mode 100755 index 0000000..a885a6a --- /dev/null +++ b/ios/preview.zsh @@ -0,0 +1,65 @@ +#!/bin/zsh +set -e +d=${0:a:h} +cd $d + +# DEVICE_ID="00008110-001855EA36D0401E" +APP_NAME="syuis" +REPO_DIR="../repos/social-app" + +echo "Running iOS preview workflow..." +cd "$REPO_DIR" + +# 0. Environment Setup (Fix Node Version) +export NVM_DIR="$HOME/.nvm" +[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm +echo "Checking Node version..." +if command -v nvm >/dev/null; then + nvm use 22 || nvm use 20 || echo "Warning: Could not switch to Node 22/20. Current: $(node -v)" +else + echo "nvm not found, using system node: $(node -v)" +fi + +# 1. Install dependencies +echo "1. Installing dependencies (yarn)..." +yarn install + +# 2. Prebuild (Generate ios directory) +echo "2. Running Expo Prebuild..." +# Clean old ios folder to remove old entitlements/AppClip targets +rm -rf ios +npx expo prebuild --platform ios --clean + +# 3. CocoaPods +echo "3. Installing CocoaPods..." +# Ensure PATH includes Homebrew ruby gems if needed +export PATH="/opt/homebrew/lib/ruby/gems/3.4.0/bin:$PATH" +cd ios +pod install +cd .. + +# 4. Signing (Manual Step) +echo "4. Opening Xcode for Signing..." +XCODE_PROJ="ios/${APP_NAME}.xcodeproj" +# Fallback search if variable name logic differs +if [ ! -d "$XCODE_PROJ" ]; then + XCODE_PROJ=$(find ios -name "*.xcodeproj" | head -n 1) +fi + +open "$XCODE_PROJ" +echo "========================================================" +echo " [ACTION REQUIRED] " +echo " Xcode opened ($XCODE_PROJ)." +echo " 1. Go to 'Signing & Capabilities' tab." +echo " 2. Select your Team." +echo " 3. Verify 'App Clip' target is gone." +echo " 4. Ensure no red errors exist." +echo " Press ENTER here once you are done to continue building." +echo "========================================================" +read + +# 5. Run +echo "5. Building and Running..." +# If user wants specific device ID, uncomment below, otherwise let Expo ask/pick boot simulator +# npx expo run:ios --device "$DEVICE_ID" --configuration Release +npx expo run:ios diff --git a/ios/setup.zsh b/ios/setup.zsh new file mode 100755 index 0000000..0473b78 --- /dev/null +++ b/ios/setup.zsh @@ -0,0 +1,215 @@ +#!/bin/zsh +d=${0:a:h} +cd $d + +APP_NAME="syuis" +APP_SLUG="syuis" +APP_SCHEME="syui" +BUNDLE_ID="is.syu" +APP_GROUP="group.is.syu" +SERVICE_URL="https://syu.is" +HELP_URL="https://syu.is/help" +PRIVACY_URL="https://syu.is/privacy" +TERMS_URL="https://syu.is/terms" + +REPO_DIR="../repos/social-app" +CONFIG_FILE="$REPO_DIR/app.config.js" +CONSTANTS_FILE="$REPO_DIR/src/lib/constants.ts" + +# Sed compatibility wrapper +function sediment() { + if [[ "$OSTYPE" == "darwin"* ]]; then + sed -i '' "$@" + else + sed -i "$@" + fi +} + +echo "Configuring $APP_NAME..." + +# Check if repo exists +if [ ! -d "$REPO_DIR" ]; then + echo "Cloning social-app..." + git clone https://github.com/bluesky-social/social-app "$REPO_DIR" +else + echo "Updating social-app..." + pushd "$REPO_DIR" + git stash -u + if ! git pull; then + echo "Git pull failed. Resetting..." + git reset --hard HEAD + git pull + fi + popd +fi + +# Backup config if not exists (or restore from backup to start fresh) +if [ ! -f "$CONFIG_FILE.bak" ]; then + cp "$CONFIG_FILE" "$CONFIG_FILE.bak" +else + cp "$CONFIG_FILE.bak" "$CONFIG_FILE" +fi + +# 1. app.config.js modifications +echo "Updating app.config.js..." + +# Replace name +sediment "s/name: 'Bluesky'/name: '$APP_NAME'/g" "$CONFIG_FILE" +sediment "s/slug: 'bluesky'/slug: '$APP_SLUG'/g" "$CONFIG_FILE" +sediment "s/scheme: 'bsky'/scheme: '$APP_SCHEME'/g" "$CONFIG_FILE" + +# Replace Bundle ID and App Group +sediment "s/xyz.blueskyweb.app/$BUNDLE_ID/g" "$CONFIG_FILE" +sediment "s/group.app.bsky/$APP_GROUP/g" "$CONFIG_FILE" + +# REMOVE App Clip Configuration (Critical for Personal Team Signing) +# Use Python for safer multi-line removal than sed +echo "Removing App Clip configuration..." +python3 -c " +import sys +import re + +try: + with open('$CONFIG_FILE', 'r') as f: + lines = f.readlines() + + with open('$CONFIG_FILE', 'w') as f: + skip = 0 + for i, line in enumerate(lines): + if skip > 0: + skip -= 1 + continue + + # Remove the plugin import line + if 'withStarterPackAppClip.js' in line: + continue + + # Check if this line defines the AppClip target + # Structure we expect: + # { + # targetName: 'BlueskyClip', + # ... + # }, + # We look for the targetName, and if found, we attempt to remove the preceding '{' line if possible + + if \"targetName: 'BlueskyClip'\" in line: + # We found the target. We need to NOT write this line. + # And we need to ensure the PREVIOUS line (which was '{') is not written? + # Since we are writing sequentially, we can't pop easily unless we buffer. + # Actually, simpler: Read file, modify list, write back. + continue + else: + pass + + # Retry with list manipulation approach + out = [] + i = 0 + while i < len(lines): + line = lines[i] + + # Remove plugin import + if 'withStarterPackAppClip.js' in line: + i += 1 + continue + + # Identify the block start + # We look ahead. If lines[i] is '{' and lines[i+1] has 'BlueskyClip', we skip the block. + if i + 1 < len(lines) and lines[i].strip() == '{' and \"targetName: 'BlueskyClip'\" in lines[i+1]: + # Found the start of the block. + # Skip until we find the closing '},' + # Typical block is 4 lines. + # { + # targetName: 'BlueskyClip', + # bundleIdentifier: ..., + # }, + # We'll just skip 4 lines to be safe matching the observed file structure + i += 4 + continue + + out.append(line) + i += 1 + + f.writelines(out) +except Exception as e: + print(f'Error processing file: {e}') + sys.exit(1) +" + +# Inject NSAppTransportSecurity for development/preview (Allow Arbitrary Loads) +if ! grep -q "NSAppTransportSecurity" "$CONFIG_FILE"; then + if [[ "$OSTYPE" == "darwin"* ]]; then + sed -i '' "/ios: {/a\\ + infoPlist: {\\ + NSAppTransportSecurity: {\\ + NSAllowsArbitraryLoads: true,\\ + },\\ + }," "$CONFIG_FILE" + else + sed -i "/ios: {/a\\ + infoPlist: {\\ + NSAppTransportSecurity: {\\ + NSAllowsArbitraryLoads: true,\\ + },\\ + }," "$CONFIG_FILE" + fi +fi + +# 2. constants.ts modifications +echo "Updating constants.ts..." +sediment "s|export const BSKY_SERVICE = 'https://bsky.social'|export const BSKY_SERVICE = '$SERVICE_URL'|g" "$CONSTANTS_FILE" +sediment "s|export const BSKY_SERVICE_DID = 'did:web:bsky.social'|export const BSKY_SERVICE_DID = 'did:web:syu.is'|g" "$CONSTANTS_FILE" +sediment "s|export const PUBLIC_BSKY_SERVICE = 'https://public.api.bsky.app'|export const PUBLIC_BSKY_SERVICE = 'https://bsky.syu.is'|g" "$CONSTANTS_FILE" +sediment "s|const HELP_DESK_LANG = 'en-us'|const HELP_DESK_LANG = 'ja-jp'|g" "$CONSTANTS_FILE" +sediment "s|export const HELP_DESK_URL = \`https://blueskyweb.zendesk.com/hc/\${HELP_DESK_LANG}\`|export const HELP_DESK_URL = '$HELP_URL'|g" "$CONSTANTS_FILE" + +# 3. Footer/Link replacements (Global text replacement for specific URLs) +echo "Replacing links..." +grep -r "https://bsky.social/about/blog" "$REPO_DIR/src" -l | xargs -I {} zsh -c "if [[ \"\$OSTYPE\" == \"darwin\"* ]]; then sed -i '' \"s|https://bsky.social/about/blog|$HELP_URL|g\" {}; else sed -i \"s|https://bsky.social/about/blog|$HELP_URL|g\" {}; fi" +grep -r "https://bsky.social/about/blog/jobs" "$REPO_DIR/src" -l | xargs -I {} zsh -c "if [[ \"\$OSTYPE\" == \"darwin\"* ]]; then sed -i '' \"s|https://bsky.social/about/blog/jobs|$HELP_URL|g\" {}; else sed -i \"s|https://bsky.social/about/blog/jobs|$HELP_URL|g\" {}; fi" +grep -r "/support/privacy" "$REPO_DIR/src" -l | xargs -I {} zsh -c "if [[ \"\$OSTYPE\" == \"darwin\"* ]]; then sed -i '' \"s|/support/privacy|$PRIVACY_URL|g\" {}; else sed -i \"s|/support/privacy|$PRIVACY_URL|g\" {}; fi" +grep -r "/support/tos" "$REPO_DIR/src" -l | xargs -I {} zsh -c "if [[ \"\$OSTYPE\" == \"darwin\"* ]]; then sed -i '' \"s|/support/tos|$TERMS_URL|g\" {}; else sed -i \"s|/support/tos|$TERMS_URL|g\" {}; fi" + +# 4. Icon replacement +if [ -f "icon.png" ]; then + echo "Updating icon..." + cp "icon.png" "$REPO_DIR/assets/icon.png" + cp "icon.png" "$REPO_DIR/assets/icon-android-notification.png" +fi + +# 5. Build Fixes (Entitlements and NSE Sounds) +echo "Applying build fixes..." + +# Fix 1: Create Config Plugin to Allow Entitlements Modification +cat < "$REPO_DIR/plugins/withCodeSignEntitlements.js" +const { withXcodeProject } = require('expo/config-plugins'); + +module.exports = function withCodeSignEntitlements(config) { + return withXcodeProject(config, (config) => { + const xcodeProject = config.modResults; + const configurations = xcodeProject.pbxXCBuildConfigurationSection(); + for (const key in configurations) { + const buildSettings = configurations[key].buildSettings; + if (buildSettings) { + buildSettings['CODE_SIGN_ALLOW_ENTITLEMENTS_MODIFICATION'] = 'YES'; + } + } + return config; + }); +}; +EOF + +# Register the plugin in app.config.js +# We insert it into the plugins array. Finding a safe anchor. +# 'expo-video' is in the plugins array. +sediment "s/'expo-video',/'expo-video', '.\/plugins\/withCodeSignEntitlements.js',/g" "$CONFIG_FILE" + + +# Fix 2: Disable soundFiles in Notification Extension to avoid 'no rule to process dm.aiff' +# The main app handles sounds via expo-notifications. The extension adding it as a source fails. +NOTIF_EXT_FILE="$REPO_DIR/plugins/notificationsExtension/withNotificationsExtension.js" +if [ -f "$NOTIF_EXT_FILE" ]; then + echo "Patching withNotificationsExtension.js..." + sediment "s/const soundFiles = \['dm.aiff'\]/const soundFiles = []/g" "$NOTIF_EXT_FILE" +fi + +echo "Setup complete. App Clip configuration removed. Build fixes applied."