{"id":18831417,"url":"https://github.com/kingstinct/react-native-device-activity","last_synced_at":"2025-04-14T04:16:23.680Z","repository":{"id":179988741,"uuid":"664413392","full_name":"kingstinct/react-native-device-activity","owner":"kingstinct","description":"Provides direct access to Apples Screen Time, Device Activity and Shielding APIs","archived":false,"fork":false,"pushed_at":"2025-04-10T13:51:31.000Z","size":4088,"stargazers_count":38,"open_issues_count":13,"forks_count":9,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-04-14T04:16:17.923Z","etag":null,"topics":["expo","ios","react-native","screentime","swift","swiftui"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kingstinct.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-07-09T22:51:56.000Z","updated_at":"2025-04-14T02:08:34.000Z","dependencies_parsed_at":null,"dependency_job_id":"2d1c4791-2e96-4c0c-82be-728f50db1c0b","html_url":"https://github.com/kingstinct/react-native-device-activity","commit_stats":null,"previous_names":["kingstinct/react-native-device-activity"],"tags_count":15,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kingstinct%2Freact-native-device-activity","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kingstinct%2Freact-native-device-activity/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kingstinct%2Freact-native-device-activity/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kingstinct%2Freact-native-device-activity/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kingstinct","download_url":"https://codeload.github.com/kingstinct/react-native-device-activity/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248819410,"owners_count":21166477,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["expo","ios","react-native","screentime","swift","swiftui"],"created_at":"2024-11-08T01:54:09.943Z","updated_at":"2025-04-14T04:16:23.673Z","avatar_url":"https://github.com/kingstinct.png","language":"Swift","readme":"[![Test Status](https://github.com/Kingstinct/react-native-device-activity/actions/workflows/test.yml/badge.svg)](https://github.com/Kingstinct/react-native-device-activity/actions/workflows/test.yml)\n[![Latest version on NPM](https://img.shields.io/npm/v/react-native-device-activity)](https://www.npmjs.com/package/react-native-device-activity)\n[![Downloads on NPM](https://img.shields.io/npm/dt/react-native-device-activity)](https://www.npmjs.com/package/react-native-device-activity)\n[![Discord](https://dcbadge.vercel.app/api/server/5wQGsRfS?style=flat)](https://discord.gg/5wQGsRfS)\n\n# react-native-device-activity\n\nProvides direct access to Apples Screen Time, Device Activity and Shielding APIs.\n\n⚠️ Before planning and starting using these APIs it is highly recommended to familiarize yourself with the [special approval and entitlements required](https://github.com/Kingstinct/react-native-device-activity#family-controls-distribution-entitlement-requires-approval-from-apple).\n\nPlease note that it only supports iOS (and requires iOS 15 or higher) and requires a Custom Dev Client to work with Expo. For Android I'd probably look into [UsageStats](https://developer.android.com/reference/android/app/usage/UsageStats), which seems provide more granularity.\n\n# Examples\n\n```TypeScript\nimport * as ReactNativeDeviceActivity from \"react-native-device-activity\";\n\nconst DeviceActivityPicker = () =\u003e {\n  // First things first, you need to request authorization\n  useEffect(() =\u003e {\n    ReactNativeDeviceActivity.requestAuthorization()\n  }, [])\n\n  const [familyActivitySelection, setFamilyActivitySelection] = React.useState(null);\n\n  // next you need to present a native view to let the user select which activities to track, you need to do this before you can start tracking (this is a completely unstyled clickable native view):\n  return (\n    \u003cReactNativeDeviceActivity.DeviceActivitySelectionView\n      onSelectionChange={(event) =\u003e {\n        setFamilyActivitySelection(\n          event.nativeEvent.familyActivitySelection\n        )\n      }}\n      familyActivitySelection={familyActivitySelection} /\u003e\n    )\n  }\n}\n\n// once you have authorization and got hold of the familyActivitySelection (which is a base64 string) you can start tracking with it:\nconst trackDeviceActivity = (activitySelection: string) =\u003e {\n  ReactNativeDeviceActivity.startMonitoring(\n    \"DeviceActivity.AppLoggedTimeDaily\",\n    {\n      // repeat logging every 24 hours\n      intervalStart: { hour: 0, minute: 0, second: 0 },\n      intervalEnd: { hour: 23, minute: 59, second: 59 },\n      repeats: true,\n    },\n    events: [\n      {\n        eventName: 'user_activity_reached_10_minutes',\n        familyActivitySelection: activitySelection,\n        threshold: { minute: 10 },\n      }\n    ]\n  );\n}\n\n// you can listen to events (which I guess only works when the app is alive):\nconst listener = ReactNativeDeviceActivity.onDeviceActivityMonitorEvent(\n      (event) =\u003e {\n        const name = event.nativeEvent.callbackName; // the name of the event\n        /* callbackName is one of, corresponding to the events received from the native API:\n          - \"intervalDidStart\"\n          - \"intervalDidEnd\"\n          - \"eventDidReachThreshold\"\n          - \"intervalWillStartWarning\"\n          - \"intervalWillEndWarning\"\n          - \"eventWillReachThresholdWarning\";\n        */\n      }\n    );\n\n// you can also get a history of events called with the time where called:\nconst events = ReactNativeDeviceActivityModule.getEvents();\n```\n\n# Installation in managed Expo projects\n\nFor [managed](https://docs.expo.dev/archive/managed-vs-bare/) Expo projects, please follow the installation instructions in the [API documentation for the latest stable release](#api-documentation). If you follow the link and there is no documentation available then this library is not yet usable within managed projects \u0026mdash; it is likely to be included in an upcoming Expo SDK release.\n\nThe package requires native code, which includes a custom app target. Currently it requires targeting iOS 15 or higher, so populate app.json/app.config.json as follows:\n\n```\n\"plugins\": [\n    [\n      \"expo-build-properties\",\n      {\n        \"ios\": {\n          \"deploymentTarget\": \"15.1\"\n        },\n      },\n    ],\n    [\n      \"react-native-device-activity\",\n      {\n        \"appleTeamId\": \"\u003cYOUR_TEAM_ID\u003e\",\n        \"appGroup\": \"group.\u003cYOUR_APP_GROUP_NAME\u003e\",\n      }\n    ]\n  ],\n```\n\nThe Swift files for the iOS target will be copied to your local `/targets` directory. You might want to add it to your .gitignore (or if you have other targets in there, you might want to specifically add the three targets added by this library).\n\nFor Expo to be able to automatically handle provisioning you need to specify extra.eas.build.experimental.ios.appExtensions in your app.json/app.config.ts [as seen here](https://github.com/Intentional-Digital/react-native-device-activity/blob/main/example/app.json#L57).\n\n## Customize native code\n\nYou can potentially modify the targets manually, although you risk the library and your app code diverging. If you want to disable the automatic copying of the targets, you can set `copyToTargetFolder` to `false` in the plugin configuration [as seen here](https://github.com/Intentional-Digital/react-native-device-activity/blob/main/example/app.json#L53).\n\n## Some notes\n- It's not possible to 100% know which familyActivitySelection an event being handled is triggered for in the context of the Shield UI/actions. We try to make a best guess here - prioritizing apps/websites in an activitySelection over categories, and smaller activitySelections over larger ones (i.e. \"Instagram\" over \"Instagram + Facebook\" over \"Social Media Apps\"). This means that if you display a shield specific for the Instagram selection that will take precedence over the less specific shields.\n- When determining which familyActivitySelectionId that should be used it will only look for familyActivitySelectionIds that are contained in any of the currently monitored activity names (i.e. if familyActivitySelectionId is \"social-media-apps\" it will only trigger if there is an activity name that contains \"social-media-apps\"). This might be a limitation for some implementations, it would probably be nice to make this configurable.\n\n## Data model\nAlmost all the functionality is built around persisting configuration as well as event history to UserDefaults.\n\n- familyActivitySelectionId mapping. This makes it possible for us to tie a familyActivitySelection token to an id that we can reuse and refer to at a later stage.\n- Triggers. This includes configuring shield UI/actions as well as sending web requests or notifications from the Swift background side, in the context of the device activity monitor process. Prefixed like actions_for_${goalId} in userDefaults. This is how we do blocking of apps, updates to shield UI/actions etc.\n- Event history. Contains information of which events have been triggered and when. Prefixed like events_${goalId} in userDefaults. This can be useful for tracking time spent.\n- ShieldIds. To reduce the storage strain on userDefaults shields are referenced with shieldIds.\n\n# Installation in bare React Native projects\n\nFor bare React Native projects, you must ensure that you have [installed and configured the `expo` package](https://docs.expo.dev/bare/installing-expo-modules/) before continuing.\n\n### Add the package to your npm dependencies\n\n```\nnpm install react-native-device-activity\n```\n\n### Configure for iOS\n\nRun `npx pod-install` after installing the npm package.\n\n## Family Controls (distribution) entitlement requires approval from Apple\n\nAs early as possible you want to [request approval from Apple](https://developer.apple.com/contact/request/family-controls-distribution), since it can take time to get approved.\n\nNote that until you have approval for all bundleIdentifiers you want to use, you are stuck with local development builds in XCode. I.e. you can't even build an Expo Dev Client.\n\nFor every base bundleIdentifier you need approval for 4 bundleIdentifiers (if you want to use all the native extensions that is, you can potentially just use the Shield-related ones if you have no need to listen to the events, or similarly just use the ActivityMonitor if you do not need control over the Shield UI):\n\n- com.your-bundleIdentifier\n- com.your-bundleIdentifier.ActivityMonitor\n- com.your-bundleIdentifier.ShieldAction\n- com.your-bundleIdentifier.ShieldConfiguration\n\nOnce you've gotten approval you need to manually add the \"Family Controls (Distribution)\" under Additional Capabilities for each of the bundleIdentifiers on [developer.apple.com](https://developer.apple.com/account/resources/identifiers/list) mentioned above. If you use Expo/EAS this has to be done only once, and after that provisioning will be handled automatically.\n\n⚠️ If you don't do all the above you will run in to a lot of strange provisioning errors.\n\n# Contributing\n\nContributions are very welcome! Please refer to guidelines described in the [contributing guide](https://github.com/expo/expo#contributing).\n\n# Weird behaviors ⚠️\n\n- Authorization changes outside app not captured\nWhen we've asked whether the user has authorized us to use screen time, and the state is changed outside the app, the native API doesn't update until the app restarts, i.e. this flow:\n  1. Ask for current permission\n  2. Change permission outside the app\n  3. Ask for current permission again will return same as (1)\n  4. **Workaround: restart the app**\n\n- We can both request and revoke permissions as we like, and how many times we like, even when the user has denied permissions. This is very unlike most authorization flows on iOS.\n\n- When calling `getAuthorizationStatus` it can sometimes return `notDetermined` even though the user has already made a choice, this comes with a delay. Workaround: keep polling the status for a while (`pollAuthorizationStatus` is a convenience function for this).\n\n- The DeviceActivitySelectionView is prone to crashes, which is outside of our control. The best we can do is provide fallback views that allows the user to know what's happening and reload the view.\n\n# Troubleshooting 📱\nThe Screen Time APIs are known to be very finnicky. Here are some things you can try to troubleshoot events not being reported:\n\n- Disable Low Power Mode (mentioned by Apple Community Specialist [here](https://discussions.apple.com/thread/254808070)) 🪫\n- Turn off/turn on app \u0026 website activity\n- Disable/reenable sync between devices for screen time\n- Restart device\n- Make sure device is not low on storage (mentioned by Apple Community Specialist [here](https://discussions.apple.com/thread/254808070)) 💾\n- Upgrade iOS version\n- Content \u0026 Privacy Restrictions: If any restrictions are enabled under Screen Time’s Content \u0026 Privacy Restrictions, ensure none are blocking your app.\n- Reset all device settings","funding_links":[],"categories":["Javascript"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkingstinct%2Freact-native-device-activity","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkingstinct%2Freact-native-device-activity","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkingstinct%2Freact-native-device-activity/lists"}