├── .watchmanconfig ├── app.json ├── jest.config.js ├── .bundle └── config ├── .eslintrc.js ├── .yarnrc.yml ├── tsconfig.json ├── babel.config.js ├── .gitattributes ├── android ├── app │ ├── src │ │ ├── main │ │ │ ├── res │ │ │ │ ├── values │ │ │ │ │ ├── strings.xml │ │ │ │ │ └── styles.xml │ │ │ │ ├── mipmap-hdpi │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ └── ic_launcher_round.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ └── ic_launcher_round.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ └── ic_launcher_round.png │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ └── ic_launcher_round.png │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ └── ic_launcher_round.png │ │ │ │ └── drawable │ │ │ │ │ └── rn_edit_text_material.xml │ │ │ ├── java │ │ │ │ └── com │ │ │ │ │ └── test │ │ │ │ │ ├── BatteryPackage.kt │ │ │ │ │ ├── MainActivity.kt │ │ │ │ │ ├── BatteryModule.kt │ │ │ │ │ └── MainApplication.kt │ │ │ └── AndroidManifest.xml │ │ └── debug │ │ │ └── AndroidManifest.xml │ ├── debug.keystore │ ├── release │ │ ├── app-release.apk │ │ └── output-metadata.json │ ├── proguard-rules.pro │ └── build.gradle ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── settings.gradle ├── build.gradle ├── gradle.properties ├── gradlew.bat └── gradlew ├── ios ├── test │ ├── Images.xcassets │ │ ├── Contents.json │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── AppDelegate.h │ ├── main.m │ ├── AppDelegate.mm │ ├── PrivacyInfo.xcprivacy │ ├── Info.plist │ └── LaunchScreen.storyboard ├── .xcode.env ├── testTests │ ├── Info.plist │ └── testTests.m ├── Podfile └── test.xcodeproj │ ├── xcshareddata │ └── xcschemes │ │ └── test.xcscheme │ └── project.pbxproj ├── .prettierrc.js ├── index.js ├── metro.config.js ├── Gemfile ├── __tests__ └── App.test.tsx ├── LICENSE ├── package.json ├── .gitignore ├── App.js └── README.md /.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test", 3 | "displayName": "test" 4 | } 5 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: 'react-native', 3 | }; 4 | -------------------------------------------------------------------------------- /.bundle/config: -------------------------------------------------------------------------------- 1 | BUNDLE_PATH: "vendor/bundle" 2 | BUNDLE_FORCE_RUBY_PLATFORM: 1 3 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: '@react-native', 4 | }; 5 | -------------------------------------------------------------------------------- /.yarnrc.yml: -------------------------------------------------------------------------------- 1 | nodeLinker: node-modules 2 | 3 | yarnPath: .yarn/releases/yarn-3.6.4.cjs 4 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@react-native/typescript-config/tsconfig.json" 3 | } 4 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ['module:@react-native/babel-preset'], 3 | }; 4 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.apk filter=lfs diff=lfs merge=lfs -text 2 | *.zip filter=lfs diff=lfs merge=lfs -text 3 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | test 3 | 4 | -------------------------------------------------------------------------------- /ios/test/Images.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /android/app/debug.keystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stackmasteraliza/Battery-Percentage-With-Native-Module/HEAD/android/app/debug.keystore -------------------------------------------------------------------------------- /ios/test/AppDelegate.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | @interface AppDelegate : RCTAppDelegate 5 | 6 | @end 7 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stackmasteraliza/Battery-Percentage-With-Native-Module/HEAD/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | arrowParens: 'avoid', 3 | bracketSameLine: true, 4 | bracketSpacing: false, 5 | singleQuote: true, 6 | trailingComma: 'all', 7 | }; 8 | -------------------------------------------------------------------------------- /android/app/release/app-release.apk: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:cfefa67fd29f00d7ac62011cd7d8e2093c17f273d582e05d042c5f34a71e1510 3 | size 53141095 4 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stackmasteraliza/Battery-Percentage-With-Native-Module/HEAD/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stackmasteraliza/Battery-Percentage-With-Native-Module/HEAD/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stackmasteraliza/Battery-Percentage-With-Native-Module/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stackmasteraliza/Battery-Percentage-With-Native-Module/HEAD/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stackmasteraliza/Battery-Percentage-With-Native-Module/HEAD/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stackmasteraliza/Battery-Percentage-With-Native-Module/HEAD/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stackmasteraliza/Battery-Percentage-With-Native-Module/HEAD/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stackmasteraliza/Battery-Percentage-With-Native-Module/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stackmasteraliza/Battery-Percentage-With-Native-Module/HEAD/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stackmasteraliza/Battery-Percentage-With-Native-Module/HEAD/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @format 3 | */ 4 | 5 | import {AppRegistry} from 'react-native'; 6 | import App from './App'; 7 | import {name as appName} from './app.json'; 8 | 9 | AppRegistry.registerComponent(appName, () => App); 10 | -------------------------------------------------------------------------------- /ios/test/main.m: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | #import "AppDelegate.h" 4 | 5 | int main(int argc, char *argv[]) 6 | { 7 | @autoreleasepool { 8 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'test' 2 | apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings) 3 | include ':app' 4 | includeBuild('../node_modules/@react-native/gradle-plugin') 5 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-all.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /metro.config.js: -------------------------------------------------------------------------------- 1 | const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config'); 2 | 3 | /** 4 | * Metro configuration 5 | * https://reactnative.dev/docs/metro 6 | * 7 | * @type {import('metro-config').MetroConfig} 8 | */ 9 | const config = {}; 10 | 11 | module.exports = mergeConfig(getDefaultConfig(__dirname), config); 12 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # You may use http://rbenv.org/ or https://rvm.io/ to install and use this version 4 | ruby ">= 2.6.10" 5 | 6 | # Cocoapods 1.15 introduced a bug which break the build. We will remove the upper 7 | # bound in the template on Cocoapods with next React Native release. 8 | gem 'cocoapods', '>= 1.13', '< 1.15' 9 | gem 'activesupport', '>= 6.1.7.5', '< 7.1.0' 10 | -------------------------------------------------------------------------------- /__tests__/App.test.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @format 3 | */ 4 | 5 | import 'react-native'; 6 | import React from 'react'; 7 | import App from '../App'; 8 | 9 | // Note: import explicitly to use the types shipped with jest. 10 | import {it} from '@jest/globals'; 11 | 12 | // Note: test renderer must be required after react-native. 13 | import renderer from 'react-test-renderer'; 14 | 15 | it('renders correctly', () => { 16 | renderer.create(); 17 | }); 18 | -------------------------------------------------------------------------------- /android/app/release/output-metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 3, 3 | "artifactType": { 4 | "type": "APK", 5 | "kind": "Directory" 6 | }, 7 | "applicationId": "com.test", 8 | "variantName": "release", 9 | "elements": [ 10 | { 11 | "type": "SINGLE", 12 | "filters": [], 13 | "attributes": [], 14 | "versionCode": 1, 15 | "versionName": "1.0", 16 | "outputFile": "app-release.apk" 17 | } 18 | ], 19 | "elementType": "File" 20 | } -------------------------------------------------------------------------------- /android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | -------------------------------------------------------------------------------- /ios/.xcode.env: -------------------------------------------------------------------------------- 1 | # This `.xcode.env` file is versioned and is used to source the environment 2 | # used when running script phases inside Xcode. 3 | # To customize your local environment, you can create an `.xcode.env.local` 4 | # file that is not versioned. 5 | 6 | # NODE_BINARY variable contains the PATH to the node executable. 7 | # 8 | # Customize the NODE_BINARY variable here. 9 | # For example, to use nvm with brew, add the following line 10 | # . "$(brew --prefix nvm)/nvm.sh" --no-use 11 | export NODE_BINARY=$(command -v node) 12 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/test/BatteryPackage.kt: -------------------------------------------------------------------------------- 1 | package com.test 2 | 3 | import com.facebook.react.ReactPackage 4 | import com.facebook.react.bridge.NativeModule 5 | import com.facebook.react.bridge.ReactApplicationContext 6 | import com.facebook.react.uimanager.ViewManager 7 | 8 | class BatteryPackage : ReactPackage { 9 | override fun createNativeModules(reactContext: ReactApplicationContext): List { 10 | return listOf(BatteryModule(reactContext)) 11 | } 12 | 13 | override fun createViewManagers(reactContext: ReactApplicationContext): List> { 14 | return emptyList() 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext { 3 | buildToolsVersion = "34.0.0" 4 | minSdkVersion = 23 5 | compileSdkVersion = 34 6 | targetSdkVersion = 34 7 | ndkVersion = "26.1.10909125" 8 | kotlinVersion = "1.9.22" 9 | } 10 | repositories { 11 | google() 12 | mavenCentral() 13 | } 14 | dependencies { 15 | classpath("com.android.tools.build:gradle") 16 | classpath("com.facebook.react:react-native-gradle-plugin") 17 | classpath("org.jetbrains.kotlin:kotlin-gradle-plugin") 18 | } 19 | } 20 | 21 | apply plugin: "com.facebook.react.rootproject" 22 | -------------------------------------------------------------------------------- /ios/testTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /ios/test/AppDelegate.mm: -------------------------------------------------------------------------------- 1 | #import "AppDelegate.h" 2 | 3 | #import 4 | 5 | @implementation AppDelegate 6 | 7 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 8 | { 9 | self.moduleName = @"test"; 10 | // You can add your custom initial props in the dictionary below. 11 | // They will be passed down to the ViewController used by React Native. 12 | self.initialProps = @{}; 13 | 14 | return [super application:application didFinishLaunchingWithOptions:launchOptions]; 15 | } 16 | 17 | - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge 18 | { 19 | return [self bundleURL]; 20 | } 21 | 22 | - (NSURL *)bundleURL 23 | { 24 | #if DEBUG 25 | return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"]; 26 | #else 27 | return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; 28 | #endif 29 | } 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/test/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.test 2 | 3 | import com.facebook.react.ReactActivity 4 | import com.facebook.react.ReactActivityDelegate 5 | import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled 6 | import com.facebook.react.defaults.DefaultReactActivityDelegate 7 | 8 | class MainActivity : ReactActivity() { 9 | 10 | /** 11 | * Returns the name of the main component registered from JavaScript. This is used to schedule 12 | * rendering of the component. 13 | */ 14 | override fun getMainComponentName(): String = "test" 15 | 16 | /** 17 | * Returns the instance of the [ReactActivityDelegate]. We use [DefaultReactActivityDelegate] 18 | * which allows you to enable New Architecture with a single boolean flags [fabricEnabled] 19 | */ 20 | override fun createReactActivityDelegate(): ReactActivityDelegate = 21 | DefaultReactActivityDelegate(this, mainComponentName, fabricEnabled) 22 | } 23 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 12 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /ios/test/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "scale" : "2x", 6 | "size" : "20x20" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "scale" : "3x", 11 | "size" : "20x20" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "scale" : "2x", 16 | "size" : "29x29" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "scale" : "3x", 21 | "size" : "29x29" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "scale" : "2x", 26 | "size" : "40x40" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "scale" : "3x", 31 | "size" : "40x40" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "scale" : "2x", 36 | "size" : "60x60" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "scale" : "3x", 41 | "size" : "60x60" 42 | }, 43 | { 44 | "idiom" : "ios-marketing", 45 | "scale" : "1x", 46 | "size" : "1024x1024" 47 | } 48 | ], 49 | "info" : { 50 | "author" : "xcode", 51 | "version" : 1 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Aliza Ali 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test", 3 | "version": "0.0.1", 4 | "private": true, 5 | "scripts": { 6 | "android": "react-native run-android", 7 | "ios": "react-native run-ios", 8 | "lint": "eslint .", 9 | "start": "react-native start", 10 | "test": "jest" 11 | }, 12 | "dependencies": { 13 | "react": "18.2.0", 14 | "react-native": "0.74.3", 15 | "react-native-linear-gradient": "^2.8.3" 16 | }, 17 | "devDependencies": { 18 | "@babel/core": "^7.20.0", 19 | "@babel/preset-env": "^7.20.0", 20 | "@babel/runtime": "^7.20.0", 21 | "@react-native/babel-preset": "0.74.85", 22 | "@react-native/eslint-config": "0.74.85", 23 | "@react-native/metro-config": "0.74.85", 24 | "@react-native/typescript-config": "0.74.85", 25 | "@types/react": "^18.2.6", 26 | "@types/react-test-renderer": "^18.0.0", 27 | "babel-jest": "^29.6.3", 28 | "eslint": "^8.19.0", 29 | "jest": "^29.6.3", 30 | "prettier": "2.8.8", 31 | "react-test-renderer": "18.2.0", 32 | "typescript": "5.0.4" 33 | }, 34 | "engines": { 35 | "node": ">=18" 36 | }, 37 | "packageManager": "yarn@3.6.4" 38 | } 39 | -------------------------------------------------------------------------------- /ios/test/PrivacyInfo.xcprivacy: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSPrivacyCollectedDataTypes 6 | 7 | 8 | NSPrivacyAccessedAPITypes 9 | 10 | 11 | NSPrivacyAccessedAPIType 12 | NSPrivacyAccessedAPICategoryFileTimestamp 13 | NSPrivacyAccessedAPITypeReasons 14 | 15 | C617.1 16 | 17 | 18 | 19 | NSPrivacyAccessedAPIType 20 | NSPrivacyAccessedAPICategoryUserDefaults 21 | NSPrivacyAccessedAPITypeReasons 22 | 23 | CA92.1 24 | 25 | 26 | 27 | NSPrivacyAccessedAPIType 28 | NSPrivacyAccessedAPICategorySystemBootTime 29 | NSPrivacyAccessedAPITypeReasons 30 | 31 | 35F9.1 32 | 33 | 34 | 35 | NSPrivacyTracking 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /ios/Podfile: -------------------------------------------------------------------------------- 1 | # Resolve react_native_pods.rb with node to allow for hoisting 2 | require Pod::Executable.execute_command('node', ['-p', 3 | 'require.resolve( 4 | "react-native/scripts/react_native_pods.rb", 5 | {paths: [process.argv[1]]}, 6 | )', __dir__]).strip 7 | 8 | platform :ios, min_ios_version_supported 9 | prepare_react_native_project! 10 | 11 | linkage = ENV['USE_FRAMEWORKS'] 12 | if linkage != nil 13 | Pod::UI.puts "Configuring Pod with #{linkage}ally linked Frameworks".green 14 | use_frameworks! :linkage => linkage.to_sym 15 | end 16 | 17 | target 'test' do 18 | config = use_native_modules! 19 | 20 | use_react_native!( 21 | :path => config[:reactNativePath], 22 | # An absolute path to your application root. 23 | :app_path => "#{Pod::Config.instance.installation_root}/.." 24 | ) 25 | 26 | target 'testTests' do 27 | inherit! :complete 28 | # Pods for testing 29 | end 30 | 31 | post_install do |installer| 32 | # https://github.com/facebook/react-native/blob/main/packages/react-native/scripts/react_native_pods.rb#L197-L202 33 | react_native_post_install( 34 | installer, 35 | config[:reactNativePath], 36 | :mac_catalyst_enabled => false, 37 | # :ccache_enabled => true 38 | ) 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/test/BatteryModule.kt: -------------------------------------------------------------------------------- 1 | package com.test 2 | 3 | import android.content.Intent 4 | import android.content.IntentFilter 5 | import android.os.BatteryManager 6 | import com.facebook.react.bridge.Promise 7 | import com.facebook.react.bridge.ReactApplicationContext 8 | import com.facebook.react.bridge.ReactContextBaseJavaModule 9 | import com.facebook.react.bridge.ReactMethod 10 | 11 | class BatteryModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) { 12 | private val context: ReactApplicationContext = reactContext 13 | 14 | override fun getName(): String { 15 | return "BatteryModule" 16 | } 17 | 18 | @ReactMethod 19 | fun getBatteryLevel(promise: Promise) { 20 | try { 21 | val intentFilter = IntentFilter(Intent.ACTION_BATTERY_CHANGED) 22 | val batteryStatus = context.registerReceiver(null, intentFilter) 23 | val level = batteryStatus?.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) ?: -1 24 | val scale = batteryStatus?.getIntExtra(BatteryManager.EXTRA_SCALE, -1) ?: -1 25 | val batteryPct = (level / scale.toFloat()) * 100 26 | promise.resolve(batteryPct.toInt()) 27 | } catch (e: Exception) { 28 | promise.reject("ERROR", e.message) 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # Xcode 6 | # 7 | build/ 8 | *.pbxuser 9 | !default.pbxuser 10 | *.mode1v3 11 | !default.mode1v3 12 | *.mode2v3 13 | !default.mode2v3 14 | *.perspectivev3 15 | !default.perspectivev3 16 | xcuserdata 17 | *.xccheckout 18 | *.moved-aside 19 | DerivedData 20 | *.hmap 21 | *.ipa 22 | *.xcuserstate 23 | **/.xcode.env.local 24 | 25 | # Android/IntelliJ 26 | # 27 | build/ 28 | .idea 29 | .gradle 30 | local.properties 31 | *.iml 32 | *.hprof 33 | .cxx/ 34 | *.keystore 35 | !debug.keystore 36 | 37 | # node.js 38 | # 39 | node_modules/ 40 | npm-debug.log 41 | yarn-error.log 42 | 43 | # fastlane 44 | # 45 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 46 | # screenshots whenever they are needed. 47 | # For more information about the recommended setup visit: 48 | # https://docs.fastlane.tools/best-practices/source-control/ 49 | 50 | **/fastlane/report.xml 51 | **/fastlane/Preview.html 52 | **/fastlane/screenshots 53 | **/fastlane/test_output 54 | 55 | # Bundle artifact 56 | *.jsbundle 57 | 58 | # Ruby / CocoaPods 59 | **/Pods/ 60 | /vendor/bundle/ 61 | 62 | # Temporary files created by Metro to check the health of the file watcher 63 | .metro-health-check* 64 | 65 | # testing 66 | /coverage 67 | 68 | # Yarn 69 | .yarn/* 70 | !.yarn/patches 71 | !.yarn/plugins 72 | !.yarn/releases 73 | !.yarn/sdks 74 | !.yarn/versions 75 | -------------------------------------------------------------------------------- /ios/test/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | test 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(MARKETING_VERSION) 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | $(CURRENT_PROJECT_VERSION) 25 | LSRequiresIPhoneOS 26 | 27 | NSAppTransportSecurity 28 | 29 | 30 | NSAllowsArbitraryLoads 31 | 32 | NSAllowsLocalNetworking 33 | 34 | 35 | NSLocationWhenInUseUsageDescription 36 | 37 | UILaunchStoryboardName 38 | LaunchScreen 39 | UIRequiredDeviceCapabilities 40 | 41 | arm64 42 | 43 | UISupportedInterfaceOrientations 44 | 45 | UIInterfaceOrientationPortrait 46 | UIInterfaceOrientationLandscapeLeft 47 | UIInterfaceOrientationLandscapeRight 48 | 49 | UIViewControllerBasedStatusBarAppearance 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/test/MainApplication.kt: -------------------------------------------------------------------------------- 1 | package com.test 2 | 3 | import android.app.Application 4 | import com.facebook.react.PackageList 5 | import com.facebook.react.ReactApplication 6 | import com.facebook.react.ReactHost 7 | import com.facebook.react.ReactNativeHost 8 | import com.facebook.react.ReactPackage 9 | import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load 10 | import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost 11 | import com.facebook.react.defaults.DefaultReactNativeHost 12 | import com.facebook.soloader.SoLoader 13 | import com.test.BatteryPackage 14 | 15 | class MainApplication : Application(), ReactApplication { 16 | 17 | override val reactNativeHost: ReactNativeHost = 18 | object : DefaultReactNativeHost(this) { 19 | override fun getPackages(): List = 20 | PackageList(this).packages.apply { 21 | add(BatteryPackage()) 22 | // Packages that cannot be autolinked yet can be added manually here, for example: 23 | // add(MyReactNativePackage()) 24 | } 25 | 26 | override fun getJSMainModuleName(): String = "index" 27 | 28 | override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG 29 | 30 | override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED 31 | override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED 32 | } 33 | 34 | override val reactHost: ReactHost 35 | get() = getDefaultReactHost(applicationContext, reactNativeHost) 36 | 37 | override fun onCreate() { 38 | super.onCreate() 39 | SoLoader.init(this, false) 40 | if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) { 41 | // If you opted-in for the New Architecture, we load the native entry point for this app. 42 | load() 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx512m -XX:MaxMetaspaceSize=256m 13 | org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true 19 | 20 | # AndroidX package structure to make it clearer which packages are bundled with the 21 | # Android operating system, and which are packaged with your app's APK 22 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 23 | android.useAndroidX=true 24 | # Automatically convert third-party libraries to use AndroidX 25 | android.enableJetifier=true 26 | 27 | # Use this property to specify which architecture you want to build. 28 | # You can also override it from the CLI using 29 | # ./gradlew -PreactNativeArchitectures=x86_64 30 | reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64 31 | 32 | # Use this property to enable support to the new architecture. 33 | # This will allow you to use TurboModules and the Fabric render in 34 | # your application. You should enable this flag either if you want 35 | # to write custom TurboModules/Fabric components OR use libraries that 36 | # are providing them. 37 | newArchEnabled=false 38 | 39 | # Use this property to enable or disable the Hermes JS engine. 40 | # If set to false, you will be using JSC instead. 41 | hermesEnabled=true 42 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/rn_edit_text_material.xml: -------------------------------------------------------------------------------- 1 | 2 | 16 | 22 | 23 | 24 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /App.js: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from 'react'; 2 | import { View, Text, StyleSheet, TouchableOpacity } from 'react-native'; 3 | import { NativeModules } from 'react-native'; 4 | 5 | const { BatteryModule } = NativeModules; 6 | 7 | const App = () => { 8 | const [batteryLevel, setBatteryLevel] = useState(null); 9 | console.log(NativeModules); 10 | 11 | const fetchBatteryPercentage = async () => { 12 | try { 13 | const level = await BatteryModule.getBatteryLevel(); 14 | setBatteryLevel(level); 15 | } catch (error) { 16 | console.error('Error fetching battery level:', error); 17 | } 18 | }; 19 | 20 | useEffect(() => { 21 | fetchBatteryPercentage(); 22 | }, []); 23 | 24 | return ( 25 | 26 | Battery Percentage 27 | {batteryLevel !== null ? ( 28 | {batteryLevel}% 29 | ) : ( 30 | ... 31 | )} 32 | 33 | Refresh 34 | 35 | 36 | ); 37 | }; 38 | 39 | const styles = StyleSheet.create({ 40 | container: { 41 | flex: 1, 42 | justifyContent: 'center', 43 | alignItems: 'center', 44 | backgroundColor: '#f5f5f5', 45 | }, 46 | title: { 47 | fontSize: 24, 48 | fontWeight: 'bold', 49 | color: "#000000", 50 | marginBottom: 20, 51 | }, 52 | batteryText: { 53 | fontSize: 40, 54 | marginBottom: 20, 55 | color: '#4caf50', 56 | }, 57 | button: { 58 | backgroundColor: '#2196f3', 59 | padding: 15, 60 | borderRadius: 30, 61 | paddingHorizontal: 30 62 | }, 63 | buttonText: { 64 | color: '#fff', 65 | fontSize: 18, 66 | }, 67 | }); 68 | 69 | export default App; 70 | -------------------------------------------------------------------------------- /ios/testTests/testTests.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | #import 5 | #import 6 | 7 | #define TIMEOUT_SECONDS 600 8 | #define TEXT_TO_LOOK_FOR @"Welcome to React" 9 | 10 | @interface testTests : XCTestCase 11 | 12 | @end 13 | 14 | @implementation testTests 15 | 16 | - (BOOL)findSubviewInView:(UIView *)view matching:(BOOL (^)(UIView *view))test 17 | { 18 | if (test(view)) { 19 | return YES; 20 | } 21 | for (UIView *subview in [view subviews]) { 22 | if ([self findSubviewInView:subview matching:test]) { 23 | return YES; 24 | } 25 | } 26 | return NO; 27 | } 28 | 29 | - (void)testRendersWelcomeScreen 30 | { 31 | UIViewController *vc = [[[RCTSharedApplication() delegate] window] rootViewController]; 32 | NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS]; 33 | BOOL foundElement = NO; 34 | 35 | __block NSString *redboxError = nil; 36 | #ifdef DEBUG 37 | RCTSetLogFunction( 38 | ^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) { 39 | if (level >= RCTLogLevelError) { 40 | redboxError = message; 41 | } 42 | }); 43 | #endif 44 | 45 | while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) { 46 | [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; 47 | [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; 48 | 49 | foundElement = [self findSubviewInView:vc.view 50 | matching:^BOOL(UIView *view) { 51 | if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) { 52 | return YES; 53 | } 54 | return NO; 55 | }]; 56 | } 57 | 58 | #ifdef DEBUG 59 | RCTSetLogFunction(RCTDefaultLogFunction); 60 | #endif 61 | 62 | XCTAssertNil(redboxError, @"RedBox error: %@", redboxError); 63 | XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS); 64 | } 65 | 66 | @end 67 | -------------------------------------------------------------------------------- /android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%"=="" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%"=="" set DIRNAME=. 29 | @rem This is normally unused 30 | set APP_BASE_NAME=%~n0 31 | set APP_HOME=%DIRNAME% 32 | 33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 35 | 36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 38 | 39 | @rem Find java.exe 40 | if defined JAVA_HOME goto findJavaFromJavaHome 41 | 42 | set JAVA_EXE=java.exe 43 | %JAVA_EXE% -version >NUL 2>&1 44 | if %ERRORLEVEL% equ 0 goto execute 45 | 46 | echo. 1>&2 47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 48 | echo. 1>&2 49 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 50 | echo location of your Java installation. 1>&2 51 | 52 | goto fail 53 | 54 | :findJavaFromJavaHome 55 | set JAVA_HOME=%JAVA_HOME:"=% 56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 57 | 58 | if exist "%JAVA_EXE%" goto execute 59 | 60 | echo. 1>&2 61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 62 | echo. 1>&2 63 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 64 | echo location of your Java installation. 1>&2 65 | 66 | goto fail 67 | 68 | :execute 69 | @rem Setup the command line 70 | 71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 72 | 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if %ERRORLEVEL% equ 0 goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | set EXIT_CODE=%ERRORLEVEL% 85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 87 | exit /b %EXIT_CODE% 88 | 89 | :mainEnd 90 | if "%OS%"=="Windows_NT" endlocal 91 | 92 | :omega 93 | -------------------------------------------------------------------------------- /ios/test.xcodeproj/xcshareddata/xcschemes/test.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 53 | 55 | 61 | 62 | 63 | 64 | 70 | 72 | 78 | 79 | 80 | 81 | 83 | 84 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /ios/test/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 24 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /android/app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: "com.android.application" 2 | apply plugin: "org.jetbrains.kotlin.android" 3 | apply plugin: "com.facebook.react" 4 | 5 | /** 6 | * This is the configuration block to customize your React Native Android app. 7 | * By default you don't need to apply any configuration, just uncomment the lines you need. 8 | */ 9 | react { 10 | /* Folders */ 11 | // The root of your project, i.e. where "package.json" lives. Default is '..' 12 | // root = file("../") 13 | // The folder where the react-native NPM package is. Default is ../node_modules/react-native 14 | // reactNativeDir = file("../node_modules/react-native") 15 | // The folder where the react-native Codegen package is. Default is ../node_modules/@react-native/codegen 16 | // codegenDir = file("../node_modules/@react-native/codegen") 17 | // The cli.js file which is the React Native CLI entrypoint. Default is ../node_modules/react-native/cli.js 18 | // cliFile = file("../node_modules/react-native/cli.js") 19 | 20 | /* Variants */ 21 | // The list of variants to that are debuggable. For those we're going to 22 | // skip the bundling of the JS bundle and the assets. By default is just 'debug'. 23 | // If you add flavors like lite, prod, etc. you'll have to list your debuggableVariants. 24 | // debuggableVariants = ["liteDebug", "prodDebug"] 25 | 26 | /* Bundling */ 27 | // A list containing the node command and its flags. Default is just 'node'. 28 | // nodeExecutableAndArgs = ["node"] 29 | // 30 | // The command to run when bundling. By default is 'bundle' 31 | // bundleCommand = "ram-bundle" 32 | // 33 | // The path to the CLI configuration file. Default is empty. 34 | // bundleConfig = file(../rn-cli.config.js) 35 | // 36 | // The name of the generated asset file containing your JS bundle 37 | // bundleAssetName = "MyApplication.android.bundle" 38 | // 39 | // The entry file for bundle generation. Default is 'index.android.js' or 'index.js' 40 | // entryFile = file("../js/MyApplication.android.js") 41 | // 42 | // A list of extra flags to pass to the 'bundle' commands. 43 | // See https://github.com/react-native-community/cli/blob/main/docs/commands.md#bundle 44 | // extraPackagerArgs = [] 45 | 46 | /* Hermes Commands */ 47 | // The hermes compiler command to run. By default it is 'hermesc' 48 | // hermesCommand = "$rootDir/my-custom-hermesc/bin/hermesc" 49 | // 50 | // The list of flags to pass to the Hermes compiler. By default is "-O", "-output-source-map" 51 | // hermesFlags = ["-O", "-output-source-map"] 52 | } 53 | 54 | /** 55 | * Set this to true to Run Proguard on Release builds to minify the Java bytecode. 56 | */ 57 | def enableProguardInReleaseBuilds = false 58 | 59 | /** 60 | * The preferred build flavor of JavaScriptCore (JSC) 61 | * 62 | * For example, to use the international variant, you can use: 63 | * `def jscFlavor = 'org.webkit:android-jsc-intl:+'` 64 | * 65 | * The international variant includes ICU i18n library and necessary data 66 | * allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that 67 | * give correct results when using with locales other than en-US. Note that 68 | * this variant is about 6MiB larger per architecture than default. 69 | */ 70 | def jscFlavor = 'org.webkit:android-jsc:+' 71 | 72 | android { 73 | ndkVersion rootProject.ext.ndkVersion 74 | buildToolsVersion rootProject.ext.buildToolsVersion 75 | compileSdk rootProject.ext.compileSdkVersion 76 | 77 | namespace "com.test" 78 | defaultConfig { 79 | applicationId "com.test" 80 | minSdkVersion rootProject.ext.minSdkVersion 81 | targetSdkVersion rootProject.ext.targetSdkVersion 82 | versionCode 1 83 | versionName "1.0" 84 | } 85 | signingConfigs { 86 | debug { 87 | storeFile file('debug.keystore') 88 | storePassword 'android' 89 | keyAlias 'androiddebugkey' 90 | keyPassword 'android' 91 | } 92 | } 93 | buildTypes { 94 | debug { 95 | signingConfig signingConfigs.debug 96 | } 97 | release { 98 | // Caution! In production, you need to generate your own keystore file. 99 | // see https://reactnative.dev/docs/signed-apk-android. 100 | signingConfig signingConfigs.debug 101 | minifyEnabled enableProguardInReleaseBuilds 102 | proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" 103 | } 104 | } 105 | } 106 | 107 | dependencies { 108 | // The version of react-native is set by the React Native Gradle Plugin 109 | implementation("com.facebook.react:react-android") 110 | 111 | 112 | if (hermesEnabled.toBoolean()) { 113 | implementation("com.facebook.react:hermes-android") 114 | } else { 115 | implementation jscFlavor 116 | } 117 | } 118 | 119 | apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project) 120 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Battery Percentage Fetcher 2 | 3 | This React Native project fetches and displays the battery percentage of the user's device using a native module. The application leverages platform-specific code (Kotlin for Android) to retrieve the battery level, ensuring smooth integration with React Native. Note: iOS functionality has not been implemented or tested yet. 4 | 5 | --- 6 | 7 | ## Features 8 | 1. Fetches the current battery percentage of the device. 9 | 2. Displays the battery percentage in real-time. 10 | 3. Refresh button to manually update the battery level. 11 | 4. Android support only (iOS functionality not implemented). 12 | 13 | --- 14 | 15 | ## Prerequisites 16 | - Node.js (v14 or above) 17 | - React Native CLI or Expo 18 | - Android Studio (for Android development) 19 | 20 | --- 21 | 22 | ## Installation 23 | 1. Clone the repository: 24 | ```bash 25 | git clone https://github.com/alizaali9/Battery-Percentage-With-Native-Module 26 | cd Battery-Percentage-With-Native-Module 27 | ``` 28 | 29 | 2. Install dependencies: 30 | ```bash 31 | npm install 32 | # or 33 | yarn install 34 | ``` 35 | 36 | 3. Link the native module: 37 | - For React Native 0.60+, auto-linking should take care of this. 38 | - For older versions, link manually: 39 | ```bash 40 | react-native link 41 | ``` 42 | 43 | --- 44 | 45 | ## Native Module Integration 46 | 47 | ### Android 48 | 1. Navigate to `android/app/src/main/java/com//`. 49 | 2. Create a file `BatteryModule.kt` and `BatteryPackage.kt`: 50 | ```kotlin 51 | <---- BatteryModule.kt ----> 52 | package com. 53 | 54 | import android.content.Intent 55 | import android.content.IntentFilter 56 | import android.os.BatteryManager 57 | import com.facebook.react.bridge.Promise 58 | import com.facebook.react.bridge.ReactApplicationContext 59 | import com.facebook.react.bridge.ReactContextBaseJavaModule 60 | import com.facebook.react.bridge.ReactMethod 61 | 62 | class BatteryModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) { 63 | private val context: ReactApplicationContext = reactContext 64 | 65 | override fun getName(): String { 66 | return "BatteryModule" 67 | } 68 | 69 | @ReactMethod 70 | fun getBatteryLevel(promise: Promise) { 71 | try { 72 | val intentFilter = IntentFilter(Intent.ACTION_BATTERY_CHANGED) 73 | val batteryStatus = context.registerReceiver(null, intentFilter) 74 | val level = batteryStatus?.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) ?: -1 75 | val scale = batteryStatus?.getIntExtra(BatteryManager.EXTRA_SCALE, -1) ?: -1 76 | val batteryPct = (level / scale.toFloat()) * 100 77 | promise.resolve(batteryPct.toInt()) 78 | } catch (e: Exception) { 79 | promise.reject("ERROR", e.message) 80 | }} 81 | } 82 | ``` 83 | --- 84 | ```kotlin 85 | <---- BatteryPackage.kt ----> 86 | package com. 87 | 88 | import com.facebook.react.ReactPackage 89 | import com.facebook.react.bridge.NativeModule 90 | import com.facebook.react.bridge.ReactApplicationContext 91 | import com.facebook.react.uimanager.ViewManager 92 | 93 | class BatteryPackage : ReactPackage { 94 | override fun createNativeModules(reactContext: ReactApplicationContext): List { 95 | return listOf(BatteryModule(reactContext)) 96 | } 97 | 98 | override fun createViewManagers(reactContext: ReactApplicationContext): List> { 99 | return emptyList() 100 | } 101 | } 102 | ``` 103 | 104 | 4. Update `MainApplication.kt` to include the module. 105 | 106 | ```kotlin 107 | <---- MainApplication.kt ----> 108 | package com. 109 | 110 | import android.app.Application 111 | import com.facebook.react.PackageList 112 | import com.facebook.react.ReactApplication 113 | import com.facebook.react.ReactHost 114 | import com.facebook.react.ReactNativeHost 115 | import com.facebook.react.ReactPackage 116 | import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load 117 | import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost 118 | import com.facebook.react.defaults.DefaultReactNativeHost 119 | import com.facebook.soloader.SoLoader 120 | import com.test.BatteryPackage 121 | 122 | class MainApplication : Application(), ReactApplication { 123 | 124 | override val reactNativeHost: ReactNativeHost = 125 | object : DefaultReactNativeHost(this) { 126 | override fun getPackages(): List = 127 | PackageList(this).packages.apply { 128 | add(BatteryPackage()) 129 | // Packages that cannot be autolinked yet can be added manually here, for example: 130 | // add(MyReactNativePackage()) 131 | } 132 | 133 | override fun getJSMainModuleName(): String = "index" 134 | 135 | override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG 136 | 137 | override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED 138 | override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED 139 | } 140 | 141 | override val reactHost: ReactHost 142 | get() = getDefaultReactHost(applicationContext, reactNativeHost) 143 | 144 | override fun onCreate() { 145 | super.onCreate() 146 | SoLoader.init(this, false) 147 | if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) { 148 | // If you opted-in for the New Architecture, we load the native entry point for this app. 149 | load() 150 | } 151 | } 152 | } 153 | ``` 154 | 155 | --- 156 | 157 | ## Usage 158 | 1. Import the module in your React Native component: 159 | ```javascript 160 | import { NativeModules } from 'react-native'; 161 | 162 | const { BatteryModule } = NativeModules; 163 | 164 | const fetchBatteryLevel = async () => { 165 | try { 166 | const batteryLevel = await BatteryModule.getBatteryLevel(); 167 | console.log(`Battery Level: ${batteryLevel}%`); 168 | } catch (error) { 169 | console.error('Error fetching battery level:', error); 170 | } 171 | }; 172 | 173 | export default function App() { 174 | useEffect(() => { 175 | fetchBatteryLevel(); 176 | }, []); 177 | 178 | return ( 179 | 180 | Battery Level: 181 |