简介

如题所示!本篇文章就是为了解决这种问题。方便打包和运行的时候能做到无需手动替换配置,即可打包想要的apk。打包的时候,只需选一下想打哪种配置的apk就OK啦。 (^o^)/~

先来看,有需求如下:

  1. 同一个项目
  2. 不同的apk图标
  3. 不同的服务器域名
  4. 不同的包名
  5. 不同的名称
  6. 不同的签名
  7. 不同的第三方key
  8. 不同的版本名版本号

解决思路

  1. 当然最直接的方式不过于每次打不同包的时候都去替换对应的配置,这种方式的麻烦之处不言而喻。
  2. 将所有配置,资源等都配置入项目中,打包的时候,根据选择渠道打包不同配置的apk。(本篇文章就是要讲怎么这么做的)
  3. 相信还有其他的。。。

相关的几个要点

  1. 首先我们需要知道productFlavors来配置渠道,这里我将渠道用来表示哪种apk,如下我需要配置四种应用:

    productFlavors {
    userquhua {}
    quhua {}
    cuntuba {}
    xemh {}
    }
  2. 如果我们选择了某一个渠道,那么运行打包的时候会根据渠道名选择资源文件(可结合第6点一起看)

  3. 签名可在signingConfigs中配置多个(我将所有签名文件放在了项目跟目录的key文件夹中),这样我们就可以通过signingConfigs指定预制好的签名配置。

    signingConfigs {    userquhuaRelease {        storeFile file("../key/xxx1.keystore")        storePassword "xxxxxx"        keyAlias "alias"        keyPassword "xxxxxx"    }
    
        quhuaRelease {        storeFile file("../key/xxx2.keystore")        storePassword "xxxxxx"        keyAlias "alias"        keyPassword "xxxxxx"    }
    
        cuntubaRelease {        storeFile file("../key/xxx3.keystore")        storePassword "xxxxxx"        keyAlias "alias"        keyPassword "xxxxxx"    }
    
        xemhRelease {        storeFile file("../key/xxx4.keystore")        storePassword "xxxxxx"        keyAlias "alias"        keyPassword "xxxxxx"    }}
  4. 可在build.gradle中配置动态配置java代码调用的常量数据(如:通过该方式我们可根据不同渠道动态配置第三方appid,或其他需要根据渠道而改变的数据)

    • 比如:我们在defaultConfig {} 中定义了:

      buildConfigField "String", "SERVER_URL", '"http://xx.xxxx.com/"'
    • 此时,您看一下清单文件中manifest标签里的,package的值,假如是:

      com.xxx.xx
    • 那么,您就可以在java代码中通过导入文件:

      import com.xxx.xx.BuildConfig;
    • 然后调用

      BuildConfig.SERVER_URL

    它的值就是上边配置的字符串:http://xx.xxxx.com/

    • 您可以进入BuildConfig看一看,里面还包含了一些当前的包名版本号等信息。
  5. 在渠道配置那里可以配置对应的包名版本名签名等等
    如下所示:

    // 省略其他配置...android {  // 省略其他配置...  productFlavors {      userquhua {          applicationId "com.xxx.xx"          versionCode 1          versionName "1.0.0"          signingConfig signingConfigs.userquhuaRelease // 配置签名
    
              String qq_id = '"xxxxxxxxx"' //配置qq appid          buildConfigField "String",           "QQ_ID", qq_id          buildConfigField "String",           "WX_ID", '"wxxxxxxxxxxxxxxxxx"' // 配置微信appid          manifestPlaceholders = [            qq_id: qq_id,            JPUSH_PKGNAME : applicationId,            JPUSH_APPKEY : "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx", //JPush 上注册的包名对应的 Appkey.            JPUSH_CHANNEL : "developer-default",          ]      }  }
    
      buildTypes {    release {      // 省略其他配置...        signingConfig null  // 置空    }
    
        debug {      // 省略其他配置...        signingConfig null // 置空    }  }}
    • 这样,如果我们打包userquhua这个渠道,看第2点中介绍选择userquhuaDebug。
    • 然后,最好clean一下项目、然后我们运行项目。
    • 该app的包名就是com.xxx.xx,版本号为1,版本名为1.0.0
    • 通过BuildConfig调用QQ_ID静态常量,就是该渠道里配置的值,WX_ID同理。
    • manifestPlaceholders配置也可以这样配置。
    • 签名问题经过个人反复尝试(然后半天就过去了 ̄へ ̄),最终签名如上配置。需要注意buildTypes中的签名配置signingConfig如果不设置为null,那么打包的是有还是以内置的签名打包。
  6. 资源文件替换
    再看到第2点的介绍,我们选择运行渠道后,会默认匹配对应渠道下的资源。下面我将xemh渠道的资源目录全部展开一下。

    • 如上图这样,只需要资源名字和app目录对应的文件名字一样即可替换。
    • strings.xml里的应用名,只需要将对应app_name修改既可替换app下strings的app_name,其他不用替换的不用写就行。
  7. 打正式包的时候选好渠道,就可以打包不同配置的apk,当然您也可以使用命令的方式。

其他配置记录

获取当前时间

static def releaseTime() {    return new Date().format("yyyy-MM-dd-HH.mm", TimeZone.getTimeZone("GMT+8"))}

打包的时候,修改文件名,以方便区别渠道和版本打包时间

applicationVariants.all {
variant ->
variant.outputs.all {
outputFileName = "${variant.productFlavors[0].name}-v${variant.productFlavors[0].versionName}-${releaseTime()}.apk"
}
}
  • ${variant.productFlavors[0].name}当前渠道名
  • ${variant.productFlavors[0].versionName}当前版本名
  • ${releaseTime()}当前时间

其他需要注意事项

如果您在清单文件AndroidManifest.xml中,有那种以包名开头命名的那种。因为如果包名都改了,有些也需要动态的改变。可以用${applicationId}代替。在打包的时候,会自动替换成当前包名。

比如,类似下配置:

<permission    android:name="com.xxx.xx.permission.JPUSH_MESSAGE"    android:protectionLevel="signature" /><uses-permission android:name="com.xxx.xx.permission.JPUSH_MESSAGE" /><receiver    android:name=".push.MyJPushMessageReceiver"    android:enabled="true"    android:exported="false" >    <intent-filter>        <action android:name="cn.jpush.android.intent.RECEIVE_MESSAGE" />        <category android:name="com.xxx.xx" />    </intent-filter></receiver><provider    android:name="android.support.v4.content.FileProvider"    android:authorities="com.xxx.xx.provider"    android:exported="false"    tools:replace="android:authorities"    android:grantUriPermissions="true">    <meta-data        android:name="android.support.FILE_PROVIDER_PATHS"        android:resource="@xml/file_paths" /></provider>

可改为:

<permission    android:name="${applicationId}.permission.JPUSH_MESSAGE"    android:protectionLevel="signature" /><uses-permission android:name="${applicationId}.permission.JPUSH_MESSAGE" /><receiver    android:name=".push.MyJPushMessageReceiver"    android:enabled="true"    android:exported="false" >    <intent-filter>        <action android:name="cn.jpush.android.intent.RECEIVE_MESSAGE" />        <category android:name="${applicationId}" />    </intent-filter></receiver><provider    android:name="android.support.v4.content.FileProvider"    android:authorities="${applicationId}.provider"    android:exported="false"    tools:replace="android:authorities"    android:grantUriPermissions="true">    <meta-data        android:name="android.support.FILE_PROVIDER_PATHS"        android:resource="@xml/file_paths" /></provider>

当然值得注意的是,在代码中我们也不能把包名写死了,可通过BuildConfig得到当前包名

我的完整配置,供参考

有关隐私信息的都用xxx替换了

  1. 项目根目录的build.gradle

    // Top-level build file where you can add configuration options common to all sub-projects/modules.
    
    buildscript {
    
        repositories {        google()        jcenter()    }    dependencies {        classpath 'com.android.tools.build:gradle:3.0.0'        classpath "io.github.prototypez:save-state:0.1.7"
    
            // NOTE: Do not place your application dependencies here; they belong        // in the individual module build.gradle files    }}
    
    allprojects {    repositories {        google()        jcenter()        maven { url "https://jitpack.io" }        maven { url 'http://oss.jfrog.org/artifactory/oss-snapshot-local/' }        flatDir {            dirs 'libs'        }    }}
    
    task clean(type: Delete) {    delete rootProject.buildDir}
    
    ext{    minSdkVersion               = 16    targetSdkVersion            = 27    compileSdkVersion           = 27    buildToolsVersion           = '27.1.1'
    
        supportLibraryVersion       = '27.1.1'    xmvpVersion                 = '1.2.2'    retrofit2Version            = '2.3.0'    okhttp3Version              = '3.8.1'    butterknifeVersion          = '8.6.0'    rx2Version                  = '2.0.2'    CircleProgressDialogVersion = '1.0.2'    smarttabVersion             = '1.6.1@aar'    adapterHelperVersion        = '2.9.41'    glideVersion                = '4.7.1'    roundedimageviewVersion     = '2.3.0'    eventbusVersion             = '3.0.0'    dispatcherVersion           = '2.4.0'    picture_libraryVersion      = 'v2.2.3'    statusbarutilVersion        = '1.5.1'    okhttpUtilsVersion          = '3.8.0'    constraintVersion           = '1.1.3'    flexboxVersion              = '1.0.0'}
  2. app目录下的build.gradle

    apply plugin: 'com.android.application'apply plugin: 'save.state'
    
    static def releaseTime() {    return new Date().format("yyyy-MM-dd-HH.mm", TimeZone.getTimeZone("GMT+8"))}
    
    android {    compileSdkVersion rootProject.compileSdkVersion//    buildToolsVersion rootProject.buildToolsVersion    defaultConfig {        minSdkVersion rootProject.minSdkVersion        targetSdkVersion rootProject.targetSdkVersion
    
            testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"        multiDexEnabled true        // config the JSON processing library        javaCompileOptions {            annotationProcessorOptions {                arguments = [ serializer : "gson" ]            }        }
    
            ndk {            abiFilters "armeabi-v7a"        }        renderscriptTargetApi 25        renderscriptSupportModeEnabled true
    
        }    signingConfigs {        userquhuaRelease {            storeFile file("../key/xxx.keystore")            storePassword "xxxxxx"            keyAlias "xxx"            keyPassword "xxxxxx"        }
    
            quhuaRelease {            storeFile file("../key/xxx.keystore")            storePassword "xxxxxxx"            keyAlias "xxx"            keyPassword "xxxxxxx"        }
    
            cuntubaRelease {            storeFile file("../key/xxx.keystore")            storePassword "xxxxxxx"            keyAlias "xxx"            keyPassword "xxxxxxx"        }
    
            xemhRelease {            storeFile file("../key/xxx.keystore")            storePassword "xxxxxxx"            keyAlias "xxx"            keyPassword "xxxxxxx"        }    }    flavorDimensions "default"    productFlavors {        userquhua {            applicationId "com.xxx.xx"            versionCode 22            versionName "1.7.5"            signingConfig = signingConfigs.userquhuaRelease
    
                String qq_id = '"xxxxxx"'            buildConfigField "String",           "QQ_ID", qq_id // qq appId            buildConfigField "String",         "SINA_ID", '"xxxxxx"' // 新浪appId            buildConfigField "String",           "WX_ID", '"xxxxxx"' // 微信 appId            buildConfigField "String",           "UM_ID", '"xxxxxx"' // 友盟            buildConfigField "String",       "WX_SECRET", '"xxxxxx"' // 微信 secret            buildConfigField "String",   "SINA_REDIRECT", '"http://open.weibo.com/apps/xxxxxx/privilege/oauth"' // 新浪
    
                buildConfigField "String",   "ADHUB_INIT_ID", '"xxxxxx"' // 广告sdk初始化id            buildConfigField "String", "ADHUB_SPLASH_ID", '"xxxxxx"' // 开屏广告id            buildConfigField "String", "ADHUB_BANNER_ID", '"xxxxxx"' // banner广告id
    
                buildConfigField "String",      "SERVER_URL", '"http://xxx.xxx.com/"'            buildConfigField "String",        "LOGO_URL", '"http://file.xxx.com/img/xxx.png"'
    
                manifestPlaceholders = [                    qq_id: qq_id,                    JPUSH_PKGNAME : applicationId,                    JPUSH_APPKEY : "xxxxxx", //JPush 上注册的包名对应的 Appkey.                    JPUSH_CHANNEL : "developer-default", //暂时填写默认值即可.            ]        }
    
            quhua {            applicationId "com.xxx.xx"            versionCode 1            versionName "1.0.0"            signingConfig = signingConfigs.quhuaRelease
    
                String qq_id = '"xxxxxx"'            buildConfigField "String",           "QQ_ID", qq_id            buildConfigField "String",         "SINA_ID", '"xxxxxx"'            buildConfigField "String",           "WX_ID", '"xxxxxx"'            buildConfigField "String",           "UM_ID", '"xxxxxx"'            buildConfigField "String",       "WX_SECRET", '"xxxxxx"'            buildConfigField "String",   "SINA_REDIRECT", '"http://open.weibo.com/apps/xxxxxx/privilege/oauth"'
    
                buildConfigField "String",   "ADHUB_INIT_ID", '"xxxxxx"' // 广告sdk初始化id            buildConfigField "String", "ADHUB_SPLASH_ID", '"xxxxxx"' // 开屏广告id            buildConfigField "String", "ADHUB_BANNER_ID", '"xxxxxx"' // banner广告id
    
                buildConfigField "String",      "SERVER_URL", '"http://xx.xxx.com/"'            buildConfigField "String",        "LOGO_URL", '"http://file.xxx.com/img/xxx.png"'
    
                manifestPlaceholders = [                    qq_id: qq_id,                    JPUSH_PKGNAME : applicationId,                    JPUSH_APPKEY : "xxxxxx", //JPush 上注册的包名对应的 Appkey.                    JPUSH_CHANNEL : "developer-default", //暂时填写默认值即可.            ]        }
    
            cuntuba {            applicationId "com.xxx.xx"            versionCode 1            versionName "1.0.0"            signingConfig = signingConfigs.cuntubaRelease
    
                String qq_id = '"xxxxxx"'            buildConfigField "String",           "QQ_ID", qq_id            buildConfigField "String",         "SINA_ID", '"xxxxxx"'            buildConfigField "String",           "WX_ID", '"xxxxxx"'            buildConfigField "String",           "UM_ID", '"xxxxxx"'            buildConfigField "String",       "WX_SECRET", '"xxxxxx"'            buildConfigField "String",   "SINA_REDIRECT", '"http://open.weibo.com/apps/xxxxxx/privilege/oauth"'
    
                buildConfigField "String",   "ADHUB_INIT_ID", '"xxxxxx"' // 广告sdk初始化id            buildConfigField "String", "ADHUB_SPLASH_ID", '"xxxxxx"' // 开屏广告id            buildConfigField "String", "ADHUB_BANNER_ID", '"xxxxxx"' // banner广告id
    
                buildConfigField "String",      "SERVER_URL", '"http://xxx.xxxx.com/"'            buildConfigField "String",        "LOGO_URL", '"http://file.xxx.com/img/xxx.png"'
    
                manifestPlaceholders = [                    qq_id: qq_id,                    JPUSH_PKGNAME : applicationId,                    JPUSH_APPKEY : "xxxxxx", //JPush 上注册的包名对应的 Appkey.                    JPUSH_CHANNEL : "developer-default", //暂时填写默认值即可.            ]        }
    
            xemh {            applicationId "com.xxx.xx"            versionCode 1            versionName "1.0.0"            signingConfig = signingConfigs.xemhRelease
    
                String qq_id = '"xxxxxx"'            buildConfigField "String",           "QQ_ID", qq_id            buildConfigField "String",         "SINA_ID", '"xxxxxx"'            buildConfigField "String",           "WX_ID", '"xxxxxx"'            buildConfigField "String",           "UM_ID", '"xxxxxx"'            buildConfigField "String",       "WX_SECRET", '"xxxxxx"'            buildConfigField "String",   "SINA_REDIRECT", '"xxxxxx"'
    
                buildConfigField "String",   "ADHUB_INIT_ID", '"xxxxxx"' // 广告sdk初始化id            buildConfigField "String", "ADHUB_SPLASH_ID", '"xxxxxx"' // 开屏广告id            buildConfigField "String", "ADHUB_BANNER_ID", '"xxxxxx"' // banner广告id
    
                buildConfigField "String",      "SERVER_URL", '"http://xx.xxx.com/"'            buildConfigField "String",        "LOGO_URL", '"http://file.xxxxxx.com/img/xxxxxx.png"'
    
                manifestPlaceholders = [                    qq_id: qq_id,                    JPUSH_PKGNAME : applicationId,                    JPUSH_APPKEY : "xxxxxx", //JPush 上注册的包名对应的 Appkey.                    JPUSH_CHANNEL : "developer-default", //暂时填写默认值即可.            ]        }    }
    
        applicationVariants.all {        variant ->            variant.outputs.all {                outputFileName = "${variant.productFlavors[0].name}-v${variant.productFlavors[0].versionName}-${releaseTime()}.apk"            }    }
    
        buildTypes {        release {            // 不显示Log            buildConfigField "boolean", "LOG_DEBUG", "false"            signingConfig null            minifyEnabled true            zipAlignEnabled true            // 移除无用的resource文件            shrinkResources true            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'        }
    
            debug {            // 显示Log            buildConfigField "boolean", "LOG_DEBUG", "true"            signingConfig null            minifyEnabled false            zipAlignEnabled false            shrinkResources false        }    }    packagingOptions {        exclude 'META-INF/DEPENDENCIES.txt'        exclude 'META-INF/NOTICE'        exclude 'META-INF/NOTICE.txt'        exclude 'META-INF/LICENSE'        exclude 'META-INF/LICENSE.txt'    }    compileOptions {        targetCompatibility JavaVersion.VERSION_1_8        sourceCompatibility JavaVersion.VERSION_1_8    }
    
        dexOptions {
    
            javaMaxHeapSize "4g" //此处可根据电脑本身配置 数值越大 当然越快
    
            preDexLibraries = false
    
        }}
    
    repositories {    flatDir {        dirs 'libs', '../adpoymer/libs'    }}
    
    dependencies {    implementation fileTree(include: ['*.jar'], dir: 'libs')    implementation "com.android.support:appcompat-v7:$supportLibraryVersion"    implementation "com.android.support:recyclerview-v7:$supportLibraryVersion"    implementation "com.android.support:support-v4:$supportLibraryVersion"    implementation "com.android.support:design:$supportLibraryVersion"    implementation "com.android.support.constraint:constraint-layout:$constraintVersion"
    
        //添加retrofit2 的依赖 添加这个依赖就默认添加了okhttp依赖    compile "com.squareup.retrofit2:retrofit:$retrofit2Version"    compile "com.squareup.retrofit2:converter-gson:$retrofit2Version"    compile "com.squareup.retrofit2:adapter-rxjava2:$retrofit2Version"    compile "com.squareup.okhttp3:logging-interceptor:$okhttp3Version"    compile "com.jakewharton:butterknife:$butterknifeVersion"    annotationProcessor "com.jakewharton:butterknife-compiler:$butterknifeVersion"    compile "io.reactivex.rxjava2:rxandroid:$rx2Version"    compile "com.github.xujiaji:xmvp:$xmvpVersion"    implementation "com.github.autume:CircleProgressDialog:$CircleProgressDialogVersion"    compile "com.ogaclejapan.smarttablayout:library:$smarttabVersion"    compile "com.github.CymChad:BaseRecyclerViewAdapterHelper:$adapterHelperVersion"
    
        compile "com.github.bumptech.glide:glide:$glideVersion"    annotationProcessor "com.github.bumptech.glide:compiler:$glideVersion"
    
        compile "com.makeramen:roundedimageview:$roundedimageviewVersion"    compile "org.greenrobot:eventbus:$eventbusVersion"    annotationProcessor "com.github.hotchemi:permissionsdispatcher-processor:$dispatcherVersion"    compile "com.jaeger.statusbarutil:library:$statusbarutilVersion"    compile("com.github.hotchemi:permissionsdispatcher:$dispatcherVersion") {        exclude module: "support-v13"    }    implementation "com.github.LuckSiege.PictureSelector:picture_library:$picture_libraryVersion"    implementation 'me.drakeet.library:crashwoodpecker:2.1.1'    implementation 'com.github.chenupt.android:springindicator:1.0.2@aar'    debugImplementation 'com.amitshekhar.android:debug-db:1.0.4'    implementation 'com.umeng.sdk:common:1.5.3'    implementation 'com.umeng.sdk:analytics:7.5.3'
    
        implementation 'com.liulishuo.filedownloader:library:1.7.5'
    
        implementation project(':banner')    implementation project(':xdialog')    implementation project(':shareutil')    implementation project(':update')    implementation project(':pay')//    implementation project(':adhub')    implementation project(':imagewatcher')    implementation files('libs/lite-orm-1.9.2.jar')    implementation 'jp.wasabeef:blurry:2.1.1'    implementation "com.google.android:flexbox:$flexboxVersion"
    
        implementation 'cn.jiguang.sdk:jpush:3.1.6'  // 此处以JPush 3.1.6 版本为例。    implementation 'cn.jiguang.sdk:jcore:1.2.5'  // 此处以JCore 1.2.5 版本为例。
    
        compile(name: 'sdk-release', ext: 'aar')    compile(name: 'open_ad_sdk', ext: 'aar')    compile(name: 'adpoymer-3.4.35', ext: 'aar')    implementation 'pl.droidsonroids.gif:android-gif-drawable:1.0.+'}

Demo 地址

https://github.com/xujiaji/OneForAllApk

结束

就这样就可以解放大量劳动力啦!每次项目打包各种软件,选一下就ojbk,哈哈哈~
如果有些配置在其他渠道没有的,也可通过BuildConfig在java中判断如果是某某渠道那么屏蔽。
over

一个项目如何编译多个不同签名,包名,资源等相关推荐

  1. 一个项目如何编译多个不同签名、包名、资源等,的apk?

    简介 如题所示!本篇文章就是为了解决这种问题.方便打包和运行的时候能做到无需手动替换配置,即可打包想要的apk.打包的时候,只需选一下想打哪种配置的apk就OK啦. (^o^)/~ 先来看,有需求如下 ...

  2. android 多包名apk,一个项目如何编译多个不同签名、包名、资源等,的apk?

    4 其他需要注意的事项 如果您在清单文件AndroidManifest.xml中,有那种以包名开头命名的那种.因为如果包名都改了,有些也需要动态的改变.可以用${applicationId}代替.在打 ...

  3. Eric6最简单的应用(创建一个项目-窗体-编译-运行)

    1.创建项目 2.创建一个窗体 自动弹出Qt designer 工具,可视化窗体界面: 创建一个关闭按钮,关闭这个窗体: 保存后,选择ui文件,进行编译ui文件: 然后执行该脚本,即可: 以上是eri ...

  4. 微信申请 包名和签名

    开发环境: window 7 Egret Engine 5.0.14 Egret support 5.0.12 Eclipse 一  申请微信移动应用 二  怎么获取Android包名 三  怎么获取 ...

  5. Android Studio 修改项目包名(最后一级)

    背景: 如果新做的项目跟以前做的某一个项目十分相似,那么一个简单的方法就是把原来项目拷贝一份,然后修改代码,但是这样包名还是原来项目的包名,还有如果想在同一台手机上同时安装新做的app和原来的app会 ...

  6. 个人或团队项目怎么起包名

    转载文章 出处http://www.lxway.com/9904091.htm 在java开发的过程中,每名Java开发人员都可以编写属于自己的java package,为了在编写中保证每一个java ...

  7. (已更新)价值8000元APP封装系统 自动实现5分钟随机更换包名和签名

    PS 本源码提供给大家学习研究借鉴美工之用,请勿用于商业和非法用途,无任何技术支持! 某站8000元APP封装系统源码app误报毒app可上传+自动实现5分钟随机更换包名和签名+视频安装教程; 程序可 ...

  8. 解决APP误报毒 可打包APP可上传APK 自动实现5分钟随机更换包名和签名系统源码

    简介: 解决app误报毒 可打包APP可上传APK 自动实现5分钟随机更换包名和签名系统源码 本程序功能介绍: 程序可实现域名自动打包成app 出现误报毒并自动更换包名和签名(*时间一次) 也可以上传 ...

  9. nixyx —— 一个小巧的项目工程/编译文件生成器(构建系统?)

    恩..nixyx确实算不上是一个构建系统. 所谓构建系统,比如GNU的Autotools,那是一套很完整的构建体系,包括了程序的配置,编译和安装三大部分. 类似的软件还有:google的gyp.腾讯的 ...

最新文章

  1. 摊牌了!国内首个基于结构光投影三维重建系列视频课程
  2. html5画布显示不出来,运行后html5画布没出来
  3. RocEDU.课程设计2018 第二周进展 博客补交
  4. Eclipse(javaweb)刚换工作空间之后,应该做哪几件事
  5. matlab4.0,matlab 4.0
  6. Spring构建微服务
  7. 【Matlab学习笔记】保存图片(待续)
  8. IDEA统计代码行数
  9. 使用matplotlib动态打印图片(RGB图片)
  10. 【学习随记】Word域代码相关
  11. 微信小程序中slider实现拾色器功能
  12. android studio partially installed,APK安装流程详解2——PackageManager简介
  13. 虚拟化、文件系统、查找文件
  14. 18 在springboot整合thymeleaf模板引擎中@Controller和@RestController不同注解的跳转页面方法
  15. BlackHoleDAO能否点燃DeFi3.0用户激情
  16. object-c中的对象的释放
  17. 如何将带Dxperience组件的Asp.net 2.0网站部署到服务器(转载)
  18. 关于kali连不上网络
  19. 显示器接口_电脑显示器接口类型哪个好?VGA、DVI、HDMI、DP接口区别对比科普
  20. linux 命令的英文缩写含义----文件夹英文缩写的含义

热门文章

  1. Python脚本一键找出哪些微信好友删了你(附源码)
  2. 计算机网络是如何通信的「三」DNS
  3. 7月7日易用性SIG技术分享活动精彩回顾
  4. 自媒体人如何搜集写作素材?建立自己的素材库
  5. 11月21至28号总结
  6. 618这款秒杀神器Python介绍给你,低调使用哦,因为太赞了
  7. 计算1+3+5+....+99的和
  8. android 9.0音量键功能开关(屏蔽音量加减功能)
  9. WIN10 启动后花屏
  10. 致远A8-m协同管理系统