diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 3213ca9..d3d3db0 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -1,7 +1,7 @@
name: Build
-on: [push, pull_request]
+on: [push]
jobs:
build:
@@ -14,3 +14,13 @@ jobs:
- name: Build
run: swift build -v
+
+ build-android:
+ name: Build Android
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - name: "Test Swift Package on Android"
+ uses: skiptools/swift-android-action@v2
+ with:
+ run-tests: false
diff --git a/.github/workflows/swiftlint.yml b/.github/workflows/swiftlint.yml
index f004099..468cd9a 100644
--- a/.github/workflows/swiftlint.yml
+++ b/.github/workflows/swiftlint.yml
@@ -1,7 +1,7 @@
name: Swiftlint
-on: [push, pull_request]
+on: [push]
jobs:
swiftlint:
@@ -14,4 +14,4 @@ jobs:
- name: GitHub Action for SwiftLint with --strict
uses: norio-nomura/action-swiftlint@3.1.0
with:
- args: --strict
\ No newline at end of file
+ args: --strict
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 9092dea..67b62e5 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -1,7 +1,7 @@
name: Test
-on: [push, pull_request]
+on: [push]
jobs:
test:
@@ -13,4 +13,12 @@ jobs:
uses: actions/checkout@v4
- name: Test
- run: swift test -v --enable-test-discovery --enable-code-coverage --sanitize=thread
\ No newline at end of file
+ run: swift test -v --enable-test-discovery --enable-code-coverage --sanitize=thread
+
+ test-android:
+ name: Test Android
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - name: "Test Swift Package on Android"
+ uses: skiptools/swift-android-action@v2
diff --git a/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata b/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
index 706eede..919434a 100644
--- a/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
+++ b/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
@@ -2,6 +2,6 @@
+ location = "self:">
diff --git a/Package.resolved b/Package.resolved
new file mode 100644
index 0000000..6e0eda8
--- /dev/null
+++ b/Package.resolved
@@ -0,0 +1,15 @@
+{
+ "originHash" : "86d3c80e950364bab61f36d013b45300638a34fdb39bd15bb3b25d4c933a82e4",
+ "pins" : [
+ {
+ "identity" : "swift-android-native",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/skiptools/swift-android-native.git",
+ "state" : {
+ "revision" : "c0d6a8422a04bea5f953e8f09efb5344515545ab",
+ "version" : "1.1.0"
+ }
+ }
+ ],
+ "version" : 3
+}
diff --git a/Package.swift b/Package.swift
index 2bfda60..d2de48e 100644
--- a/Package.swift
+++ b/Package.swift
@@ -6,6 +6,7 @@ import PackageDescription
//swiftlint:disable all
let package = Package(
name: "LogKit",
+ platforms: [.macOS(.v11), .iOS(.v14), .macCatalyst(.v14), .tvOS(.v14), .watchOS(.v7), .visionOS(.v1)],
products: [
// Products define the executables and libraries produced by a package, and make them visible to other packages.
.library(
@@ -19,14 +20,16 @@ let package = Package(
],
dependencies: [
// Dependencies declare other packages that this package depends on.
- // .package(url: /* package url */, from: "1.0.0"),
+ .package(url: "https://github.com/skiptools/swift-android-native.git", from: "1.0.0")
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
// Targets can depend on other targets in this package, and on products in packages which this package depends on.
.target(
name: "LogKit",
- dependencies: []),
+ dependencies: [
+ .product(name: "AndroidLogging", package: "swift-android-native", condition: .when(platforms: [.android]))
+ ]),
.testTarget(
name: "LogKitTests",
dependencies: ["LogKit"])
diff --git a/README.md b/README.md
index 6fbcad3..93ac180 100644
--- a/README.md
+++ b/README.md
@@ -1,14 +1,16 @@
# LogKit
-    [](https://github.com/apple/swift-package-manager)  
+    [](https://github.com/apple/swift-package-manager)  
LogKit is logging framework to simplify work with `os.log` API provided by Apple.
-## Requirements
-- iOS 10.0+
-- watchOS 3.0+
-- macOS 10.12+
-- tvOS 10.0+
+## Support
+- iOS 14.0+
+- watchOS 7.0+
+- macOS 11+
+- tvOS 14.0+
+- visionOS 1.0+
+- Android
## Installation
@@ -32,7 +34,7 @@ import PackageDescription
let package = Package(
name: "LogKitExample",
dependencies: [
- .package(url: "https://github.com/marekpridal/LogKit", from: "2.0.0")
+ .package(url: "https://github.com/marekpridal/LogKit", from: "3.0.0")
],
targets: [
.target(name: "LogKitExample", dependencies: ["LogKit"])
@@ -139,4 +141,4 @@ Log.payment(transactions: transactions)
// []
// ----------------------------
-```
\ No newline at end of file
+```
diff --git a/Sources/LogKit/LogKit.swift b/Sources/LogKit/LogKit.swift
index aba683e..5d5bfc2 100644
--- a/Sources/LogKit/LogKit.swift
+++ b/Sources/LogKit/LogKit.swift
@@ -6,10 +6,15 @@
//
import Foundation
-import os.log
+#if os(Android) || os(Windows) || os(Linux)
+import AndroidLogging
+import FoundationNetworking
+#else
+import OSLog
import StoreKit
+#endif
-@available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *)
+@available(OSX 11, iOS 10.0, watchOS 3.0, tvOS 10.0, *)
public enum Log {
public enum Category: String, CaseIterable, Sendable {
case `deinit`
@@ -23,42 +28,46 @@ public enum Log {
case dependencyInjection
}
+#if canImport(Darwin)
nonisolated(unsafe) public static var subsystem = Bundle.main.bundleIdentifier!
+#elseif os(Android)
+ nonisolated(unsafe) public static var subsystem = "com.logkit.android"
+#endif
nonisolated(unsafe) public static var enabledLogging: [Category] = Category.allCases
-
+#if canImport(Darwin)
public static func `deinit`(of object: AnyObject) {
guard enabledLogging.contains(.deinit) else { return }
- let deinitLog = OSLog(subsystem: subsystem, category: Category.deinit.rawValue)
- os_log("Deinit of %{PRIVATE}@", log: deinitLog, type: .info, object.debugDescription ?? "")
+ let logger = Logger(subsystem: subsystem, category: Category.deinit.rawValue)
+ logger.info("Deinit of \(object.debugDescription ?? "")")
}
-
+#endif
public static func function(_ function: String, in file: String) {
guard enabledLogging.contains(.function) else { return }
- let deinitLog = OSLog(subsystem: subsystem, category: Category.function.rawValue)
- os_log("%{PRIVATE}@ %{PRIVATE}@", log: deinitLog, type: .debug, function, file)
+ let logger = Logger(subsystem: subsystem, category: Category.function.rawValue)
+ logger.debug("\(function) \(file)")
}
public static func `default`(_ string: String) {
guard enabledLogging.contains(.default) else { return }
- let deinitLog = OSLog(subsystem: subsystem, category: Category.default.rawValue)
- os_log("%{PRIVATE}@", log: deinitLog, type: .debug, string)
+ let logger = Logger(subsystem: subsystem, category: Category.default.rawValue)
+ logger.debug("\(string)")
}
public static func requestCalled(function: String) {
guard enabledLogging.contains(.networking) else { return }
- let deinitLog = OSLog(subsystem: subsystem, category: Category.networking.rawValue)
- os_log("%{PRIVATE}@ already called", log: deinitLog, type: .debug, function)
+ let logger = Logger(subsystem: subsystem, category: Category.networking.rawValue)
+ logger.debug("\(function) already called")
}
public static func expiration(date: Date) {
guard enabledLogging.contains(.expiration) else { return }
- let deinitLog = OSLog(subsystem: subsystem, category: Category.expiration.rawValue)
- os_log("[GMT] Valid until %{PRIVATE}@", log: deinitLog, type: .debug, date.debugDescription)
+ let logger = Logger(subsystem: subsystem, category: Category.expiration.rawValue)
+ logger.debug("[GMT] Valid until \(date.debugDescription)")
}
public static func request(_ request: URLRequest) {
guard enabledLogging.contains(.networking) else { return }
- let deinitLog = OSLog(subsystem: subsystem, category: Category.networking.rawValue)
+ let logger = Logger(subsystem: subsystem, category: Category.networking.rawValue)
var message = "\n---REQUEST------------------\n"
message.append("URL -> \((request.url?.absoluteString ?? ""))\n")
message.append("METHOD -> \(request.httpMethod ?? "")\n")
@@ -71,12 +80,12 @@ public enum Log {
message.append("BODY -> \(String(data: body, encoding: .utf8) ?? "")\n")
}
message.append("----------------------------\n")
- os_log("%{PRIVATE}@", log: deinitLog, type: .debug, message)
+ logger.debug("\(message)")
}
public static func response(_ response: URLResponse?, data: Data?) {
guard enabledLogging.contains(.networking) else { return }
- let deinitLog = OSLog(subsystem: subsystem, category: Category.networking.rawValue)
+ let logger = Logger(subsystem: subsystem, category: Category.networking.rawValue)
guard let response = response, let data = data else { return }
var message = "\n---RESPONSE------------------\n"
message.append("URL -> \(response.url?.absoluteString ?? "")\n")
@@ -89,89 +98,84 @@ public enum Log {
message.append("}\n")
message.append("Response data -> \(String(data: data, encoding: .utf8) ?? "")\n")
message.append("----------------------------\n")
- os_log("%{PRIVATE}@", log: deinitLog, type: .debug, message)
+ logger.debug("\(message)")
}
public static func function(_ function: String, text: String) {
guard enabledLogging.contains(.function) else { return }
- let deinitLog = OSLog(subsystem: subsystem, category: Category.function.rawValue)
- os_log("%{PRIVATE}@ %{PRIVATE}@", log: deinitLog, type: .debug, function, text)
+ let logger = Logger(subsystem: subsystem, category: Category.function.rawValue)
+ logger.debug("\(function) \(text)")
}
public static func inAppPurchase(_ string: String) {
guard enabledLogging.contains(.inAppPurchase) else { return }
- let deinitLog = OSLog(subsystem: subsystem, category: Category.inAppPurchase.rawValue)
- os_log("%{PRIVATE}@", log: deinitLog, type: .debug, string)
+ let logger = Logger(subsystem: subsystem, category: Category.inAppPurchase.rawValue)
+ logger.debug("\(string)")
}
public static func error(_ error: Error) {
guard enabledLogging.contains(.error) else { return }
- let deinitLog = OSLog(subsystem: subsystem, category: Category.error.rawValue)
- os_log("%{PRIVATE}@", log: deinitLog, type: .error, error.localizedDescription)
+ let logger = Logger(subsystem: subsystem, category: Category.error.rawValue)
+ logger.debug("\(error.localizedDescription)")
}
public static func database(_ string: String) {
guard enabledLogging.contains(.database) else { return }
- let log = OSLog(subsystem: subsystem, category: LogKit.Log.Category.database.rawValue)
- os_log("%{PRIVATE}@", log: log, type: .debug, string)
+ let logger = Logger(subsystem: subsystem, category: Category.database.rawValue)
+ logger.debug("\(string)")
}
public static func dependencyInjection(_ string: String) {
guard enabledLogging.contains(.dependencyInjection) else { return }
- let log = OSLog(subsystem: subsystem, category: LogKit.Log.Category.dependencyInjection.rawValue)
- os_log("%{PRIVATE}@", log: log, type: .debug, string)
+ let logger = Logger(subsystem: subsystem, category: Category.dependencyInjection.rawValue)
+ logger.debug("\(string)")
}
-
- @available(watchOS 6.2, *)
+#if canImport(Darwin)
public static func products(request: SKProductsRequest) {
guard enabledLogging.contains(.inAppPurchase) else { return }
- let deinitLog = OSLog(subsystem: subsystem, category: Category.inAppPurchase.rawValue)
+ let logger = Logger(subsystem: subsystem, category: Category.inAppPurchase.rawValue)
var requestMessage = "\n---REQUEST------------------\n"
requestMessage.append("\(request)")
requestMessage.append("\n----------------------------\n")
- os_log("%{PRIVATE}@", log: deinitLog, type: .debug, requestMessage)
+ logger.debug("\(requestMessage)")
}
- @available(watchOS 6.2, *)
public static func products(response: SKProductsResponse) {
guard enabledLogging.contains(.inAppPurchase) else { return }
- let deinitLog = OSLog(subsystem: subsystem, category: Category.inAppPurchase.rawValue)
+ let logger = Logger(subsystem: subsystem, category: Category.inAppPurchase.rawValue)
var responseMessage = "\n---RESPONSE------------------\n"
responseMessage.append("Invalid product identifiers \(response.invalidProductIdentifiers)")
responseMessage.append("\n----------------------------\n")
responseMessage.append("Products \(response.products)")
responseMessage.append("\n----------------------------\n")
- os_log("%{PRIVATE}@", log: deinitLog, type: .debug, responseMessage)
+ logger.debug("\(responseMessage)")
}
- @available(watchOS 6.2, *)
public static func products(request: SKRequest) {
guard enabledLogging.contains(.inAppPurchase) else { return }
- let deinitLog = OSLog(subsystem: subsystem, category: Category.inAppPurchase.rawValue)
+ let logger = Logger(subsystem: subsystem, category: Category.inAppPurchase.rawValue)
var requestMessage = "\n---REQUEST------------------\n"
requestMessage.append("\(request)")
requestMessage.append("\n----------------------------\n")
- Log.default(requestMessage)
- os_log("%{PRIVATE}@", log: deinitLog, type: .debug, requestMessage)
+ logger.debug("\(requestMessage)")
}
- @available(watchOS 6.2, *)
public static func paymentQueue(_ queue: SKPaymentQueue) {
guard enabledLogging.contains(.inAppPurchase) else { return }
- let deinitLog = OSLog(subsystem: subsystem, category: Category.inAppPurchase.rawValue)
+ let logger = Logger(subsystem: subsystem, category: Category.inAppPurchase.rawValue)
var requestMessage = "\n---QUEUE------------------\n"
requestMessage.append("\(queue)")
requestMessage.append("\n----------------------------\n")
- os_log("%{PRIVATE}@", log: deinitLog, type: .debug, requestMessage)
+ logger.debug("\(requestMessage)")
}
- @available(watchOS 6.2, *)
public static func payment(transactions: [SKPaymentTransaction]) {
guard enabledLogging.contains(.inAppPurchase) else { return }
- let deinitLog = OSLog(subsystem: subsystem, category: Category.inAppPurchase.rawValue)
+ let logger = Logger(subsystem: subsystem, category: Category.inAppPurchase.rawValue)
var responseMessage = "\n---UPDATED TRANSACTIONS------------------\n"
responseMessage.append("\(transactions)")
responseMessage.append("\n----------------------------\n")
- os_log("%{PRIVATE}@", log: deinitLog, type: .debug, responseMessage)
+ logger.debug("\(responseMessage)")
}
+#endif
}
diff --git a/Tests/LinuxMain.swift b/Tests/LinuxMain.swift
deleted file mode 100644
index c3e2227..0000000
--- a/Tests/LinuxMain.swift
+++ /dev/null
@@ -1 +0,0 @@
-fatalError("Running tests like this is unsupported. Run the tests again by using `swift test --enable-test-discovery`")
diff --git a/Tests/LogKitTests/LogKitTests.swift b/Tests/LogKitTests/LogKitTests.swift
index 89778e6..d520ca2 100644
--- a/Tests/LogKitTests/LogKitTests.swift
+++ b/Tests/LogKitTests/LogKitTests.swift
@@ -1,8 +1,11 @@
+#if !os(Android) && !os(Windows) && !os(Linux)
import StoreKit
+#else
+import FoundationNetworking
+#endif
import XCTest
@testable import LogKit
-@available(OSX 10.12, *)
final class LogKitTests: XCTestCase {
private var log: LogKit.Log.Type {
let log = Log.self
@@ -21,11 +24,11 @@ final class LogKitTests: XCTestCase {
private struct Foo: Encodable {
let bar: String
}
-
+#if !os(Android) && !os(Windows) && !os(Linux)
func testLogDeinit() {
log.deinit(of: self)
}
-
+#endif
func testLogFunctionIn() {
log.function(#function, in: #file)
log.function(#function, text: "text")
@@ -44,9 +47,7 @@ final class LogKitTests: XCTestCase {
}
func testLogRequest() {
- log.request(URLRequest(url: URL(string: "https://github.com/marekpridal/LogKit")!,
- cachePolicy: .useProtocolCachePolicy,
- timeoutInterval: 30))
+ log.request(URLRequest(url: URL(string: "https://github.com/marekpridal/LogKit")!))
}
func testLogResponse() {
@@ -66,7 +67,7 @@ final class LogKitTests: XCTestCase {
func testLogError() {
log.error(NSError(domain: "logkit.tests", code: 0, userInfo: nil))
}
-
+#if !os(Android) && !os(Windows) && !os(Linux)
func testLogSKRequest() {
log.products(request: .init(productIdentifiers: ["logkit_product_identifier"]))
}
@@ -86,4 +87,5 @@ final class LogKitTests: XCTestCase {
func testLogPayment() {
log.payment(transactions: [.init()])
}
+#endif
}
diff --git a/assets/xcframework-asset.png b/assets/xcframework-asset.png
deleted file mode 100644
index b830337..0000000
Binary files a/assets/xcframework-asset.png and /dev/null differ