Tüm Yazılar
KategoriSecurity
Okuma Süresi
16 dk
Yayın Tarihi
2025-11-13
Kelime Sayısı
3.037kelime

Kahveni hazırla - bu içerikli bir makale!

Mobil Bağımlılık Zinciri Güvenliği: SBOM ve Denetim

Özet

Mobil bağımlılık zinciri güvenliği için SPM, CocoaPods ve Gradle'da SBOM üretimi, envanter çıkarma, sürüm sabitleme ve üç aylık denetim şablonunu resmi dokümantasyona dayanarak adım adım kur.

  • Bağımlılık envanteri Gradle'da konfigürasyon tipiyle (api/implementation/compileOnly), SPM'de Package.Dependency listesiyle çıkarılır.
  • SPM exact, from (upToNextMajor), revision etiketli çağrılarla tip güvenli sürüm sabitleme sunar (arkalarındaki Requirement enum'u SwiftPM 5.6'dan beri deprecated).
  • GitHub'ın SPDX formatlı SBOM export'u transitive path'leri içerir ama dependents'ı içermez.
  • CocoaPods'ta resmi bir envanter/SBOM aracı yok — Podfile.lock manuel veya üçüncü taraf araçla denetlenmeli.
Mobil Bağımlılık Zinciri Güvenliği: SBOM ve Denetim

Bir mobil uygulamanın kaynak kodunu tek tek satır satır denetlemek artık güvenlik için yeterli değil — çünkü uygulamanın gerçek saldırı yüzeyinin büyük kısmı senin yazmadığın kodda, yani bağımlılık zincirinde yaşıyor. SPM, CocoaPods ve Gradle her gün onlarca transitive paketi projene otomatik olarak dahil ediyor ve bunların hiçbiri kod incelemesine girmiyor. Bu yazıda mobil bağımlılık zinciri güvenliğini SBOM üretimi, sürüm sabitleme ve denetim şablonuyla birlikte, Android/Gradle ve Apple/SPM'in resmi dokümantasyonuna dayanarak adım adım kuracaksın.

💡 Pro Tip: Bir bağımlılığı eklemeden önce sor: "Bu paket transitive olarak başka kaç paketi projeme sokuyor?" Cevabı bilmiyorsan, envanterin zaten eksik demektir.

İçindekiler

Bağımlılık zincirinin görünmeyen yüzü: transitive paketler

Bir bağımlılık eklediğinde aslında tek bir paket değil, onun bildirdiği tüm alt bağımlılıkları da projene dahil edersin. Android'in resmi Gradle dokümantasyonu bunu açıkça tanımlar: bir kütüphaneyi bağımlılık olarak eklediğinde, "any transitive dependencies they declare are automatically included as well." Yani senin build.gradle.kts dosyanda tek satır olarak görünen bir paket, arka planda beş ya da on farklı paketi daha projene sokabilir.

Gradle'da bu davranışı yönetmenin anahtarı, konfigürasyon tipini doğru seçmektir. api ile eklenen bir bağımlılık, onu kullanan modülün tüketicilerine de transitive olarak "export" edilir — resmi dokümanın ifadesiyle: "When a module includes an api dependency, it's letting Gradle know that the module wants to transitively export that dependency." implementation ise bu sızıntıyı modülün sınırında durdurur.

kotlin
1// build.gradle.kts — konfigürasyon tipi = envanter sınırı
2dependencies {
3 // Transitive olarak dışa aktarılır — tüketici modüller de görür
4 api("com.squareup.retrofit2:retrofit:2.9.0")
5 
6 // Yalnız bu modülde kalır — envanter yüzeyi küçük tutulur
7 implementation("com.squareup.okhttp3:logging-interceptor:4.12.0")
8 
9 // Yalnız derleme sınıf yoluna eklenir, çıktıya paketlenmez
10 compileOnly("com.google.code.findbugs:jsr305:3.0.2")
11 
12 // Derleme öncesi kod üretir, runtime'a girmez
13 ksp("com.google.dagger:dagger-compiler:2.48")
14}

Apple tarafında model farklı ama sonuç benzer: Target.Dependency, bir target'ın aynı paket içindeki diğer target'lara veya bağımlı olunan paketlerin sunduğu "product"lara bağımlı olabileceğini tanımlar — resmi ifadeyle "A target may depend on other targets within the same package and on products vended by the package's dependencies." Yani SPM'de transitive zincir, target-product grafiği üzerinden kurulur; bir paketi eklediğinde onun products alanında tanımlı her şey projenin ulaşabileceği yüzeye dahil olur.

Pratik sonuç şu: envanter çıkarmadan önce hangi konfigürasyon tipinin (Gradle) veya hangi product ilişkisinin (SPM) gerçekten derlenmiş çıktıya girdiğini bilmen gerekir — aksi halde saydığın "10 bağımlılık" aslında 40 paketlik gizli bir yüzeyi temsil ediyor olabilir.

SPM, CocoaPods ve Gradle'da envanter çıkarma

Üç ekosistemin de bağımlılık listesini tanımlama biçimi farklıdır ve envanter çıkarma stratejin buna göre şekillenmeli.

SPM'de bağımlılıklar, Package struct'ının dependencies: [Package.Dependency] alanında listelenir. Apple'ın resmi dokümanı bu alanı "The list of package dependencies." olarak tanımlar ve örnek deklarasyonu şöyle verir:

swift
1// Package.swift — envanterin başlangıç noktası
2let package = Package(
3 name: "MyApp",
4 dependencies: [
5 .package(url: "https://url/of/another/package/named/utility", from: "1.0.0")
6 ],
7 targets: [
8 .target(name: "MyApp", dependencies: ["Utility"])
9 ]
10)

Her .package(...) girdisi ayrı bir Package.Dependency nesnesidir — dokümanın tanımıyla "A package dependency of a Swift package." Envanterin ilk adımı, bu manifest dosyasındaki her girdiyi elle veya bir script ile listelemektir.

CocoaPods tarafında durum farklı: CocoaPods'a özgü resmi bir envanter veya SBOM mekanizması yok. Bir Podfile yine de aynı mantıkla bir bağımlılık listesi tutar; envanterin başlangıç noktası budur, ama üçüncü taraf araçlar (Syft, Microsoft SBOM Tool gibi genel amaçlı tarayıcılar) devreye girmeden CocoaPods'un kendi resmi bir "envanter çıkar" komutu yok.

ruby
1# Podfile — envanterin ham listesi (CocoaPods'ta yerleşik SBOM aracı yok)
2platform :ios, '15.0'
3 
4target 'MyApp' do
5 use_frameworks!
6 pod 'Alamofire', '5.9.1'
7 pod 'SDWebImage', '5.19.1'
8end

Android/Gradle tarafında ise envanter, konfigürasyon tipleriyle iç içe geçmiş durumda. compileOnly bir bağımlılığı yalnızca derleme sınıf yoluna ekler ve çıktıya paketlemez — dokümanın ifadesiyle "Gradle adds the dependency to the compile classpath only (that is, it's not added to the build output)." annotationProcessor, kapt ve ksp konfigürasyonları ise "supply libraries that process annotations and other symbols in your code before it is compiled" — yani derleme zamanında çalışıp runtime'a hiç girmezler. Envanterini çıkarırken bu ayrımı yapmazsan, gerçekte uygulamana giren bağımlılık sayısını olduğundan fazla göstermiş olursun.

Ekosistem
Manifest / kaynak
Resmi envanter mekanizması
Gradle (Android)
build.gradle.kts
Konfigürasyon tipleri (api/implementation/compileOnly) + Play Console meta veri taraması
Swift Package Manager
Package.swift
Package.Dependency listesi + Target.Dependency grafiği
GitHub (repo geneli)
Dependency graph
SBOM export (SPDX formatı)
CocoaPods
Podfile
Resmi mekanizma yok — üçüncü taraf tarayıcı gerekir

SBOM üretimi ve sürüm sabitleme (pinning)

GitHub, bir reponun bağımlılık envanterini biçimsel bir standarda döken SBOM export özelliğini sunar. Bu özellik endüstri standardı bir formatı kullanır — dokümanın ifadesiyle "industry standard SPDX format" — ve export akışı repo içindeki Insights sekmesinin Dependency graph bölümünden tetiklenir: "On the top right side of the Dependencies tab, click Export SBOM." GitHub Actions üzerinden de otomatik üretim mümkündür; dokümantasyon bunu "SPDX 2.2 compatible SBOMs" olarak tanımlar.

Üretilen SBOM'un neyi içerip neyi içermediğini bilmek kritik: "SBOMs include an inventory of a project's dependencies and associated information such as versions, package identifiers, licenses, transitive paths, and copyright information." Yani transitive path'ler dahildir — ama tek yönlüdür: "SBOMs do not include dependents (other projects that rely on your project)." Başka bir deyişle SBOM sana "ben neyi kullanıyorum" sorusuna cevap verir, "beni kim kullanıyor" sorusuna değil.

Sürüm sabitleme tarafında SPM, en yaygın üç pinning yöntemi sunar (bu yöntemlerin arkasındaki Package.Dependency.Requirement enum'u SwiftPM 5.6'dan beri deprecated'dır; güncel kullanım doğrudan package(url:exact:), package(url:from:) ve package(url:revision:) çağrılarıdır):

swift
1// Package.swift — pinning stratejisi seçimi
2dependencies: [
3 // Tam sabitleme — yalnızca bu sürüm, otomatik güncelleme yok
4 .package(url: "https://github.com/vendor/utility", exact: "2.4.0"),
5 
6 // Kontrollü otomatik güncelleme — major sürüm sabit, minor/patch serbest
7 .package(url: "https://github.com/vendor/networking", from: "3.0.0"),
8 
9 // Commit hash seviyesinde mutlak kilitleme
10 .package(url: "https://github.com/vendor/crypto", revision: "a1b2c3d4e5f6")
11]

Bu çağrıların arkasındaki eski Requirement enum'u için Apple'ın resmi tanımı şöyle: exact(_:) — "Returns a requirement for the given exact version."; upToNextMajor(from:) — "A source control requirement bounded to the given version's major version number." ve upToNextMinor(from:) aynı mantığı minor seviyesinde uygular; revision(_:) — "Returns a requirement for a source control revision such as the hash of a commit." — yani bir bağımlılığı belirli bir commit'e kilitleyebilirsin.

Gradle/Android tarafında dinamik sürüm kullanımı açıkça caydırılır: "When specifying dependencies, you shouldn't use dynamic version numbers, such as 'com.android.tools.build:gradle:3.+'. Using this feature can cause unexpected version updates." Bunun yerine BOM (Bill of Materials) desteği önerilir — "Some libraries are available in a published Bill of Materials (BOM) that groups families of libraries and their versions. You can include a BOM in your version catalog and build files." BOM, sürüm tutarlılığını tek noktadan yöneten resmi bir mekanizmadır.

Strateji
Platform
Güncelleme esnekliği
Risk profili
.exact(_:)
SPM
Yok — manuel güncelleme gerekir
En düşük sürpriz riski, en yüksek bakım yükü
.upToNextMajor(from:)
SPM
Minor/patch otomatik
Dengeli — çoğu ekip için varsayılan seçim
.revision(_:)
SPM
Yok — commit'e kilitli
Kritik/kriptografi bağımlılıkları için
BOM + version catalog
Gradle
Merkezi, tek noktadan
Sürüm tutarlılığı, dinamik sürüm riskini engeller
Dinamik sürüm (3.+)
Gradle
Tam otomatik
Resmi dokümanda açıkça önerilmiyor

Ben genelde ağ ve kriptografi katmanındaki bağımlılıklarda .exact ya da .revision tercih ederim; UI bileşen kütüphaneleri gibi daha düşük riskli paketlerde .upToNextMajor yeterli oluyor.

Yeni bağımlılık kabul kriterleri

Bir bağımlılığı projene kabul etmeden önce sorman gereken sorular, Android Studio'nun zaten otomatik olarak sorduğu sorularla örtüşüyor. Resmi dokümanın ifadesiyle Android Studio, version catalog dosyasında ve Project Structure Dialog'da (Google Play SDK Index'teki public SDK'lar için) şu dört durumda lint uyarısı gösterir: "The SDKs are marked as outdated by their authors, The SDKs violate Play policies, The SDKs have known security vulnerabilities, The SDKs have been deprecated by their authors." Bu dört kriter, kendi kabul kontrol listeni oluştururken doğrudan resmi referans olarak kullanılabilir.

Kabul kriterlerine eklemen gereken ek bir boyut, bağımlılığın hangi konfigürasyon tipiyle ekleneceğidir. Bir paket yalnızca derleme zamanı kod üretimi yapıyorsa (ksp/kapt) veya yalnızca derleme sınıf yoluna gerekiyorsa (compileOnly), bunu implementation ya da api ile eklemek runtime yüzeyini gereksiz büyütür. Kabul sürecinde şu soruyu sabit sor: "Bu paket runtime'a mı giriyor, yoksa yalnızca derleme zamanında mı çalışıyor?"

Mimari tarafta modüler bir yapı kurduysan (bkz. Modular iOS Architecture ve Swift Package Manager), yeni bir bağımlılığın hangi modüle gireceği ve oradan hangi modüllere transitive olarak sızacağı sorusu kabul kriterinin ayrılmaz bir parçası olmalı. Bağımlılık enjeksiyonu kullanan projelerde ise üçüncü taraf bir SDK'yı doğrudan somut tip olarak enjekte etmek yerine bir protokol arkasına almak, ilerideki bir paket değişikliğinin (ya da ele geçirilme senaryosunda hızlı bir değişikliğin) etkisini tek bir noktaya sıkıştırır.

  • Sürüm politikası: paket .exact/.revision mi yoksa .upToNextMajor ile mi kabul ediliyor — bu karar dokümante edilmeli.
  • Konfigürasyon tipi: api, implementation, compileOnly, ksp — hangisi, neden.
  • Play/App Store politika uyumu: Android tarafında Android Studio'nun (Google Play SDK Index üzerinden) taradığı dört kriterin (outdated/policy/zafiyet/deprecated) manuel ön kontrolü.
  • Soyutlama: SDK doğrudan mı çağrılıyor, yoksa bir protokol/arayüz arkasında mı.

Otomatik güncelleme ve güvenlik uyarılarını CI'ya bağlamak

Android tarafında bu entegrasyon zaten yerleşik: AGP, uygulamayı yüklediğinde okunan bağımlılık meta verisini APK/AAB'ye gömer ve "When uploading your app, the Play Console inspects this metadata to provide alerts for known issues with SDKs and dependencies your app uses." Yani ayrı bir CI adımı kurmana gerek kalmadan, uygulama yükleme adımının kendisi bir güvenlik kontrol noktasına dönüşür.

GitHub tarafında SBOM'u CI'ya bağlamanın en pratik yolu, export akışını bir workflow'a taşımaktır. Aşağıdaki iskelet, SBOM üretimini pull request akışına bağlar (adım adı ve uses: satırı repona göre uyarlanmalı, kendi organizasyonunun onayladığı action'ı kullan):

yaml
1# .github/workflows/dependency-audit.yml — iskelet
2name: Dependency Audit
3on:
4 pull_request:
5 paths:
6 - "**/build.gradle.kts"
7 - "**/Package.swift"
8 - "**/Podfile"
9jobs:
10 audit:
11 runs-on: ubuntu-latest
12 steps:
13 - uses: actions/checkout@v4
14 - name: Yeni bağımlılık değişikliğini işaretle
15 run: |
16 echo "Bu PR bir manifest dosyasını değiştiriyor — kabul kriteri kontrol listesini uygula."

Bu iskeletin asıl işi, "manifest değişti mi" sorusunu otomatikleştirmek ve inceleyene hatırlatmaktır — SBOM'un kendisini üretmek için GitHub'ın kendi export akışını (Dependency graph → Export SBOM) veya organizasyonunun onayladığı bir SBOM action'ını kullanman gerekir.

Bir paketin ele geçirilmesi senaryosunda müdahale planı

Yukarı akış (upstream) bir paketin ele geçirilmesi senaryosunda ilk sorman gereken şey şu: "Bu bağımlılığı nasıl sabitledim?" SPM'de revision(_:) ile bir bağımlılık commit hash seviyesinde kilitlendiğinde — dokümanın ifadesiyle "Returns a requirement for a source control revision such as the hash of a commit." — yukarı akış deposu ele geçirilse ve kötü niyetli bir sürüm yayınlansa bile, projen o commit'e sabit kaldığı için otomatik olarak o sürümü çekmez. Bu, müdahale planının teknik temelidir: revision-pinning, "beklenmedik güncelleme" riskini API seviyesinde engeller.

Bunun tersi de doğru: .upToNextMajor ile eklenmiş bir bağımlılık, upstream'de kötü niyetli bir minor/patch sürümü yayınlanırsa bir sonraki derlemede otomatik olarak çekilebilir. Müdahale planın şu adımları içermeli:

  1. Tespit: Play Console'un bilinen SDK sorunları uyarısını, Android Studio'nun SDK Index lint bulgularını veya GitHub'ın ürettiği uyarıyı izleyen bir kanal kur.
  2. Dondurma: etkilenen bağımlılığı .exact veya .revision ile derhal bilinen-temiz bir sürüme/commit'e kilitle.
  3. Kapsam belirleme: SBOM'daki transitive path bilgisini kullanarak hangi modüllerin bu paketi kullandığını çıkar (SBOM "dependents" içermez, yani kimin senin projeni kullandığını değil, senin projenin neyi kullandığını gösterir — kapsam belirleme senin kendi repo(lar)ında yapılır).
  4. İletişim: modüler mimarideyse (bkz. Clean Architecture iOS), etkilenen katmanı izole edip diğer modüllerin build'ini bloklamadan yamanın geçmesini sağla.

Üç aylık denetim şablonu

Android Studio'nun zaten uyguladığı dört kriter — "The SDKs are marked as outdated by their authors, The SDKs violate Play policies, The SDKs have known security vulnerabilities, The SDKs have been deprecated by their authors." — periyodik bir denetim şablonunun omurgasını oluşturur. Üç ayda bir aşağıdaki listeyi her modül için tekrarla:

  • Her bağımlılığın son sürümle arasındaki fark kaç major sürüm; .exact/.revision ile sabitlenmiş paketlerde bu fark bilinçli bir gecikme mi, yoksa unutulmuş mu?
  • Android Studio'nun (SDK Index üzerinden) veya derleme uyarılarının işaretlediği outdated/politika/zafiyet/deprecated bulgularının hiçbiri kapatılmadan bekletilmiyor mu?
  • GitHub SBOM export'u yeniden alınıp bir önceki çeyrekle karşılaştırıldığında beklenmedik yeni bir transitive paket girmiş mi?
  • CocoaPods kullanılan hedeflerde (resmi bir envanter aracı olmadığı için) Podfile.lock elle veya üçüncü taraf bir tarayıcıyla gözden geçirildi mi?

ALTIN İPUCU

Bu yazının en değerli bilgisi

Bu ipucu, yazının en önemli çıkarımını içeriyor.

Easter Egg

Gizli bir bilgi buldun!

Bu bölümde gizli bir bilgi var. Keşfetmek ister misin?

Okuyucu Ödülü

Bu yazıda geçen tüm resmi mekanizmaları tek bir kontrol listesine indirdim — üç platformun (Gradle, SPM, GitHub) sana zaten verdiği araçları hiçbir ek maliyet olmadan nasıl kullanacağını gösteren, adım adım uygulanabilir bir liste. Aşağıdaki maddeleri sırayla uyguladığında bağımlılık zincirinin görünmeyen yüzünü büyük ölçüde görünür kılmış olursun.

SSS

Mobil uygulamada bağımlılık envanteri nasıl çıkarılır?

Envanterin başlangıç noktası platforma göre değişir: Gradle'da build.gradle.kts içindeki konfigürasyon tipleri (api, implementation, compileOnly, ksp), SPM'de Package.swift içindeki dependencies: [Package.Dependency] listesi, CocoaPods'ta ise Podfile. GitHub reposundaysan, Insights sekmesindeki Dependency graph üzerinden bir SBOM export alarak transitive path'leri de içeren biçimsel bir envanter çıkarabilirsin — ama bu SBOM'un dependents'ı (seni kimin kullandığını) içermediğini unutma.

SBOM nedir ve mobilde nasıl üretilir?

SBOM (Software Bill of Materials), bir projenin bağımlılık envanterini endüstri standardı bir formatta (SPDX) listeleyen bir belgedir; sürüm, paket kimliği, lisans, transitive path ve telif bilgisini içerir. GitHub'da bunu repo Insights sekmesindeki Dependency graph → Export SBOM akışından veya GitHub Actions üzerinden SPDX 2.2 uyumlu biçimde üretebilirsin. CocoaPods'a özgü resmi bir SBOM aracı olmadığı için CocoaPods hedeflerinde üçüncü taraf tarayıcılara ihtiyaç duyarsın.

Bir bağımlılık ele geçirilirse ne yapmalı?

Önce bağımlılığın nasıl sabitlendiğine bak: .revision(_:) ile commit hash'ine kilitlenmiş bir paket, upstream'de kötü niyetli bir sürüm yayınlansa bile otomatik olarak çekilmez. Sabitleme gevşekse (.upToNextMajor veya Gradle'da dinamik sürüm), etkilenen paketi derhal bilinen-temiz bir sürüme/commit'e dondur, SBOM'daki transitive path bilgisiyle etkilenen modülleri belirle ve modüler mimarideysen etkilenen katmanı izole ederek diğer modüllerin build'ini bloklama.

Gradle'da hangi bağımlılık hangi konfigürasyonla eklenmeli?

Bir bağımlılık yalnızca modülün kendi içinde kullanılıyorsa implementation, tüketici modüllerin de erişmesi gerekiyorsa api, yalnızca derleme sınıf yoluna gerekiyorsa (runtime'a girmeyecekse) compileOnly, derleme zamanında kod üretiyorsa ksp/kapt/annotationProcessor kullanılmalı. Bu seçim doğrudan envanterinin doğruluğunu belirler.

SPM'de sürüm sabitleme seçenekleri nelerdir?

package(url:exact:), package(url:from:) ve package(url:revision:) üç temel seçenek sunar: exact tam sürüme kilitler, from (upToNextMajor) major sürüm numarasına bağlı kontrollü bir aralık tanımlar, revision ise commit hash veya revizyon kimliğine göre sabitler (bu çağrıların arkasındaki eski Requirement enum'u SwiftPM 5.6'dan beri deprecated'dır).

Güncelleme (Eylül 2026)

Bu yazı 2025-11-13 tarihinde, o tarihteki resmi dokümantasyona göre yazıldı. Aradan geçen sürede iki gelişme doğrudan ilgili: AB'nin Siber Dayanıklılık Yasası (Cyber Resilience Act) kapsamında, AB pazarına ürün/SDK süren üreticiler için aktif istismar edilen zafiyetleri raporlama yükümlülüğü 11 Eylül 2026'da yürürlüğe girdi — bağımlılık envanterinin (SBOM) artık isteğe bağlı bir iyi-pratikten yasal bir baskı altına girdiğini gösteriyor.

Kaynak: Cyber Resilience Act — Avrupa Komisyonu.

Saldırı yüzeyi tarafında bir sinyal daha var: npm altyapısı ve aynaları Ağustos 2026'da bir phishing kampanyasında istismar edildi — mobil-özel bir olay değil ama tedarik zincirinin artık bağımsız bir güvenlik disiplini haline geldiğini doğruluyor.

Kaynak: npm mirror phishing — BleepingComputer.

Sonuç

Mobil bağımlılık zinciri güvenliği tek bir araçla değil, üç resmi mekanizmanın bir araya getirilmesiyle kurulur: Gradle'ın konfigürasyon tipi ayrımı ve Play Console'un otomatik meta veri taraması, SPM'in package(url:exact:) / package(url:from:) / package(url:revision:) çağrılarıyla sürüm/commit seviyesinde pinning, GitHub'ın SPDX formatındaki SBOM export'u. CocoaPods'a özgü resmi bir envanter aracı olmaması, bu hedeflerde manuel disiplini zorunlu kılıyor.

Modüler bir mimari kurduysan (Modular iOS Architecture ve Swift Package Manager, SPM Advanced Modular), yeni bağımlılık kabul kriterini modül sınırlarıyla birleştirmek doğal bir sonraki adım. Genel güvenlik pratiklerini (iOS Security Best Practices) ve hassas veri saklama stratejini (iOS Keychain Security) bu bağımlılık disipliniyle birleştirdiğinde, saldırı yüzeyinin büyük bir kısmını kapatmış olursun. Üçüncü taraf SDK'ları doğrudan somut tip olarak enjekte etmek yerine bir soyutlama katmanı (Swift Dependency Injection) arkasına almak da bir ele geçirilme senaryosunda müdahaleyi hızlandırır — özellikle temiz bir katman ayrımı (Clean Architecture iOS) üzerine kurulu projelerde.

Kaynaklar

Etiketler

#mobil güvenlik#SBOM#tedarik zinciri#Swift Package Manager#Gradle#CocoaPods#dependency pinning#CI/CD
Muhittin Çamdalı

Muhittin Çamdalı

Lead Mobile Engineer

12+ yıllık deneyime sahip Lead Mobile Engineer. Swift, SwiftUI, Kotlin ve Flutter ile iOS, Android ve cross-platform mimarilerde uzman. Performanslı ve kullanıcı dostu mobil uygulamalar geliştiriyorum.

iOS Geliştirme Haberleri

Haftalık Swift tips, SwiftUI tricks ve iOS best practices. Spam yok, sadece değerli içerik.

Gizliliğinize saygı duyuyoruz. İstediğiniz zaman abonelikten çıkabilirsiniz.

Paylaş

İlgili İçerik