android多渠道打包(动态改变地址打包,只需改下版本号)

多渠道打包本来不想写的,因为比较麻烦,所以没打算写。只是前段时间因为电脑蓝屏重装了系统,导致不能打包了,所以又百度了半天,今天就写下来做个笔记。

废话不多说,进入主题。

配置多渠道打包就要使用友盟统计




build.gradle中添加友盟的依赖包:

//友盟统计
compile 'com.umeng.analytics:analytics:latest.integration'

一、配置AndroidManifest.xml

1、权限(4个权限一定要写,   ps:我这里就不写了,因为我这里4个都是重复的,就做下备注.   大家去友盟里面复制下来贴上)

<!-- 友盟统计权限 这4个权限都是必须添加 ACCESS_NETWORK_STATEACCESS_WIFI_STATEINTERNETREAD_PHONE_STATE -->

2、友盟配置(value 就是你的Appkey)

<!-- 友盟 -->
<!-- 替换为在友盟后台申请的应用Appkey -->
<meta-data
    android:name="UMENG_APPKEY"
    android:value="5aXXX2df29d9821bbXXXXXX"/>
<!-- 应用的推广渠道名称,Channel ID自定义 -->
<meta-data
    android:name="UMENG_CHANNEL"
    android:value="${UMENG_CHANNEL_VALUE}"/>

二、在build.gradle设置productFlavors

记住:渠道包名称不能以数字开头。比如:360的包就不可以, 我在前面加了一个大写C

android{

productFlavors {
        dandanzhuan { dimension "default" } //蛋蛋赚
        yingyongbao { dimension "default" } //腾讯开放平台-应用宝
        huawei { dimension "default" }  //智汇云应用市场-华为
        ppzhushou { dimension "default" } //PP助手
        C360 { dimension "default" }    //360应用市场
        diankai { dimension "default" } //点开广告
        oppo { dimension "default" }    //oppo应用市场
        youmi { dimension "default" }   //有米广告
        xiaomi { dimension "default" }  //小米应用市场
        meizu { dimension "default" }  //魅族应用市场
        xunfei { dimension "default" }  //讯飞更新包
        mumayi { dimension "default" }  //木蚂蚁
        vivo { dimension "default" }  //vivo
    }
    productFlavors.all {
        flavor -> flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE: name]
    }

}

三、配置渠道包的输出路径(jglc是我的项目简称,   _v是版本字母的开头字母。例如jglc_v3.1.0_20180425_release_Releases.apk)

//修改生成的最终文件名
    applicationVariants.all { variant ->
        variant.outputs.all { output ->
            def outputFile = output.outputFile
            if (outputFile != null && outputFile.name.endsWith('.apk')) {
                def fileName
                if (!project.hasProperty('FILE_NAME')) {
                    if (variant.buildType.name == "release") {
                        // 输出apk名称为app_v1.0.0_2015-06-15_playStore.apk  _${variant.productFlavors[0].name}
                        fileName = "jglc_v${defaultConfig.versionName}_${releaseTime()}_${variant.buildType.name}_${variant.productFlavors[0].name}.apk"
                    } else if (variant.buildType.name == "releaselog") {
                        fileName = "jglc_v${defaultConfig.versionName}_${releaseTime()}_${variant.buildType.name}_${variant.productFlavors[0].name}.apk"
                    } else if (variant.buildType.name == "check") {
                        fileName = "jglc_v${defaultConfig.versionName}_${releaseTime()}_${variant.buildType.name}_${variant.productFlavors[0].name}.apk"
                    } else if (variant.buildType.name == "debug") {
                        fileName = "jglc_v${defaultConfig.versionName}_${releaseTime()}_${variant.buildType.name}_${variant.productFlavors[0].name}.apk"
                    } else if (variant.buildType.name == "dev") {
//                        fileName = outputFile.name
                        fileName = "jglc_v${defaultConfig.versionName}_${releaseTime()}_${variant.buildType.name}_${variant.productFlavors[0].name}.apk"
                    }
                } else {
                    fileName = FILE_NAME
                }
                outputFileName = fileName
            }
        }
    }

获取时间代码(位置与android{}同级):

def releaseTime() {
    return new Date().format("yyyyMMdd", TimeZone.getTimeZone("UTC"))
}

接下来我们说下怎么动态获取正式服、开发服、测试服的地址 以及 动态指定版本号版本名

四、在build.gradle里面配置url地址以及版本号、版本名

//默认版本号和版本名
def DEF_VERSION_CODE = 27
def DEF_VERSION_NAME = "3.1.0"

//正式环境
def API_RELEASE_HOST = "\"https://www.XXXXXX.cn\""
//开发环境
def API_DEV_HOST = "\"http://develop.XXXXXX.cn\""
//测试环境
def API_TEST_HOST = "\"http://test.XXXXXX.cn\""
defaultConfig {
    //动态指定版本号版本名
    versionCode project.hasProperty('VERSION_CODE') ? Integer.parseInt(VERSION_CODE) : DEF_VERSION_CODE
    versionName project.hasProperty('VERSION_NAME') ? VERSION_NAME : "${DEF_VERSION_NAME}"
    flavorDimensions "default"
    println("versionCode = " + versionCode + " versionName = " + versionName)
    buildConfigField("String", "API_HOST", "${API_RELEASE_HOST}")
}
buildTypes {
        debug {
            // 显示Log
            buildConfigField "boolean", "LOG_DEBUG", "true"
            buildConfigField "String", "API_HOST", "${API_TEST_HOST}"
            minifyEnabled false
            //签名
            signingConfig signingConfigs.release
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
        release {
            // 不显示Log
            buildConfigField "boolean", "LOG_DEBUG", "false"
            buildConfigField "String", "API_HOST", "${API_RELEASE_HOST}"
            minifyEnabled true //是否混淆
            //是否设置zip对齐优化
            zipAlignEnabled true
            // 移除无用的resource文件
            shrinkResources true
            //签名
            signingConfig signingConfigs.release
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
        /* 正式环境显示log */
        releaselog {
            // 显示Log
            buildConfigField "boolean", "LOG_DEBUG", "true"
            buildConfigField "String", "API_HOST", "${API_RELEASE_HOST}"
            minifyEnabled true //是否混淆
            //是否设置zip对齐优化
            zipAlignEnabled true
            // 移除无用的resource文件
            shrinkResources true
            //签名
            signingConfig signingConfigs.release
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
        /* 开发环境 */
        dev {
            buildConfigField "boolean", "LOG_DEBUG", "true"
            buildConfigField "String", "API_HOST", "${API_DEV_HOST}"
            minifyEnabled false
            //签名
            signingConfig signingConfigs.release
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
        /* 测试环境 */
        check {
            // 显示Log
            buildConfigField "boolean", "LOG_DEBUG", "true"
            buildConfigField "String", "API_HOST", "${API_TEST_HOST}"
            minifyEnabled true //是否混淆
            //是否设置zip对齐优化
            zipAlignEnabled true
            // 移除无用的resource文件
            shrinkResources true
            //签名
            signingConfig signingConfigs.release
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

moudle里面也要配置(如图):



我的build.gradle的配置

apply plugin: 'com.android.application'
apply plugin: 'com.jakewharton.butterknife'

android {
    compileSdkVersion 25
    buildToolsVersion '26.0.2'

    //默认版本号和版本名
    def DEF_VERSION_CODE = 27
    def DEF_VERSION_NAME = "3.1.0"

    useLibrary 'org.apache.http.legacy'

    //正式环境
    def API_RELEASE_HOST = "\"https://www.XXXXX.cn\""
    //开发环境
    def API_DEV_HOST = "\"http://develop.XXXXX.cn\""
    //测试环境
    def API_TEST_HOST = "\"http://test.XXXXX.cn\""

    defaultConfig {
        applicationId "cn.XXXXX.app"
        minSdkVersion 15
        targetSdkVersion 22
        multiDexEnabled true
        //动态指定版本号版本名
        versionCode project.hasProperty('VERSION_CODE') ? Integer.parseInt(VERSION_CODE) : DEF_VERSION_CODE
        versionName project.hasProperty('VERSION_NAME') ? VERSION_NAME : "${DEF_VERSION_NAME}"
        flavorDimensions "default"
        println("versionCode = " + versionCode + " versionName = " + versionName)
        buildConfigField("String", "API_HOST", "${API_RELEASE_HOST}")

        ndk {
            //设置支持的SO库架构
            abiFilters "armeabi", "x86"//, 'armeabi-v7a', 'x86_64', 'arm64-v8a'
        }

        manifestPlaceholders = [
                JPUSH_PKGNAME: applicationId,
                JPUSH_APPKEY : "88d9754a5b3589d6f09a362e", //JPush上注册的包名对应的appkey.
                JPUSH_CHANNEL: "developer-default", //暂时填写默认值即可.
        ]
    }

    signingConfigs {
        release {
            storeFile file(STORE_FILE);
            storePassword STORE_PASSWORD
            keyAlias KEY_ALIAS
            keyPassword KEY_PASSWORD
        }
        debug {
            storeFile file(STORE_FILE);
            storePassword STORE_PASSWORD
            keyAlias KEY_ALIAS
            keyPassword KEY_PASSWORD
        }
    }

    buildTypes {
        debug {
            // 显示Log
            buildConfigField "boolean", "LOG_DEBUG", "true"
            buildConfigField "String", "API_HOST", "${API_TEST_HOST}"
            minifyEnabled false
            //签名
            signingConfig signingConfigs.release
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
        release {
            // 不显示Log
            buildConfigField "boolean", "LOG_DEBUG", "false"
            buildConfigField "String", "API_HOST", "${API_RELEASE_HOST}"
            minifyEnabled true //是否混淆
            //是否设置zip对齐优化
            zipAlignEnabled true
            // 移除无用的resource文件
            shrinkResources true
            //签名
            signingConfig signingConfigs.release
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
        /* 正式环境显示log */
        releaselog {
            // 显示Log
            buildConfigField "boolean", "LOG_DEBUG", "true"
            buildConfigField "String", "API_HOST", "${API_RELEASE_HOST}"
            minifyEnabled true //是否混淆
            //是否设置zip对齐优化
            zipAlignEnabled true
            // 移除无用的resource文件
            shrinkResources true
            //签名
            signingConfig signingConfigs.release
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
        /* 开发环境 */
        dev {
            buildConfigField "boolean", "LOG_DEBUG", "true"
            buildConfigField "String", "API_HOST", "${API_DEV_HOST}"
            minifyEnabled false
            //签名
            signingConfig signingConfigs.release
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
        /* 测试环境 */
        check {
            // 显示Log
            buildConfigField "boolean", "LOG_DEBUG", "true"
            buildConfigField "String", "API_HOST", "${API_TEST_HOST}"
            minifyEnabled true //是否混淆
            //是否设置zip对齐优化
            zipAlignEnabled true
            // 移除无用的resource文件
            shrinkResources true
            //签名
            signingConfig signingConfigs.release
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

    lintOptions {
        disable 'MissingTranslation'
        abortOnError false
    }

    dexOptions {
//        preDexLibraries true
//        javaMaxHeapSize "8g"
//        incremental true
//        dexInProcess = true
    }
    //修改生成的最终文件名
    applicationVariants.all { variant ->
        variant.outputs.all { output ->
            def outputFile = output.outputFile
            if (outputFile != null && outputFile.name.endsWith('.apk')) {
                def fileName
                if (!project.hasProperty('FILE_NAME')) {
                    if (variant.buildType.name == "release") {
                        // 输出apk名称为app_v1.0.0_2015-06-15_playStore.apk  _${variant.productFlavors[0].name}
                        fileName = "jglc_v${defaultConfig.versionName}_${releaseTime()}_${variant.buildType.name}_${variant.productFlavors[0].name}.apk"
                    } else if (variant.buildType.name == "releaselog") {
                        fileName = "jglc_v${defaultConfig.versionName}_${releaseTime()}_${variant.buildType.name}_${variant.productFlavors[0].name}.apk"
                    } else if (variant.buildType.name == "check") {
                        fileName = "jglc_v${defaultConfig.versionName}_${releaseTime()}_${variant.buildType.name}_${variant.productFlavors[0].name}.apk"
                    } else if (variant.buildType.name == "debug") {
                        fileName = "jglc_v${defaultConfig.versionName}_${releaseTime()}_${variant.buildType.name}_${variant.productFlavors[0].name}.apk"
                    } else if (variant.buildType.name == "dev") {
//                        fileName = outputFile.name
                        fileName = "jglc_v${defaultConfig.versionName}_${releaseTime()}_${variant.buildType.name}_${variant.productFlavors[0].name}.apk"
                    }
                } else {
                    fileName = FILE_NAME
                }
                outputFileName = fileName
            }
        }
    }

    //配置多版本的apk
    productFlavors {
        dandanzhuan { dimension "default" } //蛋蛋赚
        yingyongbao { dimension "default" } //腾讯开放平台-应用宝
        huawei { dimension "default" }  //智汇云应用市场-华为
        ppzhushou { dimension "default" } //PP助手
        C360 { dimension "default" }    //360应用市场
        diankai { dimension "default" } //点开广告
        oppo { dimension "default" }    //oppo应用市场
        youmi { dimension "default" }   //有米广告
        xiaomi { dimension "default" }  //小米应用市场
        meizu { dimension "default" }  //魅族应用市场
        xunfei { dimension "default" }  //讯飞更新包
        mumayi { dimension "default" }  //木蚂蚁
        vivo { dimension "default" }  //vivo
    }

    productFlavors.all {
        flavor -> flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE: name]
    }
}

def releaseTime() {
    return new Date().format("yyyyMMdd", TimeZone.getTimeZone("UTC"))
}

repositories {
    flatDir { dirs 'libs' }
    google()
}


dependencies {
    compile fileTree(include: ['*.jar'], dir: 'libs')
    //    compile 'com.mcxiaoke.volley:library:1.0.19'
    compile(name: 'viewpagerindicator-2.4.2', ext: 'aar')
    //    compile 'com.github.navasmdc:MaterialDesign:1.5@aar'

    //    compile 'it.neokree:MaterialNavigationDrawer:1.3.2'

    //    compile 'me.zhanghai.android.materialprogressbar:library:1.1.4'
    compile files('libs/Baofoo_SDK_IDC_V2.0.jar')
    //    compile 'com.tencent.bugly:crashreport_upgrade:latest.release'

    //其中latest.release指代最新版本号,也可以指定明确的版本号,例如1.0.0
    compile files('libs/AutoUpdate_SDK.jar')
    implementation project(':library')
    // 此处以JPush 3.0.0 版本为例。

    // 此处以JCore 1.0.0 版本为例。

    //    compile 'com.github.barteksc:android-pdf-viewer:2.1.0'
    compile files('libs/MobCommons-2017.0608.1618.jar')
    compile files('libs/MobTools-2017.0608.1618.jar')
    compile files('libs/ShareSDK-Core-3.0.0.jar')
    compile files('libs/ShareSDK-QQ-3.0.0.jar')
    compile files('libs/ShareSDK-QZone-3.0.0.jar')
    compile files('libs/ShareSDK-SinaWeibo-3.0.0.jar')
    compile files('libs/ShareSDK-Wechat-3.0.0.jar')
    compile files('libs/ShareSDK-Wechat-Core-3.0.0.jar')
    compile files('libs/ShareSDK-Wechat-Favorite-3.0.0.jar')
    compile files('libs/ShareSDK-Wechat-Moments-3.0.0.jar')
    //其中latest.release指代最新Bugly SDK版本号,也可以指定明确的版本号,例如2.1.9
    compile 'com.android.support:appcompat-v7:23.4.0'
    compile 'com.android.support:design:23.4.0'
    compile 'com.android.support:multidex:1.0.1'
    compile 'de.greenrobot:eventbus:2.4.0'
    compile 'in.srain.cube:ultra-ptr:1.0.11'
    compile 'in.srain.cube:cube-sdk:1.0.45.3.2-SNAPSHOT@aar'
    compile 'in.srain.cube:clog:1.0.2'
    compile 'com.baoyz.swipemenulistview:library:1.3.0'
    compile 'com.bigkoo:pickerview:1.0.3'
    compile 'com.bigkoo:convenientbanner:2.0.5'
    compile 'com.squareup.picasso:picasso:2.5.2'
    compile 'com.zcw:togglebutton-library:1.0.0'
    compile 'com.github.barteksc:android-pdf-viewer:2.7.0-beta'
    compile 'com.android.support:support-v4:25.3.1'
    compile 'cn.jiguang.sdk:jpush:3.0.0'
    compile 'cn.jiguang.sdk:jcore:1.0.0'
    compile 'com.android.support.constraint:constraint-layout:1.0.2'
    compile 'com.android.support:cardview-v7:23.4.0'
    compile 'com.tencent.bugly:crashreport:2.6.5'
    compile 'com.bm.photoview:library:1.4.1'
    compile 'com.android.support:percent:23.4.0'
    //retrofit+rxjava+okhttp
    compile 'com.squareup.retrofit2:retrofit:2.3.0'
    compile 'com.squareup.retrofit2:converter-gson:2.1.0'
    compile 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'
    compile 'com.squareup.okhttp3:okhttp:3.8.0'
    compile 'com.squareup.okhttp3:logging-interceptor:3.8.0'
    compile 'io.reactivex.rxjava2:rxjava:2.1.0'
    compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
    compile 'com.flyco.dialog:FlycoDialog_Lib:1.0.0'
    compile 'com.google.zxing:core:3.3.0'
    compile 'com.github.yidun:captcha-android-demo:2.4'
    //友盟统计
    compile 'com.umeng.analytics:analytics:latest.integration'

    //butterknife
    compile 'com.jakewharton:butterknife:8.4.0'
    annotationProcessor 'com.jakewharton:butterknife-compiler:8.4.0'

    //logger
    compile 'com.orhanobut:logger:2.1.1'
}


然后就是你URL工具类的配置,如下图:

public static final String SERVER_HOST = BuildConfig.API_HOST;


基本已经完成了所有的配置,如下图:


在terminal中使用gradle命令打包的前提就是先配置gradle(2种方法)。

1、在你电脑系统环境变量中配置(我的gradle路径)

新建,变量名:GRADLE_HOME

变量值:D:\Gradle_4.3all\gradle-4.3.1-all\gradle-4.3.1

Path中添加:   %GRADLE_HOME%\bin



第二种配置gradle就是直接在terminal中输入 gradlew回车,自动去下载,很慢的。


配置完成之后:

在terminal中输入命令行 (比如打C360正式服的渠道包):

window系统:gradle assembleC360Release

mac系统:./gradle assembleC360Release

如果没有配置gradle,会提示:'gradle' 不是内部或外部命令,也不是可运行的程序 或批处理文件。


上面的配置完成之后友盟也收不到用户在哪下载的,因为渠道邀请码还没写,友盟怎么能收集到呢,接下来才是重点。

下面就是具体操作用友盟来收集各个渠道的下载量   (渠道邀请码(XXXX)大家去找运营要),工具类:

package com.XXXX.app.base.util;

import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.text.TextUtils;

import com.umeng.analytics.MobclickAgent;

/**
 * Describe: 友盟统计配置初始化
 * Created by ky on 2017/11/13.
 */

public class UmengUtils {
    /**
     * Application中做的初始化
     */
    public static void initUmeng() {
        MobclickAgent.setDebugMode(true);//开启调试模式(如果不开启debug运行不会上传umeng统计)
        MobclickAgent.openActivityDurationTrack(false);
    }

    /**
     * BaseActivityBaseFragmentActivity中的onResume加入
     *
     * @param context
     */
    public static void onResumeToActivity(Context context) {
        MobclickAgent.onPageStart(context.getClass().getName());
        MobclickAgent.onResume(context);
    }

    /**
     * BaseActivityBaseFragmentActivity中的onPause加入
     *
     * @param context
     */
    public static void onPauseToActivity(Context context) {
        MobclickAgent.onPageEnd(context.getClass().getName());
        MobclickAgent.onPause(context);
    }

    /**
     * BaseFragment中的onResume加入
     *
     * @param context
     */
    public static void onResumeToFragment(Context context) {
        MobclickAgent.onPageStart(context.getClass().getName());
    }

    /**
     * BaseFragment中的onPause加入
     *
     * @param context
     */
    public static void onPauseToFragment(Context context) {
        MobclickAgent.onPageEnd(context.getClass().getName());
    }

    /**
     * 获取application中指定的meta-data
     *
     * @return 如果没有获取成功(没有对应值, 或者异常),则返回值为空
     */
    public static String getAppMetaData(Context ctx, String key) {
        if (ctx == null || TextUtils.isEmpty(key)) {
            return null;
        }
        String resultData = null;
        try {
            PackageManager packageManager = ctx.getPackageManager();
            if (packageManager != null) {
                ApplicationInfo applicationInfo = packageManager.getApplicationInfo(ctx.getPackageName(), PackageManager.GET_META_DATA);
                if (applicationInfo != null) {
                    if (applicationInfo.metaData != null) {
                        resultData = applicationInfo.metaData.getString(key);
                    }
                }
            }
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }

        return resultData;
    }

    /**
     * 判断多渠道打包---渠道邀请码(对应的应用市场的代号)
     *
     * @param ctx
     * @param channel
     * @return
     */
    public static String getChannel(Context ctx, String channel) {
        if (ctx == null || TextUtils.isEmpty(channel)) {
            return null;
        }
        String channelValue = null;
        if (!TextUtils.isEmpty(channel)) {
            if ("C360".equals(channel)) {
                channelValue = "XXXX";
            } else if ("diankai".equals(channel)) {
                channelValue = "XXXX";
            } else if ("oppo".equals(channel)) {
                channelValue = "XXXX";
            } else if ("youmi".equals(channel)) {
                channelValue = "XXXX";
            } else if ("xiaomi".equals(channel)) {
                channelValue = "XXXX";
            } else if ("dandanzhuan".equals(channel)) {
                channelValue = "XXXX";
            } else if ("yingyongbao".equals(channel)) {
                channelValue = "";
            } else if ("huawei".equals(channel)) {
                channelValue = "XXXX";
            } else if ("ppzhushou".equals(channel)) {
                channelValue = "";
            } else if ("xunfei".equals(channel)) {
                channelValue = "";
            } else if("mumayi".equals(channel)){
                channelValue = "XXXX";
            } else if("vivo".equals(channel)){
                channelValue = "XXXX";
            }
        }
        return channelValue;
    }
}

具体使用方法(我的项目这里是调用了后台激活渠道的一个接口):

/**
 * 渠道激活信息
 **/
private void getChannelVisit() {
    Map<String, Object> mapData = new HashMap<String, Object>();
    String uuid = UUIDS.getUniqueId(getBaseActivity());
    mapData.put("act", "promotion_activate");
    mapData.put("uuid", uuid);
    mapData.put("terminal", "android");
    String channel = UmengUtils.getAppMetaData(getActivity(), "UMENG_CHANNEL");
    String channelValue = UmengUtils.getChannel(getActivity(), channel);
    if (!TextUtils.isEmpty(channelValue)) {
        mapData.put("appstore_id", channelValue);
    }
    FragmentRequestMode requestMode = new FragmentRequestMode(this);
    requestMode.params = mapData;
    requestMode.tag = REQUEST_KEY_CHANNEL_VISIT;
    Appcontext.verifyCaptcha(requestMode);
}

channelValue就是获取的渠道邀请码,传给后台就可以,不用处理返回的数据

这个接口就是在用户下载下来,启动咱们的app时候会收集他在哪个平台上下载的,友盟会做记录。

里面有个工具类是获取手机唯一标识符,工具如下:

package com.XXXXXX.app.base.util;

import android.content.Context;
import android.os.Build;
import android.provider.Settings;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/**
 * Android唯一标识生成方案
 * Created by ky on 2017/11/13.
 */
public class UUIDS {
    /**AndroidId Serial Number*/
    public static String getUniqueId(Context context){
        String androidID = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);
        String id = androidID + Build.SERIAL;
        try {
            return id;
        } catch (Exception e) {
            e.printStackTrace();
            return id;
        }
    }
    /**唯一标识 加密使用*/
    private static String toMD5(String text) throws NoSuchAlgorithmException {
        //获取摘要器 MessageDigest
        MessageDigest messageDigest = MessageDigest.getInstance("MD5");
        //通过摘要器对字符串的二进制字节数组进行hash计算
        byte[] digest = messageDigest.digest(text.getBytes());

        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < digest.length; i++) {
            //循环每个字符 将计算结果转化为正整数;
            int digestInt = digest[i] & 0xff;
            //10进制转化为较短的16进制
            String hexString = Integer.toHexString(digestInt);
            //转化结果如果是个位数会省略0,因此判断并补0
            if (hexString.length() < 2) {
                sb.append(0);
            }
            //将循环结果添加到缓冲区
            sb.append(hexString);
        }
        //返回整个结果
        return sb.toString();
    }

}


终于完成了,  这还是去年配置的,都是拼记忆写的。要不是因为电脑蓝屏,配置没了,我都不愿意写。

如果有错误,联系我我会查找原因,我是去年写的,有漏洞请指出。

运行下:



  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值