Skip to content

NandanPrabhu/GitHubRepoFinder

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

GitHubRepoFinder

iOS (SwiftUI) and Android (Jetpack Compose) app that fetches GitHub repositories by username. Both platforms share the same Swift networking code — no duplicate API logic.

┌────────────────────────────────────────┐
│         GitHubRepoKit (Swift)          │
│     URLSession → GitHub API → JSON     │
└─────────────┬──────────────┬───────────┘
              │              │
     ┌────────▼───┐   ┌─────▼──────────────┐
     │  iOS App   │   │   Android App       │
     │  (SwiftUI) │   │   (Jetpack Compose) │
     │            │   │                     │
     │  Direct    │   │  Swift .so (ARM64)  │
     │  import    │   │  via JNI + swift-java│
     └────────────┘   └─────────────────────┘

Prerequisites

  • macOS with Xcode 16+ (Swift 6.1+)
  • JDK 17 (brew install --cask corretto@17)
  • Android Studio with SDK 35, NDK
  • Swift SDK for Android (swift sdk install ...)
  • swift-java CLI (built from source)
  • XcodeGen (brew install xcodegen)

See SETUP.md for complete installation steps from a fresh MacBook.


Run iOS App

cd ios-app
open GitHubRepoFinder.xcodeproj
# Press Cmd+R to build and run on simulator

Run Android App

Prerequisites

  1. Publish swift-java runtime to local Maven (required for swiftkit-core:1.0-SNAPSHOT dependency):
cd ~/Developer/swift-java-source
JAVA_HOME=$(/usr/libexec/java_home -v 17) ./gradlew :SwiftKitCore:publishToMavenLocal
  1. Set JDK path in android-app/gradle.properties:
echo "org.gradle.java.home=$(/usr/libexec/java_home -v 17)" >> android-app/gradle.properties

Cross-compile Swift and deploy .so files

# 1. Cross-compile Swift for Android ARM64
swift build \
  --package-path GitHubRepoKit \
  --product GitHubRepoKitJNI \
  --swift-sdk $(swift sdk list | grep android | tail -1) \
  --triple aarch64-unknown-linux-android35

# 2. Deploy .so files
JNILIBS=android-app/app/src/main/jniLibs/arm64-v8a
mkdir -p $JNILIBS

BUILD_DIR=$(find GitHubRepoKit/.build -name "libGitHubRepoKitJNI.so" -path "*aarch64*android*" | head -1 | xargs dirname)
cp "$BUILD_DIR/libGitHubRepoKitJNI.so" "$JNILIBS/"
cp "$BUILD_DIR/libSwiftJava.so" "$JNILIBS/"

SDK_BUNDLE=$(find ~/Library/org.swift.swiftpm/swift-sdks -name "*.artifactbundle" -path "*android*" | head -1)
SWIFT_LIBS="$SDK_BUNDLE/swift-android/swift-resources/usr/lib/swift-aarch64/android"
NDK_SYSROOT=$(find "$SDK_BUNDLE" -path "*/sysroot/usr/lib/aarch64-linux-android" -type d | head -1 | sed 's|/usr/lib/aarch64-linux-android||')

for lib in libswiftCore.so libdispatch.so libswiftDispatch.so libBlocksRuntime.so \
           libswift_Concurrency.so libswiftAndroid.so libFoundation.so \
           libFoundationEssentials.so libFoundationInternationalization.so \
           libFoundationNetworking.so lib_FoundationICU.so \
           libswift_StringProcessing.so libswift_RegexParser.so \
           libswift_Builtin_float.so libswift_math.so \
           libswiftSynchronization.so libswiftSwiftOnoneSupport.so; do
    cp "$SWIFT_LIBS/$lib" "$JNILIBS/" 2>/dev/null || true
done

cp "$NDK_SYSROOT/usr/lib/aarch64-linux-android/libc++_shared.so" "$JNILIBS/"

Build and run

cd android-app

# Build
./gradlew :app:assembleDebug

# Start emulator (use -dns-server to fix network issues)
$ANDROID_HOME/emulator/emulator -avd <your-avd-name> -dns-server 8.8.8.8,8.8.4.4 &

# Install and run
adb wait-for-device
adb install -r app/build/outputs/apk/debug/app-debug.apk
adb shell am start -n com.example.githubrepo/.MainActivity

Project Structure

Folder What it does
GitHubRepoKit/ Shared Swift package — networking code used by both platforms
ios-app/ SwiftUI app, imports GitHubRepoKit directly
android-app/ Jetpack Compose app, calls Swift via JNI
android-app/github-repo-kit-bridge/ JNI bridge module (swift-java generated bindings + Kotlin wrapper)

See PROJECT_STRUCTURE.md for a detailed file-by-file breakdown.


How It Works

  1. GitHubService.swift makes HTTP calls using URLSession (works on both iOS and Android via FoundationNetworking)
  2. On iOS: the app imports GitHubRepoKit as a Swift package — native, direct
  3. On Android: Swift code is cross-compiled to .so using Swift SDK for Android, and called via JNI bindings generated by swift-java jextract
  4. Both platforms execute the exact same Swift networking code — zero Kotlin/Java HTTP logic

Regenerating JNI Bindings

Only needed if you change the public API in GitHubRepoKit/Sources/GitHubRepoKitJNI/JNIExports.swift:

swift-java jextract \
  --input-swift GitHubRepoKit/Sources/GitHubRepoKitJNI \
  --swift-module GitHubRepoKitJNI \
  --java-package com.example.githubrepo.bridge \
  --output-swift GitHubRepoKit/Sources/GitHubRepoKitJNI/Generated \
  --output-java android-app/github-repo-kit-bridge/src/main/java \
  --mode jni

Then fix initializeLibs() in the generated GitHubRepoFetcher.java to use System.loadLibrary() (see SETUP.md step 11).

About

Github repo finder Mobile app

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages