{"id":29916272,"url":"https://github.com/tenmax/tenmax-beacon-library-sdk-android","last_synced_at":"2025-08-02T04:43:26.054Z","repository":{"id":306010502,"uuid":"966509196","full_name":"tenmax/tenmax-beacon-library-sdk-android","owner":"tenmax","description":null,"archived":false,"fork":false,"pushed_at":"2025-07-23T05:18:03.000Z","size":249,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-07-23T07:14:01.947Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tenmax.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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,"zenodo":null}},"created_at":"2025-04-15T03:14:19.000Z","updated_at":"2025-07-23T05:15:36.000Z","dependencies_parsed_at":"2025-07-23T07:14:55.413Z","dependency_job_id":"b390b61f-8ff3-453d-99fa-fd8fcf694997","html_url":"https://github.com/tenmax/tenmax-beacon-library-sdk-android","commit_stats":null,"previous_names":["tenmax/tenmax-beacon-library-sdk-android"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/tenmax/tenmax-beacon-library-sdk-android","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tenmax%2Ftenmax-beacon-library-sdk-android","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tenmax%2Ftenmax-beacon-library-sdk-android/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tenmax%2Ftenmax-beacon-library-sdk-android/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tenmax%2Ftenmax-beacon-library-sdk-android/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tenmax","download_url":"https://codeload.github.com/tenmax/tenmax-beacon-library-sdk-android/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tenmax%2Ftenmax-beacon-library-sdk-android/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":268334819,"owners_count":24233827,"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","status":"online","status_checked_at":"2025-08-02T02:00:12.353Z","response_time":74,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":[],"created_at":"2025-08-02T04:43:16.929Z","updated_at":"2025-08-02T04:43:26.009Z","avatar_url":"https://github.com/tenmax.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"# TenMaxBeaconSDK for Android\n\n[![Version](https://img.shields.io/badge/version-1.0.0-blue.svg)](../VERSION)\n[![Platform](https://img.shields.io/badge/platform-Android%206.0%2B-lightgrey.svg)](https://developer.android.com/about/versions/marshmallow)\n[![Kotlin](https://img.shields.io/badge/kotlin-1.8.0%2B-orange.svg)](https://kotlinlang.org/)\n\nA Kotlin library for integrating TenMax Beacon tracking functionality into Android applications. This public distribution provides pre-compiled AAR files and complete integration examples for quick and easy SDK integration.\n\n## Features\n\n- **Beacon Detection**: Supports Bluetooth Low Energy (BLE) beacon detection with continuous scanning\n- **Background Scanning**: Continues beacon scanning even when the app is in the background using Foreground Service\n- **Frequency Capping**: Intelligent frequency control to prevent spam notifications with configurable intervals\n- **Beacon Deduplication**: Prevents processing duplicate beacon data within 30-second time windows (configurable)\n- **Network Connectivity**: Automatic network connectivity checking before API calls\n- **Notification Management**: Handles local notifications with click tracking and creative data content support\n- **Environment Support**: Separate configurations for staging and production environments\n- **Thread Safety**: All operations are thread-safe with proper concurrent queue management and automatic main thread callback execution\n- **Permission Management**: Comprehensive permission handling for Bluetooth, Location, and Notification permissions\n- **Auto-restart Support**: Automatic SDK restart after device boot\n\n## Quick Start\n\nFor a quick integration, follow these essential steps:\n\n1. **Add the SDK to your project** using AAR file or demo project\n2. **Add required permissions** to AndroidManifest.xml (see [Permission Requirements](#permission-requirements))\n3. **Initialize the SDK** in your Application or MainActivity\n4. **Implement the callback interface** to handle events\n5. **Start scanning** when appropriate\n\n## How to Add Beacon SDK to Your App\n\n### Method 1: Using Pre-compiled AAR File\n\n1. **Copy the AAR file to your project**\n   ```bash\n   cp libs/beacon-sdk-release.aar your-project/app/libs/\n   ```\n\n2. **Configure build.gradle**\n   ```gradle\n   dependencies {\n       implementation files('libs/beacon-sdk-release.aar')\n   }\n   ```\n\n### Method 2: Using Demo Project\n\n1. **Copy the demo project**\n   ```bash\n   cp -r sdkdemo your-new-project\n   cd your-new-project\n   ```\n\n2. **Build and run**\n   ```bash\n   ./gradlew :sdkdemo:assembleDebug\n   ./gradlew :sdkdemo:installDebug\n   ```\n\n## How to Use Beacon SDK in Your App\n\n### Basic Integration\n\n```kotlin\nimport com.tenmax.beacon.TenMaxAdBeaconSDK\nimport com.tenmax.beacon.TenMaxAdBeaconCallback\nimport com.tenmax.beacon.model.ClientProfile\nimport com.tenmax.beacon.model.TenMaxAdCreative\nimport com.tenmax.beacon.model.TenMaxAdBeaconError\nimport com.tenmax.beacon.api.Environment\n\n// Create client profile\nval clientProfile = ClientProfile(\n    phoneNumber = \"0912345678\",    // Optional: will be persisted and restored\n    email = \"user@example.com\",    // Optional: will be persisted and restored\n    appName = \"YourAppName\",\n    advertisingId = null           // Optional: auto-retrieved from Google Play Services\n)\n\n// Implement callback interface\nclass BeaconCallback : TenMaxAdBeaconCallback {\n    override fun onInitialized() {\n        Log.d(\"BeaconSDK\", \"SDK initialized successfully\")\n        \n        // Start SDK\n        TenMaxAdBeaconSDK.getInstance(applicationContext).start()\n    }\n\n    override fun onCreativeReceived(creative: TenMaxAdCreative) {\n        Log.d(\"BeaconSDK\", \"Received creative with data: ${creative.data}\")\n    }\n\n    override fun onError(error: TenMaxAdBeaconError) {\n        Log.e(\"BeaconSDK\", \"Error: ${error.message}\")\n    }\n\n    override fun onNotificationClicked(creative: TenMaxAdCreative) {\n        Log.d(\"BeaconSDK\", \"Notification clicked with data: ${creative.data}\")\n        // Handle data navigation\n    }\n}\n\n// Initialize SDK\nval sdk = TenMaxAdBeaconSDK.getInstance(applicationContext)\nsdk.initiate(\n    clientProfile = clientProfile,\n    callback = BeaconCallback(),\n    environment = Environment.PRODUCTION\n)\n```\n\n### SDK Lifecycle\n\nThe SDK follows a specific lifecycle pattern:\n\n1. **getInstance()**: Get SDK singleton instance\n2. **initiate()**: Initialize SDK with client profile, callback, and environment\n3. **onInitialized()**: Callback triggered when initialization completes\n4. **start()**: Begin beacon scanning (typically called in onInitialized callback)\n5. **isScanning**: Property to check current scanning status (returns true when actively scanning)\n6. **isInitialized**: Property to check if SDK has been properly initialized\n7. **stop()**: Stop beacon scanning when needed\n\n#### Initialization State Management\n\nThe SDK prevents duplicate initialization attempts. Use the `isInitialized` property to check initialization status:\n\n```kotlin\nval sdk = TenMaxAdBeaconSDK.getInstance(applicationContext)\n\nif (!sdk.isInitialized) {\n    // Safe to initialize\n    sdk.initiate(clientProfile, callback, Environment.PRODUCTION)\n} else {\n    // Already initialized, can start scanning\n    sdk.start()\n}\n```\n\n**Note**: You must specify the environment (`Environment.STAGE` or `Environment.PRODUCTION`) during initialization. Environment can only be set during initialization and cannot be changed later.\n\n### Advanced Configuration\n\n#### Custom Notification Configuration\n\n```kotlin\nimport com.tenmax.beacon.model.NotificationConfiguration\n\nval notificationConfig = NotificationConfiguration(\n    smallIcon = R.drawable.my_notification_icon,\n    channelName = \"My Beacon Notifications\",\n    channelDescription = \"Notifications from my beacon app\",\n    foregroundServiceTitle = \"My Beacon Scanning\",\n    foregroundServiceChannelName = \"My Beacon Service\",\n    foregroundServiceChannelDescription = \"Continuously scan for beacons\",\n    foregroundServiceContentText = \"Scanning for nearby beacons...\"\n)\n\n// Initialize SDK with custom notification configuration\nsdk.initiate(\n    clientProfile = clientProfile,\n    callback = callback,\n    environment = Environment.PRODUCTION,\n    notificationConfig = notificationConfig\n)\n```\n\n#### Updating Client Profile\n\n```kotlin\n// Update client profile\nval updatedProfile = ClientProfile(\n    phoneNumber = \"0987654321\",\n    email = \"new-email@example.com\",\n    appName = \"YourAppName\",\n    advertisingId = \"updated-advertising-id\"\n)\nTenMaxAdBeaconSDK.getInstance(applicationContext).updateClientProfile(updatedProfile)\n```\n\n#### Checking Scanning Status\n\n```kotlin\n// Check if SDK is currently scanning\nval isScanning = TenMaxAdBeaconSDK.getInstance(applicationContext).isScanning\nLog.d(\"BeaconSDK\", \"SDK is scanning: $isScanning\")\n```\n\n#### Stopping the SDK\n\n```kotlin\n// Stop SDK\nTenMaxAdBeaconSDK.getInstance(applicationContext).stop()\n```\n\n## Important Notes and Best Practices\n\n### Permission Requirements\n\nThe SDK requires several permissions to function properly:\n\n#### Required Permissions\n- **Bluetooth permissions**: For BLE beacon detection\n- **Location permissions**: Required for BLE scanning on Android\n- **Foreground Service permissions**: For background scanning\n- **Notification permissions**: For displaying notifications (Android 13+)\n\n#### Permission Handling Best Practices\n\n```kotlin\nimport android.Manifest\nimport android.content.pm.PackageManager\nimport android.os.Build\nimport androidx.core.app.ActivityCompat\nimport androidx.core.content.ContextCompat\n\nclass PermissionManager(private val activity: Activity) {\n\n    companion object {\n        private const val PERMISSION_REQUEST_CODE = 100\n    }\n\n    fun requestAllPermissions() {\n        val permissionsToRequest = mutableListOf\u003cString\u003e()\n\n        // Check Bluetooth permissions\n        if (Build.VERSION.SDK_INT \u003e= Build.VERSION_CODES.S) {\n            // Android 12+ requires new Bluetooth permissions\n            if (!hasPermission(Manifest.permission.BLUETOOTH_SCAN)) {\n                permissionsToRequest.add(Manifest.permission.BLUETOOTH_SCAN)\n            }\n            if (!hasPermission(Manifest.permission.BLUETOOTH_CONNECT)) {\n                permissionsToRequest.add(Manifest.permission.BLUETOOTH_CONNECT)\n            }\n        } else {\n            // Older versions check traditional Bluetooth permissions\n            if (!hasPermission(Manifest.permission.BLUETOOTH)) {\n                permissionsToRequest.add(Manifest.permission.BLUETOOTH)\n            }\n            if (!hasPermission(Manifest.permission.BLUETOOTH_ADMIN)) {\n                permissionsToRequest.add(Manifest.permission.BLUETOOTH_ADMIN)\n            }\n        }\n\n        // Check location permissions\n        if (!hasPermission(Manifest.permission.ACCESS_FINE_LOCATION)) {\n            permissionsToRequest.add(Manifest.permission.ACCESS_FINE_LOCATION)\n        }\n\n        // Check notification permission (Android 13+)\n        if (Build.VERSION.SDK_INT \u003e= Build.VERSION_CODES.TIRAMISU) {\n            if (!hasPermission(Manifest.permission.POST_NOTIFICATIONS)) {\n                permissionsToRequest.add(Manifest.permission.POST_NOTIFICATIONS)\n            }\n        }\n\n        if (permissionsToRequest.isNotEmpty()) {\n            ActivityCompat.requestPermissions(\n                activity,\n                permissionsToRequest.toTypedArray(),\n                PERMISSION_REQUEST_CODE\n            )\n        }\n    }\n\n    private fun hasPermission(permission: String): Boolean {\n        return ContextCompat.checkSelfPermission(activity, permission) == PackageManager.PERMISSION_GRANTED\n    }\n}\n```\n\n### Error Handling\n\nThe SDK provides comprehensive error handling through the `TenMaxAdBeaconError` class:\n\n```kotlin\nclass BeaconSDKCallback : TenMaxAdBeaconCallback {\n\n    override fun onError(error: TenMaxAdBeaconError) {\n        Log.e(\"BeaconSDK\", \"SDK Error: ${error.message}\")\n\n        when (error.code) {\n            TenMaxAdBeaconError.TenMaxAdBeaconErrorType.UNAUTHORIZED_LOCATION_PERMISSION -\u003e {\n                showLocationPermissionAlert()\n            }\n\n            TenMaxAdBeaconError.TenMaxAdBeaconErrorType.BLUETOOTH_DISABLED -\u003e {\n                showBluetoothDisabledAlert()\n            }\n\n            TenMaxAdBeaconError.TenMaxAdBeaconErrorType.BLUETOOTH_PERMISSION_DENIED -\u003e {\n                showBluetoothPermissionAlert()\n            }\n\n            TenMaxAdBeaconError.TenMaxAdBeaconErrorType.UNAUTHORIZED_NOTIFICATION_PERMISSION -\u003e {\n                showNotificationPermissionAlert()\n            }\n\n            TenMaxAdBeaconError.TenMaxAdBeaconErrorType.INTERNET_CONNECTION_UNAVAILABLE -\u003e {\n                showOfflineMessage()\n            }\n\n            TenMaxAdBeaconError.TenMaxAdBeaconErrorType.FREQUENCY_CAP_EXCEEDED -\u003e {\n                // This is normal behavior - creative was blocked due to frequency limits\n                Log.d(\"BeaconSDK\", \"Creative blocked due to frequency capping\")\n            }\n\n            TenMaxAdBeaconError.TenMaxAdBeaconErrorType.CONFIGURATION_ERROR -\u003e {\n                // Handle configuration issues\n                Log.e(\"BeaconSDK\", \"Configuration error: Check SDK initialization and configuration\")\n            }\n\n            TenMaxAdBeaconError.TenMaxAdBeaconErrorType.NOT_FOUND_CREATIVE_DATA -\u003e {\n                Log.d(\"BeaconSDK\", \"No creative content available for this beacon\")\n            }\n\n            else -\u003e {\n                showGenericErrorAlert(error.message)\n            }\n        }\n    }\n\n    // Implement other callback methods...\n}\n```\n\n### Data Persistence\n\nThe SDK automatically persists user profile data across app restarts:\n\n```kotlin\n// First time - provide user data\nval profile = ClientProfile(\n    phoneNumber = \"0912345678\",\n    email = \"user@example.com\",\n    appName = \"YourApp\"\n)\n\n// After app restart - data is automatically restored\n// The SDK automatically loads previously saved profile data\n```\n\n### Privacy Compliance\n\n#### Advertising ID Handling\n\n```kotlin\nimport com.google.android.gms.ads.identifier.AdvertisingIdClient\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.withContext\n\n// Correct implementation for advertising ID retrieval\nsuspend fun getAdvertisingIdSafely(context: Context): String? {\n    return withContext(Dispatchers.IO) {\n        try {\n            val adInfo = AdvertisingIdClient.getAdvertisingIdInfo(context)\n\n            // Check if user has limited ad tracking\n            if (adInfo.isLimitAdTrackingEnabled) {\n                // User has opted out of ad tracking - do not use advertising ID\n                Log.d(\"AdID\", \"User has limited ad tracking - not using advertising ID\")\n                null\n            } else {\n                // User allows ad tracking - safe to use advertising ID\n                Log.d(\"AdID\", \"Using advertising ID: ${adInfo.id}\")\n                adInfo.id\n            }\n        } catch (e: Exception) {\n            Log.e(\"AdID\", \"Failed to get advertising ID: ${e.message}\")\n            null\n        }\n    }\n}\n```\n\n**Important**: Always respect user privacy preferences. When `isLimitAdTrackingEnabled` returns `true`, do not use the advertising ID for tracking purposes.\n\n## System Requirements\n\n- **Android**: 6.0 (API level 23) or later\n- **Kotlin**: 1.8.0 or later\n- **Compile SDK**: 33 or later\n- **Target SDK**: 33 or later\n\n### Device Requirements\n\n- **Bluetooth**: Bluetooth 4.0 (Bluetooth Low Energy) or later\n- **Location Services**: Required for beacon detection\n- **Background App Refresh**: Recommended for optimal background scanning\n\n## Troubleshooting\n\n### Common Issues\n\n#### Beacon Detection Not Working\n- Ensure location permissions are granted\n- Verify Bluetooth is enabled\n- Test on physical device (simulator limitations)\n- Check beacon configuration in SDK settings\n\n#### Notifications Not Appearing\n- Confirm notification permissions are granted\n- Verify app is not in Do Not Disturb mode\n- Check notification settings in Android Settings\n- Check if device has network connectivity\n\n#### Build Errors\n- Clean build folder (Build \u003e Clean Project)\n- Update to latest Android Studio version\n- Verify AAR file is properly included in libs directory\n\n### Performance Considerations\n\n- **Battery Usage**: Beacon scanning uses Bluetooth and location services, which can impact battery life\n- **Frequency Capping**: The SDK automatically implements frequency capping to prevent excessive notifications\n- **Network Usage**: Creative content is fetched from CDN only when beacons are detected\n- **Beacon Deduplication**: The SDK prevents duplicate beacon processing within 30-second intervals\n\n## Google Privacy Survey for TenMax SDK\n\nAndroid publisher should provide the information that data their apps collect, including the data collected by third-party SDKs. For your convenience, TenMax SDK provides the information on its data collection in the [Data Collection Survey for TenMax SDK](Privacy.md).\n\n## Issues and Contact\n\nIf you encounter any issues using the TenMax Beacon SDK, please contact us at app_support@tenmax.io. We will assist you as soon as possible.\n\nFor technical support or questions:\n- **Email**: app_support@tenmax.io\n- **Demo Code**: Check the implementation examples in `sdkdemo` directory\n\n## User Data Deletion Notice\n\nFor requests to delete the privacy data linked to users, please submit the request via [User Data Deletion Notice Form](https://forms.office.com/r/SnU40q6VmQ).\n\n## License\n\nTenMax\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftenmax%2Ftenmax-beacon-library-sdk-android","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftenmax%2Ftenmax-beacon-library-sdk-android","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftenmax%2Ftenmax-beacon-library-sdk-android/lists"}