Swift'i kullanarak Uygulama sürümünü nasıl oluşturabilirim ve numarayı nasıl oluşturabilirim?


387

Azure arka uçlu bir IOS uygulamam var ve girişler ve uygulama kullanıcılarının hangi sürümlerinin çalıştığı gibi belirli olayları günlüğe kaydetmek istiyorum.

Swift'i kullanarak sürümü ve derleme numarasını nasıl döndürebilirim?



6
Bu Objective-C, Swift değil.
Øyvind Vik

10
CFBundleVersion& CFBundleShortVersionString'i karıştırmamaya dikkat edin. Birincisi derleme sürümünüzdür. Diğeri sürüm numarasıdır. Daha fazla bilgi için buraya bakın
Honey

1
@ ØyvindVik Çoğu insan, Objective-C çözümünü Swift'e el tutmadan çevirebileceğinizi varsayar.
gnasher729

Yanıtlar:


424

DÜZENLE

Swift 4.2 için güncellendi

let appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String

DÜZENLE

@ Azdev'in Xcode'un yeni sürümünde işaret ettiği gibi, önceki çözümümü denemek için bir derleme hatası alacaksınız, bunu çözmek için bir paket sözlüğü kullanarak bir paket!

let nsObject: AnyObject? = Bundle.main.infoDictionary!["CFBundleShortVersionString"]

Düzenlemeyi Sonlandır

Objective-C ile aynı mantığı kullanın, ancak bazı küçük değişikliklerle

//First get the nsObject by defining as an optional anyObject
let nsObject: AnyObject? = NSBundle.mainBundle().infoDictionary["CFBundleShortVersionString"]

//Then just cast the object as a String, but be careful, you may want to double check for nil
let version = nsObject as! String

Umarım bu sana yardımcı olur.

David


Bunu kullandığımda, bir derleyici hatası alıyorum "[NSObject: AnyObject]?" Abone "adlı bir üyesi yok
andreas

AnyObject'i değiştirmeyi deneyebilir misiniz? AnyObject tarafından! Kullandığınız kodu tam olarak bilmeden neyin yanlış olduğunu tahmin etmek çok zordur, ayrıca Swift'in bir Xcode sürümünden diğerine değişebileceğini unutmayın, bu nedenle Xcode sürümünüzü bilmek de uygun olacaktır.
David

18
@ andreas ile ambalajından infoDictionaryçıkarılmalıdır !. Ben Globals.swift dosyasına yerleştirilen bu kullanıyorum:let appVersion = NSBundle.mainBundle().infoDictionary!["CFBundleVersion"] as String
azdev

1
Bir tane daha eklemek zorunda kaldım "!" sonra "gibi". let appVersion = NSBundle.mainBundle().infoDictionary!["CFBundleVersion"] as! String
yosei

3
Zorla paketini açmaktan kaçınmalısınız "!" çünkü bu değerlerden biri sıfır olduğunda uygulamanızın çökmesine neden olurlar
Julius

278

Bunun zaten cevaplandığını biliyorum ama kişisel olarak bunun biraz daha temiz olduğunu düşünüyorum:

Swift 3.0:

 if let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String {
    self.labelVersion.text = version
}

Swift <2.3

if let version = NSBundle.mainBundle().infoDictionary?["CFBundleShortVersionString"] as? String {
    self.labelVersion.text = version
}

Bu şekilde, eğer izin sürümü koşullu işlemeyi halleder (benim durumumda etiket metnini ayarlar) ve infoDictionary veya CFBundleShortVersionString nil ise isteğe bağlı açma işlemi kodun atlanmasına neden olur.


6
self.labelVersion.textİsteğe bağlı türdür, bu nedenle doğrudan atayabilirsinizNSBundle.mainBundle().infoDictionary?["CFBundleShortVersionString"] as? String
Jonauz

8
Değerin ayarlanmamasının bir nedeni var mı? Kesinlikle daha temkinli olduğunu kabul etti let, sadece neden gerekli olabileceğini merak etti. Teşekkürler!
Crashalot

@Crashalot isminize rağmen;), örneğin bir yazım hatası yaparsanız, sürüm numarasının "bir şeyler yanlış gittiğini" varsa uygulamanızın çökmesini istemezsiniz.
Daniel Springer

OP: değiştirebilirsiniz? ile ! ve "as String" i kaldırın. Sıfır ise, yine de çökmeyecek
Daniel Springer

245

Swift 3.0 için güncellendi

NS-Prefixes şimdi Swift 3.0 gitti ve birkaç özellikleri / yöntemleri daha Swifty olmaya isimleri değişti. İşte şimdi böyle görünüyor:

extension Bundle {
    var releaseVersionNumber: String? {
        return infoDictionary?["CFBundleShortVersionString"] as? String
    }
    var buildVersionNumber: String? {
        return infoDictionary?["CFBundleVersion"] as? String
    }
}

Bundle.main.releaseVersionNumber
Bundle.main.buildVersionNumber

Eski Güncellenmiş Yanıt

Orijinal yanıtımdan bu yana Frameworks ile çok çalışıyorum, bu yüzden çözümümü çok paketli bir ortamda hem daha basit hem de çok daha kullanışlı bir şeye güncellemek istedim:

extension NSBundle {

    var releaseVersionNumber: String? {
        return self.infoDictionary?["CFBundleShortVersionString"] as? String
    }

    var buildVersionNumber: String? {
        return self.infoDictionary?["CFBundleVersion"] as? String
    }

}

Şimdi bu uzantı, uygulamalarda hem ana paketi hem de dahil edilen diğer paketleri (uzantı programlama için paylaşılan bir çerçeve veya AFNetworking gibi üçüncü çerçeveler gibi) tanımlamak için yararlı olacaktır:

NSBundle.mainBundle().releaseVersionNumber
NSBundle.mainBundle().buildVersionNumber

// or...

NSBundle(URL: someURL)?.releaseVersionNumber
NSBundle(URL: someURL)?.buildVersionNumber

Orijinal Yanıt

Daha önce gönderilen cevapların bazılarında gelişmek istedim. Bunu daha mantıklı bir şekilde ele almak için takım zincirinize eklenebilecek bir sınıf uzantısı yazdım.

extension NSBundle {

class var applicationVersionNumber: String {
    if let version = NSBundle.mainBundle().infoDictionary?["CFBundleShortVersionString"]

gibi? String {return version} return "Sürüm Numarası Mevcut Değil"}

class var applicationBuildNumber: String {
    if let build = NSBundle.mainBundle().infoDictionary?["CFBundleVersion"] as? String {
        return build
    }
    return "Build Number Not Available"
}

}

Artık buna kolayca erişebilirsiniz:

let versionNumber = NSBundle.applicationVersionNumber

CFBundleVersionKey artık Swift 3, Xcode 8'de çalışmıyor. Kullanılacak yeni anahtarı biliyor musunuz?
Crashalot

71

Bunun zaten cevaplanmış olduğunu biliyorum ama önceki cevapları tamamladım:

(*) Uzantılar için güncellendi

extension Bundle {
    var releaseVersionNumber: String? {
        return infoDictionary?["CFBundleShortVersionString"] as? String
    }
    var buildVersionNumber: String? {
        return infoDictionary?["CFBundleVersion"] as? String
    }
    var releaseVersionNumberPretty: String {
        return "v\(releaseVersionNumber ?? "1.0.0")"
    }
}

Kullanımı:

someLabel.text = Bundle.main.releaseVersionNumberPretty

@Deprecated: Eski cevaplar

Hızlı 3.1 :

class func getVersion() -> String {
    guard let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String else {
        return "no version info"
    }
    return version
}

Eski sürümler için :

class func getVersion() -> String {
    if let version = NSBundle.mainBundle().infoDictionary?["CFBundleShortVersionString"] as? String {
        return version
    }
    return "no version info"
}

Etiket metni ayarlamak veya başka bir yerde kullanmak istiyorsanız;

self.labelVersion.text = getVersion()

1
veya: class func getVersion () -> String {return NSBundle.mainBundle (). infoDictionary? ["CFBundleShortVersionString"] olarak? Dize ?? "sürüm bilgisi yok"}
tapmonkey

Bence diğer cevapları kopyalamak mantıklı değil. Cevabınız artık geçerli değilse, o zaman her zaman silme ve diğer cevaplara yer
açma olanağına sahipsiniz

1
@carmen_munich Burada iftira ettiğiniz için size cevap vermem gerekiyor. Her şeyden önce, bu cevap Mart 2015'te ve cevabınız Şubat 2017'de yayınlanmıştır. Bu nedenle, ilhamınızın önceki cevaplardan gelmesi gerekir. İkincisi, cevabınızı hiç görmedim, cevabımı güncelledim çünkü bugünlerde bu şekilde kullanıyorum. Bir uzantı kullanmak, iOS topluluğundaki birine özgü değil sanırım. Gerçekten, lütfen olgun olmaya çalışın ve diğer geliştiricilere saygı gösterin. Burada hiçbir şey kazanmıyorum. İnsanlara bu konuda yardım etmek istiyorum. Lütfen SO'ya yardım etmeye çalışan insanların cesaretini kırmamaya çalışın.
Günhan

Yeni başlayanlardan çok sayıda geri bildirim duydum ve birisinin "yukarı" tıkladığını görmek istiyorlar, ki bu da insanları görmek ve motive etmek için çok güzel. Ama eğer birisi cevaplarını eski cevabına kopyalarsa, postalamak için çaba harcayan kişi, birisinin oy verdiği motivasyonu almayacaktır. Bu yüzden yeni başlayanlar gerçekten hayal kırıklığı hissediyorlar ve topluma değer getirmediklerini ve gönderilmeyi bıraktıklarını hissediyorlar. Ve yanlış anlamayın, genel olarak bunu kastediyorum. Umarım kırgın hissetmezsiniz ve neden bu öneriyi yaptığımı daha iyi anlıyorsunuz.
carmen_munich

@carmen_munich Bu sorunun cevabını kronolojik olarak sipariş ederseniz, bir başkasının sizden daha önce verdiğiniz yanıtın aynısını verdiğini fark edeceksiniz! Yani bana kendin yaptığın bir şeyi suçluyorsun. Bu soru için geçmişim olduğundan, yeni kullanım tercihlerimi bir güncellemede paylaştım. Bu kadar.
Günhan

32

İçin Swift 4.0

let version = Bundle.main.infoDictionary!["CFBundleShortVersionString"]!
let build = Bundle.main.infoDictionary!["CFBundleVersion"]!

29

Paket Üzerinde Eklenti Yaptım

extension Bundle {

    var appName: String {
        return infoDictionary?["CFBundleName"] as! String
    }

    var bundleId: String {
        return bundleIdentifier!
    }

    var versionNumber: String {
        return infoDictionary?["CFBundleShortVersionString"] as! String 
    }

    var buildNumber: String {
        return infoDictionary?["CFBundleVersion"] as! String
    }

}

ve sonra kullan

versionLabel.text = "\(Bundle.main.appName) v \(Bundle.main.versionNumber) (Build \(Bundle.main.buildNumber))"

Aslında biraz farklı. Mesela kuvvet açmayı kullanıyorum. Genel olarak açılmanın kuvvetinin kötü olduğunu düşünebilirsiniz, bu iyi olduğu nadir durumlardan biridir. Biraz daha açıklamak gerekirse, bu değerler sözlükte olmalıdır, aksi takdirde proje dosyasıyla ilgili bir sorun var. Bu yüzden bu yaklaşım güç
açma

Yeniden adlandırma ve açılmayı zorlama, yeni bir yanıt olarak gönderme değişikliği değildir. Ayrıca, insanlar cevabını gördüklerinde güç açmanın herhangi bir yerde kullanılabileceğini öğrenebilirler. Okuyucular için, anahtarın orada olduğunu varsaymayın, açılmayı zorlamak yerine isteğe bağlı açmayı elle işlemek her zaman daha iyidir.
Günhan

Adil olmak gerekirse, kuvvet açmanın iyi olduğu bazı nadir durumlar vardır. Bu yazı sadece iyi olabileceği bir durumu gösteriyor. Kuvvet çözme vakaları hakkında daha fazla bilgi edinmek istiyorsanız, Paul Hudson'dan bazı iyi açıklamalar ve öğreticiler var. Gerçekten tüm yeni başlayanlar için tavsiye ederim www.hackingwithswift.com
carmen_munich

Yeni başlayanlar için iyi bir öneri. Belki daha fazla okuyabilir ve daha fazla bilgi edinebilirsiniz. Ayrıca yorumlar ve ne ima ettikleri hakkındaki anlayışınızı geliştirmelisiniz. Örneğin, hiç kimse size asla / açmadan güç kullanmamanızı söylemedi. Ancak bilgi için bu anahtarlar çıkarılabilir ve açma kuvveti çökmeye neden olabilir. Sarma işlemini burada yapmak daha güvenlidir.
Günhan

Belki hangi durumda çıkarılabileceğini ve sıfır olabileceğini açıklayabilirsiniz. Kaynaktan öğrendiklerim bu kısmi açıklama durumunda değil. Proje dosyası
bozulmadıkça

16

Swift 3.0 NSBundle için çalışmıyor, Aşağıdaki kod mükemmel çalışıyor.

let versionNumberString =
      Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString")
          as! String

ve sadece yapı numarası için:

let buildNumberString =
      Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion")
          as! String

Kafa karıştırıcı bir şekilde 'CFBundleVersion', General-> Identity'de Xcode'da girildiği gibi yapı numarasıdır.


16

Xcode 9.4.1 Hızlı 4.1

Paket görünen adının doğru dil sürümünü almak için localizedInfoDictionary kullanımına dikkat edin.

var displayName: String?
var version: String?
var build: String?

override func viewDidLoad() {
    super.viewDidLoad()

    // Get display name, version and build

    if let displayName = Bundle.main.localizedInfoDictionary?["CFBundleDisplayName"] as? String {
        self.displayName = displayName
    }
    if let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String {
        self.version = version
    }
    if let build = Bundle.main.infoDictionary?["CFBundleVersion"] as? String {
        self.build = build
    }
}

14

Xcode 8, Swift 3:

let gAppVersion = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") ?? "0"
let gAppBuild = Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion") ?? "0"

13

Swift 4, Paket için kullanışlı Uzantı

import Foundation

public extension Bundle {

    public var shortVersion: String {
        if let result = infoDictionary?["CFBundleShortVersionString"] as? String {
            return result
        } else {
            assert(false)
            return ""
        }
    }

    public var buildVersion: String {
        if let result = infoDictionary?["CFBundleVersion"] as? String {
            return result
        } else {
            assert(false)
            return ""
        }
    }

    public var fullVersion: String {
        return "\(shortVersion)(\(buildVersion))"
    }
}

Bunu kullanmak için örneğin Bundle.main.fullVersion demelisiniz
Joseph Astrahan

12

Paketi + Extensions.swift

import Foundation

extension Bundle {
    var versionNumber: String? {
        return infoDictionary?["CFBundleShortVersionString"] as? String
    }

    var buildNumber: String? {
        return infoDictionary?["CFBundleVersion"] as? String
    }

    var bundleName: String? {
        return infoDictionary?["CFBundleName"] as? String
    }
}

Kullanımı:

someLabel.text = Bundle.main.versionNumber

11

OP hem sürüm numarasını hem de yapı numarasını istedi. Maalesef cevapların çoğu bu seçeneklerin ikisini de sağlamaz. Ayrıca, diğerleri gereksiz genişletme yöntemleri ekler. İşte oldukça basit ve OP'nin problemini çözen:

// Example output: "1.0 (234)"
private func versionAndBuildNumber() -> String {
  let versionNumber = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String
  let buildNumber = Bundle.main.infoDictionary?["CFBundleVersion"] as? String
  if let versionNumber = versionNumber, let buildNumber = buildNumber {
    return "\(versionNumber) (\(buildNumber))"
  } else if let versionNumber = versionNumber {
    return versionNumber
  } else if let buildNumber = buildNumber {
    return buildNumber
  } else {
    return ""
  }
}

9

Swift'in gelişmeye devam etmesi nedeniyle cevabım (Ağustos 2015'te olduğu gibi):

let version = NSBundle.mainBundle().infoDictionary!["CFBundleVersion"] as! String

8

UIApplication için bir uzantı oluşturdum.

extension UIApplication {
    static var appVersion: String {
        let versionNumber = Bundle.main.infoDictionary?[IdentifierConstants.InfoPlist.versionNumber] as? String
        let buildNumber = Bundle.main.infoDictionary?[IdentifierConstants.InfoPlist.buildNumber] as? String

        let formattedBuildNumber = buildNumber.map {
            return "(\($0))"
        }

        return [versionNumber,formattedBuildNumber].compactMap { $0 }.joined(separator: " ")
    }
}

struct IdentifierConstants {
    struct InfoPlist {
        static let versionNumber = "CFBundleShortVersionString"
        static let buildNumber = "CFBundleVersion"
    }
}

6

Belgelere baktığımda, aşağıdakilerin daha temiz olduğuna inanıyorum:

let version = 
NSBundle.mainBundle().objectForInfoDictionaryKey("CFBundleShortVersionString") 
as? String

Kaynak : "Bu yöntem, bir anahtar kullanılabilir olduğunda bir anahtarın yerelleştirilmiş değerini döndürdüğü için diğer erişim yöntemlerine göre tercih edilir."


1
Bu doğru Swift yolu, hiçbir yerde
açma

5

Swift 1.2 için:

let version = NSBundle.mainBundle().infoDictionary!["CFBundleShortVersionString"] as! String
let build = NSBundle.mainBundle().infoDictionary!["CFBundleVersion"] as! String

1
kullanabilirsin ? as well
Dan Rosenstark

4

Hızlı 3:

Versiyon numarası

if let versionNumberString = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String { // do something }

Yapı numarası

if let buildNumberString = Bundle.main.infoDictionary?["CFBundleVersion"] as? String { // do something }

Yapı numarası nasıl? Teşekkürler! CFBundleVersionKey çalışmıyor.
Crashalot

@Crashalot Ben de derleme numarası ile güncelledim. Ayrıca tüm Temel Temel Anahtarlarının bir listesi: developer.apple.com/library/content/documentation/General/…
jasonnoahchoi

3

Hızlı 4

func getAppVersion() -> String {
    return "\(Bundle.main.infoDictionary!["CFBundleShortVersionString"] ?? "")"
}

Bundle.main.infoDictionary! [ "CFBundleShortVersionString"]

Hızlı eski sözdizimi

let appVer: AnyObject? = NSBundle.mainBundle().infoDictionary!["CFBundleShortVersionString"]

2
extension UIApplication {

    static var appVersion: String {
        if let appVersion = NSBundle.mainBundle().objectForInfoDictionaryKey("CFBundleShortVersionString") {
            return "\(appVersion)"
        } else {
            return ""
        }
    }

    static var build: String {
        if let buildVersion = NSBundle.mainBundle().objectForInfoDictionaryKey(kCFBundleVersionKey as String) {
            return "\(buildVersion)"
        } else {
            return ""
        }
    }

    static var versionBuild: String {
        let version = UIApplication.appVersion
        let build = UIApplication.build

        var versionAndBuild = "v\(version)"

        if version != build {
            versionAndBuild = "v\(version)(\(build))"
        }

        return versionAndBuild
    }

}

Dikkat: Eğer uygulama sürümü veya derlemesi ayarlanmadıysa, eğer kullanmaya çalışırsanız çökmeye neden olacaksa burada kullanmalısınız! açmak için.


2

İşte Swift 3.2 için güncellenmiş bir sürüm:

extension UIApplication
{
    static var appVersion:String
    {
        if let appVersion = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString")
        {
            return "\(appVersion)"
        }
        return ""
    }

    static var buildNumber:String
    {
        if let buildNum = Bundle.main.object(forInfoDictionaryKey: kCFBundleVersionKey as String)
        {
            return "\(buildNum)"
        }
        return ""
    }

    static var versionString:String
    {
        return "\(appVersion).\(buildNumber)"
    }
}

2

Artık bunun için daha önce olduğu gibi dize türünde bir kod kullanmak zorunda kalmak yerine, bunun için bir sabit kullanabilirsiniz.

var appVersion: String {
    return Bundle.main.infoDictionary![kCFBundleVersionKey as String] as! String
}

2
public var appVersionNumberString: String {
    get {
        return Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as! String
    }
}

1

SWIFT 4

// Önce isteğe bağlı AnyObject olarak tanımlayarak nsObject'i edinin

let nsObject: AnyObject? = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as AnyObject

// Sonra nesneyi bir String olarak yayınlayın, ancak dikkatli olun, nil'i iki kez kontrol etmek isteyebilirsiniz

let version = nsObject as! String

1

ilgilenen herkes için, adlı güzel ve düzgün kütüphane var SwifterSwiftmevcut github ve de tam Swift her sürümü için belgelenmiş (bkz swifterswift.com ).

bu kütüphaneyi kullanarak, uygulama sürümünü ve derleme numarasını okumak şu kadar kolay olurdu:

import SwifterSwift

let buildNumber = SwifterSwift.appBuild
let version = SwifterSwift.appVersion

1

Swift 5 için güncelleme

"uygulama güncellendi" sayfasını gösterip göstermemeye karar vermek için kullandığım bir işlev var. Bir Int dönüştürdüğüm yapı numarasını döndürür:

if let version: String = Bundle.main.infoDictionary?["CFBundleVersion"] as? String {
        guard let intVersion = Int(version) else { return }

        if UserDefaults.standard.integer(forKey: "lastVersion") < intVersion {
            print("need to show popup")
        } else {
            print("Don't need to show popup")
        }

        UserDefaults.standard.set(intVersion, forKey: "lastVersion")
    }

Daha önce hiç kullanılmamışsa, mevcut yapı numarasından daha düşük olan 0 değerini döndürür. Böyle bir ekranı yeni kullanıcılara göstermemek için, ilk girişten sonra veya yerleşik tamamlandığında derleme numarasını eklemeniz yeterlidir.


1

For Swift 5.0 :

let appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as! String

1

Uygulama sürümünü Int olarak döndürmek için basit yardımcı işlev

func getAppVersion() -> Int {

        if let appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String {

            let appVersionClean = appVersion.replacingOccurrences(of: ".", with: "", options: NSString.CompareOptions.literal, range:nil)

            if let appVersionNum = Int(appVersionClean) {
                return appVersionNum
            }
        }
        return 0
    }

1
if let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String {
            self.lblAppVersionValue.text = version
        }

1

Paket + Uzantı.swift (SwiftUI, Swift 5, Xcode 11)

Birkaç cevaptan gelen fikirleri birleştirdim ve biraz genişlettim:

  • SwiftUI örneği
  • Anahtar Info.plist'te yoksa, bir üçgen reflektör ifadesi (uygulamayı kilitlemek yerine) görüntüler

ithalat Vakfı

uzantı Paketi {

public var appVersionShort: String? {
    if let result = infoDictionary?["CFBundleShortVersionString"] as? String {
        return result
    } else {
        return "⚠️"
    }
}
public var appVersionLong: String? {
    if let result = infoDictionary?["CFBundleVersion"] as? String {
        return result
    } else {
        return "⚠️"
    }
}
public var appName: String? {
    if let result = infoDictionary?["CFBundleName"] as? String {
        return result
    } else {
        return "⚠️"
    }
}

}


SwiftUI örnek kullanımı

VStack {

     Text("Version: \(Bundle.main.appVersionShort!) (\(Bundle.main.appVersionLong!))")
                    .font(.subheadline)
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
}

0
if let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String {
        lblVersion.text = "Version \(version)"

    }
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.