├── .gitignore ├── .idea └── .gitignore ├── README.md ├── _config.yml ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── ru │ │ └── unidevidlib │ │ └── adg │ │ ├── App.kt │ │ ├── MainActivity.kt │ │ └── MainActivityVM.kt │ └── res │ ├── drawable-v24 │ └── ic_launcher_foreground.xml │ ├── drawable │ └── ic_launcher_background.xml │ ├── layout │ └── activity_main.xml │ ├── mipmap-anydpi-v26 │ ├── ic_launcher.xml │ └── ic_launcher_round.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 │ ├── values-night │ └── themes.xml │ └── values │ ├── colors.xml │ ├── strings.xml │ └── themes.xml ├── build.gradle ├── gradle.properties ├── gradle ├── publish_github.gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── lib ├── .gitignore ├── build.gradle ├── consumer-rules.pro ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ └── java │ └── ru │ └── unidevid │ └── lib │ ├── DeviceIDUtil.java │ ├── UdidManager.kt │ └── udid │ ├── OpenUdidService.kt │ └── OpenUuidManager.kt └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/navEditor.xml 9 | /.idea/assetWizardSettings.xml 10 | .DS_Store 11 | /build 12 | /captures 13 | .externalNativeBuild 14 | .cxx 15 | local.properties 16 | /github.properties 17 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # android-uniDevId 2 | Android Iniversal Device ID Library 3 | 4 | - Use OpenUDID_manager for old API and MediaDrm for new API 5 | - If both options return an empty string, then a random UUID is generated and saved in Preferences until the application is reinstalled 6 | 7 | ### Installation 8 | 9 | - First add this repo to your project:```mavenCentral()``` 10 | - Second add this dependency to your module build.gradle: ```implementation 'io.github.beeline09.android-uniDevId:uniDevId:1.0.3'``` 11 | 12 | ### Usage 13 | Before get Device ID we need to init lib by command: ```UdidManager.init(this)```. 14 | It is highly recommended to do this in `onCreate` method of Application class 15 | 16 | For get Device UUID in any place of your app, you need to call: `UdidManager.getUUID()` 17 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.android.application' 3 | id 'kotlin-android' 4 | id 'kotlin-kapt' 5 | } 6 | apply plugin: 'kotlin-android' 7 | 8 | android { 9 | compileSdkVersion 30 10 | buildToolsVersion "30.0.3" 11 | 12 | defaultConfig { 13 | applicationId "ru.unidevidlib.adg" 14 | minSdkVersion 14 15 | targetSdkVersion 30 16 | versionCode 1 17 | versionName "$libVersion" 18 | 19 | multiDexEnabled true 20 | 21 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 22 | } 23 | 24 | buildFeatures { 25 | dataBinding true 26 | viewBinding true 27 | } 28 | 29 | buildTypes { 30 | release { 31 | minifyEnabled false 32 | multiDexEnabled true 33 | buildConfigField 'boolean', 'IS_DEBUG', 'false' 34 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 35 | } 36 | debug { 37 | minifyEnabled false 38 | buildConfigField 'boolean', 'IS_DEBUG', 'true' 39 | multiDexEnabled true 40 | } 41 | } 42 | compileOptions { 43 | sourceCompatibility JavaVersion.VERSION_1_8 44 | targetCompatibility JavaVersion.VERSION_1_8 45 | } 46 | kotlinOptions { 47 | jvmTarget = '1.8' 48 | } 49 | } 50 | 51 | dependencies { 52 | 53 | implementation project('::lib') 54 | 55 | implementation 'androidx.core:core-ktx:1.6.0-alpha03' 56 | implementation 'androidx.appcompat:appcompat:1.3.0-rc01' 57 | implementation 'com.google.android.material:material:1.4.0-alpha02' 58 | implementation 'androidx.constraintlayout:constraintlayout:2.1.0-beta02' 59 | 60 | implementation 'androidx.fragment:fragment-ktx:1.3.3' 61 | implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.4.0-alpha01" 62 | implementation "androidx.lifecycle:lifecycle-service:2.4.0-alpha01" 63 | 64 | implementation "androidx.core:core-ktx:1.3.2" 65 | implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1" 66 | 67 | } 68 | repositories { 69 | mavenCentral() 70 | } -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/java/ru/unidevidlib/adg/App.kt: -------------------------------------------------------------------------------- 1 | package ru.unidevidlib.adg 2 | 3 | import android.app.Application 4 | import android.content.Context 5 | import androidx.multidex.MultiDex 6 | import ru.unidevid.lib.UdidManager 7 | 8 | 9 | class App : Application() { 10 | override fun attachBaseContext(base: Context?) { 11 | super.attachBaseContext(base) 12 | MultiDex.install(this) 13 | } 14 | 15 | override fun onCreate() { 16 | super.onCreate() 17 | UdidManager.init(this) 18 | } 19 | } -------------------------------------------------------------------------------- /app/src/main/java/ru/unidevidlib/adg/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package ru.unidevidlib.adg 2 | 3 | import android.os.Bundle 4 | import androidx.activity.viewModels 5 | import androidx.appcompat.app.AppCompatActivity 6 | import androidx.databinding.DataBindingUtil 7 | import ru.unidevid.lib.UdidManager 8 | import ru.unidevidlib.adg.databinding.ActivityMainBinding 9 | 10 | 11 | class MainActivity : AppCompatActivity() { 12 | 13 | private val vm by viewModels() 14 | private lateinit var binding: ActivityMainBinding 15 | 16 | override fun onCreate(savedInstanceState: Bundle?) { 17 | super.onCreate(savedInstanceState) 18 | 19 | binding = DataBindingUtil.setContentView(this, R.layout.activity_main) 20 | binding.lifecycleOwner = this 21 | binding.vm = vm 22 | } 23 | 24 | override fun onResume() { 25 | super.onResume() 26 | vm.uuid.postValue(UdidManager.getUUID()) 27 | } 28 | } -------------------------------------------------------------------------------- /app/src/main/java/ru/unidevidlib/adg/MainActivityVM.kt: -------------------------------------------------------------------------------- 1 | package ru.unidevidlib.adg 2 | 3 | import androidx.lifecycle.MutableLiveData 4 | import androidx.lifecycle.ViewModel 5 | 6 | class MainActivityVM : ViewModel() { 7 | val uuid = MutableLiveData("") 8 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 15 | 18 | 21 | 22 | 23 | 24 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 11 | 12 | 13 | 17 | 18 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beeline09/android-uniDevId/fcbc35c1650c7042badeeee9d8367a91b14335db/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beeline09/android-uniDevId/fcbc35c1650c7042badeeee9d8367a91b14335db/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beeline09/android-uniDevId/fcbc35c1650c7042badeeee9d8367a91b14335db/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beeline09/android-uniDevId/fcbc35c1650c7042badeeee9d8367a91b14335db/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beeline09/android-uniDevId/fcbc35c1650c7042badeeee9d8367a91b14335db/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beeline09/android-uniDevId/fcbc35c1650c7042badeeee9d8367a91b14335db/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beeline09/android-uniDevId/fcbc35c1650c7042badeeee9d8367a91b14335db/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beeline09/android-uniDevId/fcbc35c1650c7042badeeee9d8367a91b14335db/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beeline09/android-uniDevId/fcbc35c1650c7042badeeee9d8367a91b14335db/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beeline09/android-uniDevId/fcbc35c1650c7042badeeee9d8367a91b14335db/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/values-night/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FFBB86FC 4 | #FF6200EE 5 | #FF3700B3 6 | #FF03DAC5 7 | #FF018786 8 | #FF000000 9 | #FFFFFFFF 10 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | UniDevIdApp 3 | -------------------------------------------------------------------------------- /app/src/main/res/values/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | buildscript { 3 | ext.kotlin_version = '1.5.0-release-764' 4 | 5 | ext { 6 | libVersion = "1.0.3" 7 | 8 | fragment_ktx = '1.3.3' 9 | livedata_ktx = '2.3.1' 10 | lifecycle_service = '2.3.1' 11 | lifecycle_common = "2.2.0" 12 | activity_ktx = "1.2.0-rc01" 13 | } 14 | 15 | repositories { 16 | google() 17 | mavenCentral() 18 | maven { 19 | url 'https://maven.google.com' 20 | } 21 | maven { 22 | url "https://plugins.gradle.org/m2/" 23 | } 24 | } 25 | dependencies { 26 | classpath 'com.android.tools.build:gradle:7.0.0-alpha15' 27 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.0" 28 | 29 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 30 | 31 | classpath 'com.vanniktech:gradle-maven-publish-plugin:0.15.1' 32 | } 33 | } 34 | 35 | allprojects { 36 | repositories { 37 | google() 38 | mavenCentral() 39 | maven { 40 | url 'https://maven.google.com' 41 | } 42 | maven { 43 | url "https://plugins.gradle.org/m2/" 44 | } 45 | } 46 | 47 | plugins.withId("com.vanniktech.maven.publish") { 48 | mavenPublish { 49 | sonatypeHost = "S01" 50 | } 51 | } 52 | } 53 | 54 | task clean(type: Delete) { 55 | delete rootProject.buildDir 56 | } 57 | 58 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | # AndroidX package structure to make it clearer which packages are bundled with the 15 | # Android operating system, and which are packaged with your app"s APK 16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 17 | android.useAndroidX=true 18 | # Kotlin code style for this project: "official" or "obsolete": 19 | kotlin.code.style=official 20 | 21 | GROUP=io.github.beeline09.android-uniDevId 22 | POM_ARTIFACT_ID=uniDevId 23 | VERSION_NAME=1.0.3 24 | 25 | POM_NAME=unidevidlib 26 | POM_PACKAGING=aar 27 | 28 | POM_DESCRIPTION=Android Universal Device ID Library 29 | POM_INCEPTION_YEAR=2021 30 | 31 | POM_URL=https://beeline09.github.io/android-uniDevId/ 32 | POM_SCM_URL=https://github.com/beeline09/android-uniDevId.git 33 | POM_SCM_CONNECTION=scm:git@github.com:beeline09/android-uniDevId.git 34 | POM_SCM_DEV_CONNECTION=scm:git@github.com:beeline09/android-uniDevId.git 35 | 36 | POM_LICENCE_NAME=The Apache Software License, Version 2.0 37 | POM_LICENCE_URL=http://www.apache.org/licenses/LICENSE-2.0.txt 38 | POM_LICENCE_DIST=repo 39 | 40 | POM_DEVELOPER_ID=beeline09 41 | POM_DEVELOPER_NAME=Rasul Ismailov 42 | POM_DEVELOPER_URL=https://github.com/beeline09 -------------------------------------------------------------------------------- /gradle/publish_github.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Chris Banes 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * BSD 3-Clause License 19 | * 20 | * Copyright (c) 2019, Sky Italia 21 | * All rights reserved. 22 | * 23 | * Redistribution and use in source and binary forms, with or without 24 | * modification, are permitted provided that the following conditions are met: 25 | * 26 | * * Redistributions of source code must retain the above copyright notice, this 27 | * list of conditions and the following disclaimer. 28 | * 29 | * * Redistributions in binary form must reproduce the above copyright notice, 30 | * this list of conditions and the following disclaimer in the documentation 31 | * and/or other materials provided with the distribution. 32 | * 33 | * * Neither the name of the copyright holder nor the names of its 34 | * contributors may be used to endorse or promote products derived from 35 | * this software without specific prior written permission. 36 | * 37 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 38 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 39 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 40 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 41 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 42 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 43 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 44 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 45 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 46 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 47 | */ 48 | 49 | /* 50 | * Copyright 2020 Rúben Sousa 51 | * 52 | * Licensed under the Apache License, Version 2.0 (the "License"); 53 | * you may not use this file except in compliance with the License. 54 | * You may obtain a copy of the License at 55 | * 56 | * http://www.apache.org/licenses/LICENSE-2.0 57 | * 58 | * Unless required by applicable law or agreed to in writing, software 59 | * distributed under the License is distributed on an "AS IS" BASIS, 60 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 61 | * See the License for the specific language governing permissions and 62 | * limitations under the License. 63 | */ 64 | 65 | /* 66 | * Adapted from: https://github.com/chrisbanes/gradle-mvn-push 67 | * and: https://github.com/sky-uk/gradle-maven-plugin/blob/master/artifact-pom-manager.gradle 68 | * 69 | * This script requires the following variables: 70 | * 71 | * --- LIBRARY INFORMATION --- 72 | * 73 | * LIBRARY_VERSION=1.0.0-rc01 74 | * LIBRARY_GROUP=com.library.package 75 | * LIBRARY_ARTIFACT=library 76 | * LIBRARY_PUBLISH_SOURCES=true // default is true 77 | * LIBRARY_PUBLISH_DOCS=true // default is true 78 | * 79 | * Gradle path for installation will be: com.library.package:library 80 | * 81 | * --- GITHUB PACKAGES INFORMATION --- 82 | * 83 | * GITHUB_OWNER=githubuser 84 | * GITHUB_REPOSITORY=Library 85 | * 86 | * Maven repository url will be: https://maven.pkg.github.com/githubuser/Library 87 | * 88 | * --- POM INFORMATION --- 89 | * 90 | * POM_PACKAGING=aar 91 | * POM_NAME=Library 92 | * POM_DESCRIPTION=A sample library that's published to github packages 93 | * POM_URL=https://github.com/githubuser/Library 94 | * POM_SCM_URL=https://github.com/githubuser/githubuser 95 | * POM_SCM_CONNECTION=scm:git@github.com:githubuser/githubuser.git 96 | * POM_SCM_DEV_CONNECTION=scm:git@github.com:githubuser/githubuser.git 97 | * POM_DEVELOPER_ID=githubuser 98 | * POM_DEVELOPER_NAME=Github User 99 | * POM_LICENCE_NAME=The Apache Software License, Version 2.0 100 | * POM_LICENCE_URL=http://www.apache.org/licenses/LICENSE-2.0.txt 101 | * POM_LICENCE_DIST=repo 102 | */ 103 | 104 | buildscript { 105 | repositories { 106 | jcenter() 107 | } 108 | dependencies { 109 | classpath "org.jetbrains.dokka:dokka-gradle-plugin:0.10.1" 110 | } 111 | } 112 | 113 | apply plugin: 'maven-publish' 114 | 115 | 116 | def isDokkaAvailable = project.tasks.findByName('dokka') 117 | 118 | // Check if the project has dokka setup before trying to apply the plugin 119 | // If dokka isn't setup, javadocs won't be generated for kotlin files 120 | if (isDokkaAvailable) { 121 | apply plugin: 'org.jetbrains.dokka' 122 | } 123 | 124 | afterEvaluate { project -> 125 | 126 | def publishSources = shouldPublishSources() 127 | def publishDocs = shouldPublishDocs() 128 | 129 | if (publishDocs) { 130 | 131 | // If dokka is setup, generate the javadocs for kotlin files 132 | if (isDokkaAvailable) { 133 | task dokkaJavadoc(type: dokka.class) { 134 | outputFormat = 'javadoc' 135 | outputDirectory = "$buildDir/javadoc" 136 | } 137 | 138 | task dokkaJavadocsJar(type: Jar, dependsOn: dokkaJavadoc) { 139 | getArchiveClassifier().set('javadoc') 140 | from dokkaJavadoc.outputDirectory 141 | } 142 | } 143 | 144 | task androidJavadocs(type: Javadoc) { 145 | source = android.sourceSets.main.java.source 146 | classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) 147 | excludes = ['**/*.kt'] 148 | } 149 | 150 | task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) { 151 | getArchiveClassifier().set('javadoc') 152 | from androidJavadocs.destinationDir 153 | } 154 | 155 | if (JavaVersion.current().isJava8Compatible()) { 156 | allprojects { 157 | tasks.withType(Javadoc) { 158 | options.addStringOption('Xdoclint:none', '-quiet') 159 | } 160 | } 161 | } 162 | 163 | if (JavaVersion.current().isJava9Compatible()) { 164 | allprojects { 165 | tasks.withType(Javadoc) { 166 | options.addBooleanOption('html5', true) 167 | } 168 | } 169 | } 170 | 171 | android.libraryVariants.all { variant -> 172 | tasks.androidJavadocs.doFirst { 173 | classpath += files(variant.javaCompileProvider.get().classpath.files 174 | .join(File.pathSeparator)) 175 | } 176 | } 177 | 178 | if (isDokkaAvailable) { 179 | artifacts { 180 | archives dokkaJavadocsJar 181 | } 182 | } else { 183 | artifacts { 184 | archives androidJavadocsJar 185 | } 186 | } 187 | } 188 | 189 | if (publishSources) { 190 | task androidSourcesJar(type: Jar) { 191 | getArchiveClassifier().set('sources') 192 | from android.sourceSets.main.java.source 193 | } 194 | 195 | artifacts { 196 | archives androidSourcesJar 197 | } 198 | } 199 | 200 | publishing { 201 | repositories { 202 | maven { 203 | url = getRepositoryUrl() 204 | credentials { 205 | username = GITHUB_USER 206 | password = GITHUB_TOKEN 207 | } 208 | } 209 | } 210 | publications { 211 | release(MavenPublication) { 212 | from components.release 213 | groupId LIBRARY_GROUP 214 | version LIBRARY_VERSION 215 | artifactId LIBRARY_ARTIFACT 216 | if (publishSources) { 217 | artifact androidSourcesJar 218 | } 219 | if (publishDocs) { 220 | if (isDokkaAvailable) { 221 | artifact dokkaJavadocsJar 222 | } else { 223 | artifact androidJavadocsJar 224 | } 225 | } 226 | configurePom(pom) 227 | } 228 | } 229 | } 230 | } 231 | 232 | def shouldPublishSources() { 233 | if (hasProperty("LIBRARY_PUBLISH_SOURCES")) { 234 | return LIBRARY_PUBLISH_SOURCES == "true" 235 | } else { 236 | return true 237 | } 238 | } 239 | 240 | def shouldPublishDocs() { 241 | if (hasProperty("LIBRARY_PUBLISH_DOCS")) { 242 | return LIBRARY_PUBLISH_DOCS == "true" 243 | } else { 244 | return true 245 | } 246 | } 247 | 248 | def getRepositoryUrl() { 249 | return "https://maven.pkg.github.com/" + GITHUB_OWNER + "/" + GITHUB_REPOSITORY 250 | } 251 | 252 | def configurePom(pom) { 253 | pom.name = POM_NAME 254 | pom.packaging = POM_PACKAGING 255 | pom.description = POM_DESCRIPTION 256 | pom.url = POM_URL 257 | 258 | pom.scm { 259 | url = POM_SCM_URL 260 | connection = POM_SCM_CONNECTION 261 | developerConnection = POM_SCM_DEV_CONNECTION 262 | } 263 | 264 | if (hasProperty('POM_LICENSE_NAME')) { 265 | pom.licenses { 266 | license { 267 | name = POM_LICENCE_NAME 268 | url = POM_LICENCE_URL 269 | distribution = POM_LICENCE_DIST 270 | } 271 | } 272 | } 273 | 274 | pom.developers { 275 | developer { 276 | id = POM_DEVELOPER_ID 277 | name = POM_DEVELOPER_NAME 278 | } 279 | } 280 | } 281 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beeline09/android-uniDevId/fcbc35c1650c7042badeeee9d8367a91b14335db/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Tue Dec 29 15:23:03 MSK 2020 2 | distributionBase=GRADLE_USER_HOME 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-bin.zip 4 | distributionPath=wrapper/dists 5 | zipStorePath=wrapper/dists 6 | zipStoreBase=GRADLE_USER_HOME 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /lib/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /lib/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.android.library' 3 | id 'kotlin-android' 4 | id 'com.vanniktech.maven.publish' 5 | } 6 | 7 | 8 | android { 9 | compileSdkVersion 30 10 | buildToolsVersion "30.0.3" 11 | 12 | defaultConfig { 13 | minSdkVersion 14 14 | targetSdkVersion 30 15 | versionCode 2 16 | versionName "$libVersion" 17 | 18 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 19 | consumerProguardFiles "consumer-rules.pro" 20 | 21 | } 22 | 23 | buildTypes { 24 | release { 25 | minifyEnabled false 26 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 27 | } 28 | } 29 | 30 | compileOptions { 31 | sourceCompatibility JavaVersion.VERSION_1_8 32 | targetCompatibility JavaVersion.VERSION_1_8 33 | } 34 | kotlinOptions { 35 | jvmTarget = '1.8' 36 | } 37 | sourceSets { 38 | main.java.srcDirs += 'src/main/kotlin' 39 | } 40 | } 41 | 42 | dependencies { 43 | implementation fileTree(dir: 'libs', include: ['*.jar']) 44 | implementation 'androidx.appcompat:appcompat:1.2.0' 45 | implementation 'org.jetbrains:annotations:16.0.1' 46 | implementation "androidx.core:core-ktx:1.3.2" 47 | } 48 | 49 | 50 | repositories { 51 | mavenCentral() 52 | } 53 | -------------------------------------------------------------------------------- /lib/consumer-rules.pro: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beeline09/android-uniDevId/fcbc35c1650c7042badeeee9d8367a91b14335db/lib/consumer-rules.pro -------------------------------------------------------------------------------- /lib/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile -------------------------------------------------------------------------------- /lib/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /lib/src/main/java/ru/unidevid/lib/DeviceIDUtil.java: -------------------------------------------------------------------------------- 1 | package ru.unidevid.lib; 2 | 3 | import android.media.MediaDrm; 4 | import android.media.UnsupportedSchemeException; 5 | import android.os.Build; 6 | import android.util.Log; 7 | 8 | import androidx.annotation.NonNull; 9 | import androidx.annotation.RequiresApi; 10 | 11 | import java.security.MessageDigest; 12 | import java.security.NoSuchAlgorithmException; 13 | import java.util.UUID; 14 | 15 | import ru.unidevid.lib.udid.OpenUuidManager; 16 | 17 | @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2) 18 | class DeviceIDUtil { 19 | private static final String TAG = "DeviceIDUtil"; 20 | 21 | private static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray(); 22 | 23 | @NonNull 24 | public static String getUniqueID() { 25 | UUID widevine_uuid = new UUID(-0x121074568629b532L, -0x5c37d8232ae2de13L); 26 | MediaDrm wvDrm = null; 27 | 28 | try { 29 | wvDrm = new MediaDrm(widevine_uuid); 30 | byte[] mivevineId = wvDrm.getPropertyByteArray(MediaDrm.PROPERTY_DEVICE_UNIQUE_ID); 31 | MessageDigest md = MessageDigest.getInstance("SHA-256"); 32 | md.update(mivevineId); 33 | 34 | return bytesToHex(md.digest()); 35 | } catch (UnsupportedSchemeException | NoSuchAlgorithmException e) { 36 | return OpenUuidManager.Companion.getOpenUDID(); 37 | } finally { 38 | if (isAndroidTargetPieAndHigher()) { 39 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && wvDrm != null) { 40 | wvDrm.close(); 41 | } 42 | } else if (wvDrm != null) { 43 | wvDrm.release(); 44 | } 45 | } 46 | } 47 | 48 | private static boolean isAndroidTargetPieAndHigher() { 49 | boolean retval = false; 50 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { 51 | retval = true; 52 | } 53 | return retval; 54 | } 55 | 56 | @NonNull 57 | public static String bytesToHex(@NonNull byte[] bytes) { 58 | char[] hexChars = new char[bytes.length * 2]; 59 | // Log.e("HexChars", new String(hexChars)); 60 | for (int j = 0; j < bytes.length; j++) { 61 | int v = bytes[j] & 0xFF; 62 | hexChars[j * 2] = HEX_ARRAY[v >>> 4]; 63 | hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F]; 64 | } 65 | return new String(hexChars); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /lib/src/main/java/ru/unidevid/lib/UdidManager.kt: -------------------------------------------------------------------------------- 1 | package ru.unidevid.lib 2 | 3 | import android.annotation.SuppressLint 4 | import android.content.Context 5 | import android.os.Build 6 | import android.util.Base64 7 | import ru.unidevid.lib.udid.OpenUuidManager 8 | import java.util.* 9 | 10 | class UdidManager private constructor(context: Context) { 11 | 12 | init { 13 | OpenUuidManager.sync(context = context) 14 | } 15 | 16 | companion object { 17 | private lateinit var instance: UdidManager 18 | 19 | fun init(context: Context): UdidManager { 20 | synchronized(UdidManager::class) { 21 | if (!Companion::instance.isInitialized) { 22 | instance = UdidManager(context = context) 23 | } 24 | } 25 | return instance 26 | } 27 | 28 | @SuppressLint("ObsoleteSdkInt") 29 | fun getUUID(): String { 30 | 31 | if (!Companion::instance.isInitialized) { 32 | throw Exception("UdidManager instance has not been initialised") 33 | } 34 | 35 | return if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) { 36 | val oldUUID = UUID.nameUUIDFromBytes( 37 | OpenUuidManager.getOpenUDID().toByteArray() 38 | ).toString() 39 | // Log.e("oldUUID", oldUUID) 40 | oldUUID 41 | } else { 42 | val newUUID = UUID.nameUUIDFromBytes( 43 | (Base64.encodeToString( 44 | DeviceIDUtil.getUniqueID().toByteArray(), 0 45 | )).toByteArray() 46 | ).toString() 47 | // Log.e("newUUID", newUUID) 48 | newUUID 49 | } 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /lib/src/main/java/ru/unidevid/lib/udid/OpenUdidService.kt: -------------------------------------------------------------------------------- 1 | package ru.unidevid.lib.udid 2 | 3 | import android.app.Service 4 | import android.content.Intent 5 | import android.os.Binder 6 | import android.os.IBinder 7 | import android.os.Parcel 8 | 9 | internal class OpenUdidService : Service() { 10 | 11 | override fun onBind(arg0: Intent): IBinder? { 12 | return object : Binder() { 13 | public override fun onTransact( 14 | code: Int, 15 | data: Parcel, 16 | reply: Parcel?, 17 | flags: Int 18 | ): Boolean { 19 | val preferences = getSharedPreferences(OpenUuidManager.PREFS_NAME, MODE_PRIVATE) 20 | reply?.writeInt(data.readInt()) //Return to the sender the input random number 21 | reply?.writeString(preferences.getString(OpenUuidManager.PREF_KEY, null)) 22 | return true 23 | } 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /lib/src/main/java/ru/unidevid/lib/udid/OpenUuidManager.kt: -------------------------------------------------------------------------------- 1 | package ru.unidevid.lib.udid 2 | 3 | import android.annotation.SuppressLint 4 | import android.content.* 5 | import android.content.pm.ResolveInfo 6 | import android.os.IBinder 7 | import android.os.Parcel 8 | import android.os.RemoteException 9 | import android.util.Log 10 | import java.math.BigInteger 11 | import java.security.SecureRandom 12 | import java.util.* 13 | 14 | class OpenUuidManager private constructor(context: Context) : ServiceConnection { 15 | private val mContext //Application context 16 | : Context 17 | private var mMatchingIntents //List of available OpenUDID Intents 18 | : MutableList? = null 19 | private val mReceivedOpenUDIDs //Map of OpenUDIDs found so far 20 | : MutableMap 21 | private val mPreferences: SharedPreferences //Preferences to store the OpenUDID 22 | private val mRandom: Random 23 | override fun onServiceConnected(className: ComponentName, service: IBinder) { 24 | //Get the OpenUDID from the remote service 25 | try { 26 | //Send a random number to the service 27 | val data = Parcel.obtain() 28 | data.writeInt(mRandom.nextInt()) 29 | val reply = Parcel.obtain() 30 | service.transact(1, Parcel.obtain(), reply, 0) 31 | if (data.readInt() == reply.readInt()) //Check if the service returns us this number 32 | { 33 | val openUDID = reply.readString() 34 | if (openUDID != null) { //if valid OpenUDID, save it 35 | //Log.e(TAG, "Received $openUDID") 36 | if (mReceivedOpenUDIDs.containsKey(openUDID)) mReceivedOpenUDIDs[openUDID] = mReceivedOpenUDIDs[openUDID]!! + 1 else mReceivedOpenUDIDs[openUDID] = 1 37 | } 38 | } 39 | data.recycle() 40 | } catch (e: RemoteException) { 41 | //Log.e(TAG, "RemoteException: " + e.message) 42 | } 43 | mContext.unbindService(this) 44 | startService() //Try the next one 45 | } 46 | 47 | override fun onServiceDisconnected(className: ComponentName) {} 48 | private fun storeOpenUDID() { 49 | val e = mPreferences.edit() 50 | e.putString(PREF_KEY, OpenUDID) 51 | e.apply() 52 | } 53 | 54 | /* 55 | * Generate a new OpenUDID 56 | */ 57 | private fun generateOpenUDID() { 58 | //Log.e(TAG, "Generating openUDID") 59 | // //Try to get the ANDROID_ID 60 | // OpenUDID = Secure.getString(mContext.contentResolver, Secure.ANDROID_ID) 61 | // if (OpenUDID == null || OpenUDID == "9774d56d682e549c" || OpenUDID!!.length < 15) { 62 | // //if ANDROID_ID is null, or it's equals to the GalaxyTab generic ANDROID_ID or bad, generates a new one 63 | val random = SecureRandom() 64 | OpenUDID = BigInteger(64, random).toString(16) 65 | // } 66 | } 67 | 68 | /* 69 | * Start the oldest service 70 | */ 71 | private fun startService() { 72 | if (mMatchingIntents?.isNotEmpty() == true) { //There are some Intents untested 73 | //Log.e(TAG, "Trying service " + mMatchingIntents!![0].loadLabel(mContext.packageManager)) 74 | val servInfo = mMatchingIntents?.get(0)?.serviceInfo 75 | val i = Intent() 76 | i.component = servInfo?.applicationInfo?.packageName?.let { ComponentName(it, servInfo.name) } 77 | mMatchingIntents?.removeAt(0) 78 | try { // try added by Lionscribe 79 | mContext.bindService(i, this, Context.BIND_AUTO_CREATE) 80 | } catch (e: SecurityException) { 81 | startService() // ignore this one, and start next one 82 | } 83 | } else { //No more service to test 84 | calcOpenUDID() //Choose the most frequent 85 | if (OpenUDID == null) //No OpenUDID was chosen, generate one 86 | generateOpenUDID() 87 | //Log.e(TAG, "OpenUDID: $OpenUDID") 88 | storeOpenUDID() //Store it locally 89 | isInitialized = true 90 | } 91 | } 92 | 93 | private fun calcOpenUDID(){ 94 | if (mReceivedOpenUDIDs.isNotEmpty()) { 95 | val sortedOpenUDIDS: TreeMap = TreeMap(ValueComparator()) 96 | sortedOpenUDIDS.putAll(mReceivedOpenUDIDs) 97 | OpenUDID = sortedOpenUDIDS.firstKey() 98 | } 99 | } 100 | 101 | 102 | 103 | /* 104 | * Used to sort the OpenUDIDs collected by occurrence 105 | */ 106 | private inner class ValueComparator : Comparator { 107 | override fun compare(a: Any?, b: Any?): Int { 108 | return when { 109 | mReceivedOpenUDIDs[a]!! < mReceivedOpenUDIDs[b]!! -> { 110 | 1 111 | } 112 | mReceivedOpenUDIDs[a] === mReceivedOpenUDIDs[b] -> { 113 | 0 114 | } 115 | else -> { 116 | -1 117 | } 118 | } 119 | } 120 | } 121 | 122 | companion object { 123 | const val PREF_KEY = "openudid" 124 | const val PREFS_NAME = "openudid_prefs" 125 | const val TAG = "OpenUDID" 126 | private var OpenUDID: String? = null 127 | 128 | /** 129 | * The Method to call to get OpenUDID 130 | * @return the OpenUDID 131 | */ 132 | var isInitialized = false 133 | private set 134 | 135 | /** 136 | * The Method to call to get OpenUDID 137 | * @return the OpenUDID 138 | */ 139 | fun getOpenUDID(): String { 140 | if (!isInitialized) Log.e("OpenUDID", "Initialisation isn't done") 141 | return OpenUDID?:UUID.randomUUID().toString() 142 | } 143 | 144 | /** 145 | * The Method the call at the init of your app 146 | * @param context you current context 147 | */ 148 | @SuppressLint("QueryPermissionsNeeded") 149 | fun sync(context: Context) { 150 | //Initialise the Manager 151 | val manager = OpenUuidManager(context) 152 | 153 | //Try to get the openudid from local preferences 154 | OpenUDID = manager.mPreferences.getString(PREF_KEY, null) 155 | if (OpenUDID == null) //Not found 156 | { 157 | //Get the list of all OpenUDID services available (including itself) 158 | manager.mMatchingIntents = context.packageManager.queryIntentServices(Intent("org.OpenUDID.GETUDID"), 0) 159 | //Log.e(TAG, manager.mMatchingIntents?.size.toString() + " services matches OpenUDID") 160 | if (manager.mMatchingIntents != null) //Start services one by one 161 | manager.startService() 162 | } else { //Got it, you can now call getOpenUDID() 163 | //Log.e(TAG, "OpenUDID: $OpenUDID") 164 | isInitialized = true 165 | } 166 | } 167 | } 168 | 169 | init { 170 | mPreferences = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE) 171 | mContext = context 172 | mRandom = Random() 173 | mReceivedOpenUDIDs = HashMap() 174 | } 175 | } -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = "UniDevIdApp" 2 | include ':app' 3 | include ':lib' 4 | --------------------------------------------------------------------------------