Skip to content

Commit

Permalink
6 device info for ios (#7)
Browse files Browse the repository at this point in the history
* feat: wip

* feat: wip

* feat: storage

* feat: battery

* feat: constant

* feat: network

* feat: location

* feat: headphone

* feat: brightness

* feat: typography

* feat: web

* feat: arch

* feat: la

* feat: others
  • Loading branch information
duguyihou authored Oct 26, 2023
1 parent 3f452a5 commit 1815c6c
Show file tree
Hide file tree
Showing 17 changed files with 825 additions and 6 deletions.
15 changes: 13 additions & 2 deletions example/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,29 @@
import * as React from 'react';

import { StyleSheet, View, Text } from 'react-native';
import { multiply } from 'react-native-turbo-device';
import { getTotalDiskCapacity, multiply } from 'react-native-turbo-device';

export default function App() {
const [result, setResult] = React.useState<number | undefined>();

const [totalDiskCapacity, setTotalDiskCapacity] = React.useState<
number | undefined
>();
React.useEffect(() => {
multiply(3, 7).then(setResult);
}, []);

React.useEffect(() => {
const a = async () => {
const total = await getTotalDiskCapacity();
setTotalDiskCapacity(total);
};
a();
}, []);

return (
<View style={styles.container}>
<Text>Result: {result}</Text>
<Text>TotalDiskCapacity: {totalDiskCapacity}</Text>
</View>
);
}
Expand Down
10 changes: 10 additions & 0 deletions ios/TurboDevice+arch.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import Foundation
import MachO

extension TurboDevice {
private func getSupportedAbis(_ resolve: @escaping RCTPromiseResolveBlock,
reject: @escaping RCTPromiseRejectBlock) {
guard let archRaw = NXGetLocalArchInfo().pointee.name else { return resolve("unknown") }
resolve(String(cString: archRaw))
}
}
79 changes: 79 additions & 0 deletions ios/TurboDevice+battery.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import Foundation

extension TurboDevice {

var powerState: [String:Any] {

#if RCT_DEV && !targetEnvironment(simulator) && !os(tvOS)
if !UIDevice.current.isBatteryMonitoringEnabled {
RCTLogWarn("Battery monitoring is not enabled. You need to enable monitoring with `UIDevice.current.isBatteryMonitoringEnabled = true`")
}
#endif
#if RCT_DEV && targetEnvironment(simulator) && !os(tvOS)
if UIDevice.current.batteryState == .unknown {
RCTLogWarn("Battery state `unknown` and monitoring disabled, this is normal for simulators and tvOS.")
}
#endif
let batteryLevel = UIDevice.current.batteryLevel
#if os(tvOS)
return [
"batteryLevel": batteryLevel,
"batteryState": "full"
]
#else
let batteryState = {
let state = UIDevice.current.batteryState
switch state {
case .full:
return "full"
case .charging:
return "charging"
case .unplugged:
return "unplugged"
default:
return "unknown"
}
}()
let lowPowerMode = ProcessInfo.processInfo.isLowPowerModeEnabled
return [
"batteryLevel": batteryLevel,
"batteryState": batteryState,
"lowPowerMode": lowPowerMode,
]
#endif
}

@objc
func batteryLevelDidChange(_ notification: Notification) {
let batteryLevel = UIDevice.current.batteryLevel
sendEvent(withName: "TurboDevice_batteryLevelDidChange", body: [batteryLevel])

if batteryLevel <= kLowBatteryThreshold {
sendEvent(withName: "TurboDevice_batteryLevelIsLow", body: [batteryLevel])
}
}

@objc
private func getBatteryLevel(_ resolve: @escaping RCTPromiseResolveBlock,
reject: @escaping RCTPromiseRejectBlock) {
#if os(tvOS)
resolve(Float(1))
#else
resolve(UIDevice.current.batteryLevel)
#endif
}

@objc
func powerStateDidChange() {
sendEvent(withName: "TurboDevice_powerStateDidChange", body: [powerState])
}

@objc
func isBatteryCharging(_ resolve: @escaping RCTPromiseResolveBlock,
reject: @escaping RCTPromiseRejectBlock) {
guard let batteryState = powerState["batteryState"] as? UIDevice.BatteryState
else { return reject("isBatteryCharging failed", nil, nil)}
let isCharging = batteryState == .charging
resolve(isCharging)
}
}
19 changes: 19 additions & 0 deletions ios/TurboDevice+brightness.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import Foundation

extension TurboDevice {
@objc
func brightnessDidChange() {
let brightness = UIScreen.main.brightness
sendEvent(withName: "TurboDevice_brightnessDidChange", body: [brightness])
}

@objc
func getBrightness(_ resolve: @escaping RCTPromiseResolveBlock,
reject: @escaping RCTPromiseRejectBlock) {
#if !os(tvOS)
resolve(UIScreen.main.brightness)
#else
resolve(CGFloat(-1))
#endif
}
}
105 changes: 105 additions & 0 deletions ios/TurboDevice+constant.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import Foundation

enum DeviceType: String {
case Handset = "Handset"
case Tablet = "Tablet"
case Tv = "Tv"
case Desktop = "Desktop"
case Unknown = "Unknown"

func getDeviceTypeName() -> String {
switch self {
case .Handset:
return DeviceType.Handset.rawValue
case .Tablet:
return DeviceType.Tablet.rawValue
case .Tv:
return DeviceType.Tv.rawValue
case .Desktop:
return DeviceType.Desktop.rawValue
default:
return DeviceType.Unknown.rawValue
}
}
}

extension TurboDevice {
func getBundleId() -> Any {
let buildId = Bundle.main.object(forInfoDictionaryKey: "CFBundleIdentifier")
return buildId ?? "unknown"
}

func getSystemName() -> Any {
return UIDevice.current.systemName
}

func getSystemVersion() -> Any {
return UIDevice.current.systemVersion
}

func getAppVersion() -> Any {
let appVersion = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString")
return appVersion ?? "unknown"
}

func getBuildNumber() -> Any {
let buildNumber = Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion")
return buildNumber ?? "unknown"
}

func getAppName() -> Any {
let displayName = Bundle.main.object(forInfoDictionaryKey: "CFBundleDisplayName")
let bundleName = Bundle.main.object(forInfoDictionaryKey: "CFBundleName")!

return displayName ?? bundleName
}

func isTablet() -> Bool {
return getDeviceType() == .Tablet
}

func getDeviceTypeName() -> Any {
let deviceType = getDeviceType()
let deviceTypeName = DeviceType.getDeviceTypeName(deviceType)
return deviceTypeName
}

func getDeviceType() -> DeviceType {
let userInterfaceIdiom = UIDevice.current.userInterfaceIdiom
switch userInterfaceIdiom {
case .phone:
return .Handset
case .pad:
#if targetEnvironment(macCatalyst)
return .Desktop
#endif
if #available(iOS 14, *) {
if ProcessInfo.processInfo.isiOSAppOnMac {
return .Desktop
}
}
return .Tablet
case .tv:
return .Tv
case .mac:
return .Desktop
default:
return .Unknown
}
}
// TODO: - 🐵 use scene
func isDisplayZoomed() -> Bool {
return UIScreen.main.scale != UIScreen.main.nativeScale
}
}

extension TurboDevice {
private func getBuildId() -> String {
#if os(tvOS)
return "unknown"
#else
let buildNumber = Bundle.main.object(forInfoDictionaryKey: kCFBundleVersionKey as String) as! String
return buildNumber
#endif
}
}
33 changes: 33 additions & 0 deletions ios/TurboDevice+headphone.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import Foundation
import AVFoundation

extension TurboDevice {
@objc
func isHeadphonesConnected(_ resolve: @escaping RCTPromiseResolveBlock,
reject: @escaping RCTPromiseRejectBlock) {
let currentRoute = AVAudioSession.sharedInstance().currentRoute
for desc in currentRoute.outputs {
let portType = desc.portType
if portType == .headphones || portType == .bluetoothA2DP || portType == .bluetoothHFP {
resolve(true)
}
}
resolve(false)
}

@objc
func headphoneConnectionDidChange() {
let isConnected = {
let currentRoute = AVAudioSession.sharedInstance().currentRoute
for desc in currentRoute.outputs {
let portType = desc.portType
if portType == .headphones || portType == .bluetoothA2DP || portType == .bluetoothHFP {
return true
}
}
return false
}()
sendEvent(withName: "TurboDevice_headphoneConnectionDidChange", body: [isConnected])
}

}
16 changes: 16 additions & 0 deletions ios/TurboDevice+localAuthentication.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import Foundation
#if !os(tvOS)
import LocalAuthentication
#endif

extension TurboDevice {
private func isPinOrFingerprintSet(_ resolve: @escaping RCTPromiseResolveBlock,
reject: @escaping RCTPromiseRejectBlock) {
#if os(tvOS)
resolve(false)
#else
let evaluated = LAContext().canEvaluatePolicy(.deviceOwnerAuthentication, error: nil)
resolve(evaluated)
#endif
}
}
35 changes: 35 additions & 0 deletions ios/TurboDevice+location.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import Foundation
import CoreLocation

extension TurboDevice {
@objc
func isLocationEnabled(_ resolve: @escaping RCTPromiseResolveBlock,
reject: @escaping RCTPromiseRejectBlock) {
let enabled = CLLocationManager.locationServicesEnabled()
resolve(enabled)
}

@objc
func getAvailableLocationProviders(_ resolve: @escaping RCTPromiseResolveBlock,
reject: @escaping RCTPromiseRejectBlock) {
#if !os(tvOS)
let locationServicesEnabled = CLLocationManager.locationServicesEnabled()
let significantLocationChangeMonitoringAvailable = CLLocationManager.significantLocationChangeMonitoringAvailable()
let headingAvailable = CLLocationManager.headingAvailable()
let isRangingAvailable = CLLocationManager.isRangingAvailable()
let providers = [
"locationServicesEnabled": locationServicesEnabled,
"significantLocationChangeMonitoringAvailable": significantLocationChangeMonitoringAvailable,
"headingAvailable": headingAvailable,
"isRangingAvailable": isRangingAvailable,
]
resolve(providers)
#else
let locationServicesEnabled = isLocationEnabled()
let providers = [
"locationServicesEnabled": locationServicesEnabled,
]
resolve(providers)
#endif
}
}
52 changes: 52 additions & 0 deletions ios/TurboDevice+network.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import Foundation
import CoreTelephony

extension TurboDevice {
func getCarrier(_ resolve: @escaping RCTPromiseResolveBlock,
reject: @escaping RCTPromiseRejectBlock) {
#if os(tvOS) || targetEnvironment(macCatalyst)
resolve("unknown")
#else
let netInfo = CTTelephonyNetworkInfo()
if #available(iOS 12.0, *) {
resolve(netInfo.serviceSubscriberCellularProviders?.first?.value.carrierName ?? "unknown")
} else {
resolve(netInfo.subscriberCellularProvider?.carrierName ?? "unknown")
}
#endif
}

// copy from https://stackoverflow.com/a/73853838
func getIpAddress(_ resolve: @escaping RCTPromiseResolveBlock,
reject: @escaping RCTPromiseRejectBlock) {
var address : String?

var ifaddr : UnsafeMutablePointer<ifaddrs>?
guard getifaddrs(&ifaddr) == 0 else { return reject("getIpAddress failed", nil, nil) }
guard let firstAddr = ifaddr else { return reject("getIpAddress failed", nil, nil) }

for ifptr in sequence(first: firstAddr, next: { $0.pointee.ifa_next }) {
let interface = ifptr.pointee

let addrFamily = interface.ifa_addr.pointee.sa_family
if addrFamily == UInt8(AF_INET) || addrFamily == UInt8(AF_INET6) {

// Check interface name:
// wifi = ["en0"]
// wired = ["en2", "en3", "en4"]
// cellular = ["pdp_ip0","pdp_ip1","pdp_ip2","pdp_ip3"]
let name = String(cString: interface.ifa_name)
if name == "en0" || name == "en2" || name == "en3" || name == "en4" || name == "pdp_ip0" || name == "pdp_ip1" || name == "pdp_ip2" || name == "pdp_ip3" {
var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
getnameinfo(interface.ifa_addr, socklen_t(interface.ifa_addr.pointee.sa_len),
&hostname, socklen_t(hostname.count),
nil, socklen_t(0), NI_NUMERICHOST)
address = String(cString: hostname)
}
}
}
freeifaddrs(ifaddr)

resolve(address)
}
}
Loading

0 comments on commit 1815c6c

Please sign in to comment.