2019-07-02 16:48:57 qq_32081725 阅读数 432
  • 快速入门Android开发 视频 教程 android studio

    这是一门快速入门Android开发课程,顾名思义是让大家能快速入门Android开发。 学完能让你学会如下知识点: Android的发展历程 搭建Java开发环境 搭建Android开发环境 Android Studio基础使用方法 Android Studio创建项目 项目运行到模拟器 项目运行到真实手机 Android中常用控件 排查开发中的错误 Android中请求网络 常用Android开发命令 快速入门Gradle构建系统 项目实战:看美图 常用Android Studio使用技巧 项目签名打包 如何上架市场

    19571 人正在学习 去看看 任苹蜻

修改app下的build.gradle文件

在最上方定义版本号信息

def app_version_code = 9
def app_version_name = '1.9.7'

引用变量配置

defaultConfig {
        applicationId "com.ice.demo"
        minSdkVersion 18
        targetSdkVersion 28
        versionCode app_version_code //版本code
        versionName app_version_name  //版本name
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }

配置打包,在android节点下增加如下代码

android.applicationVariants.all {
        variant ->
            variant.outputs.all {
                outputFileName = "app-release${app_version_name}.apk"
            }
    }

配置完成,打包测试

2018-09-10 14:33:22 halo1416 阅读数 788
  • 快速入门Android开发 视频 教程 android studio

    这是一门快速入门Android开发课程,顾名思义是让大家能快速入门Android开发。 学完能让你学会如下知识点: Android的发展历程 搭建Java开发环境 搭建Android开发环境 Android Studio基础使用方法 Android Studio创建项目 项目运行到模拟器 项目运行到真实手机 Android中常用控件 排查开发中的错误 Android中请求网络 常用Android开发命令 快速入门Gradle构建系统 项目实战:看美图 常用Android Studio使用技巧 项目签名打包 如何上架市场

    19571 人正在学习 去看看 任苹蜻

失败前:

1. gradle版本:

2. 签名设置

 

报错:

我一直以为是静态资源的问题,和同事两个人找了半天,结果并不是......

 

解决:

1. 修改gradle版本

===>> 这样之后可以打包,不会报错了!!但是,app会闪退!

闪退原因:react-native-modal-picker这个库里面 propTypes 的  View.propTypes.style造成的;react升级以后,View.propTypes.style这个属性已经弃用,但是这个库里面还未修改,去除即可(propTypes去除不会有太大的影响)

react-native-modal-picker 的 index.js:

好了,app可以正常运行了!

 

文章仅为本人学习过程的一个记录,仅供参考,如有问题,欢迎指出

 

2017-04-01 15:16:09 aiynmimi 阅读数 11950
  • 快速入门Android开发 视频 教程 android studio

    这是一门快速入门Android开发课程,顾名思义是让大家能快速入门Android开发。 学完能让你学会如下知识点: Android的发展历程 搭建Java开发环境 搭建Android开发环境 Android Studio基础使用方法 Android Studio创建项目 项目运行到模拟器 项目运行到真实手机 Android中常用控件 排查开发中的错误 Android中请求网络 常用Android开发命令 快速入门Gradle构建系统 项目实战:看美图 常用Android Studio使用技巧 项目签名打包 如何上架市场

    19571 人正在学习 去看看 任苹蜻

前言

在之前写过Android 多渠道打包的文章,可以发布不同APP商店的版本。有时候,我们也会遇到这样的需求,就是应用可能有一个测试版,线上版本等不同版本,可能不同的版本的一些配置信息不同,比如服务器地址,应用名称,图标等,如果我们在每安装一个版本的时候,都去代码里边更改这些值的话,就会显得很繁琐,而且效率很低。下边就说一下如何利用Gradle高效的实现这一需求!

多版本打包

首先,我们要对app的build.gradle这个文件有一个比较全面的了解,知道其中目录的意义,对于其中的语法呢,知道个大概就行了。
对于Gradle的相关知识,可以参考深入理解Android之Gradle

对于build.gradle目录中的各个内容,这里不再赘述,不是本篇文章的内容,具体可以参考:详解build.gradle

①配置
首先在app的build.gradle的android标签中添加:

//配置多版本的apk  
productFlavors{  
	Offline{  
		applicationId "com.xxxx.xxxx.beta"  
		manifestPlaceholders = [app_name:"xxxx" ,icon: "@mipmap/ic_launcher_xxxx"]  
		resValue("string" , "baseUrl","xxxxxxx")  
	}  
	Online{  
		applicationId "com.xxxx.xxxx.online"  
		manifestPlaceholders = [app_name:"xxxx" ,icon: "@mipmap/ic_launcher_xxxx"]  
		resValue("string" , "baseUrl","xxxxxxx") 
	}  

需要注意的几个问题:

  1. 上边分了两个版本offline和online,其中applicationId 表示这个版本apk的包名,如果没有写这一项,则默认是defaultConfig {}标签下的包名。
  2. manifestPlaceholders=[]这项是配置应用的名称或者图标,如果设置了这一项,需要在AndroidManifese.xml的application标签下配置android:label="${app_name}" android:icon="${icon}"
  3. resValue可以配置一些我们需要的不同的值,第一个参数是变量的类型,第二个参数key,第三个参数是变量的value。具体的使用
    value=context.getResources().getString(R.string.key)
    还有就是在代码中使用的时候,我们要把build.gradle先sync同步一下,要不然会报错找不到这个key。

打包

方法一:

直接在AS的Terminal终端输入命令:./gradlew assemble,之后回车,然后所有的包就打包好了!

方法二:

在AS右侧,点击打开Gradle,依次打开项目名/Tasks/builid/xxxx,我们就会发现会有好多打包项可以选择,需要哪种的就选择哪种就可以了!
这里写图片描述

方法三:

在AS工具栏,选择build---->select build variant...,会弹出下边的内容:
这里写图片描述
之后,选择一个就可以了!当然了,这里选择一个之后,我们如果要在手机上运行,点击三角运行的时候,安装的版本就是这里选择的版本了!

好了,对版本的打包就先介绍到这里了!

如果还想了解更多的打包的文章,比如多平台的打包等,可以参考下边一个系列的文章,写的很清楚!
android studio gradle 多版本多apk打包(打包系列教程之五)

修改生成的APK名称

默认生成的apk名字是app-debug.apk,app-release.apk,如果我们配置了上边的版本,生成的是app-offline-debug.apk等。那么如果我们想要生成的apk中加上版本号,或者当前的时间等信息,该如何生成呢?

以上边为例,我想要offline的版本加上版本号和当前日期,格式为app_offline_debug_v1.0-20170419.apk这样的格式!

首先我们需要在build.gradle根目录,定义得到当前日期的函数:

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

然后在build.gradle中android{}标签下,添加:

//在apk文件后边生成版本号信息
android.applicationVariants.all {
	variant ->
		variant.outputs.each {
		output -> output.outputFile = new File(output.outputFile.parent, "app_" + productFlavors[0].name + "_" + buildType.name + "_v" + defaultConfig.versionName + "-${releaseTime()}.apk");
		}
}

output.outputFile.parent表示生成apk的路径,这个是默认路径在项目/app/build/outpus/apk,当然我们可以自己写路径。
productFlavors[0].name表示productFlavors标签下的名称,这里就是offline或者online。
buildType.name指编译类型,就是debug或者release
defaultConfig.versionName表示在defaultConfig标签下写的版本号
releaseTime()表示我们定义的得到日期的函数

另外上边,我们可以全部用字符串进行拼接,也可以像${releaseTime()}一样定义为变量,效果是一样的!

2019.4.3更新
在下边评论中vhgcc同学指出,上述修改生成apk名称在AS3.0之后已经有所变化,确实是这样的!这里简单说一下!

详情可以参考官方文档迁移到 Android Plugin for Gradle 3.0.0

比如上边的代码在3.0中主要的改动在于修改 each()outputFile()方法为all()outputFileName

android.applicationVariants.all {
	variant ->
		variant.outputs.all {
		outputFileName = rootProject.getName()+"_" + productFlavors[0].name + "_" + buildType.name + "_v" + defaultConfig.versionName + "-${releaseTime()}.apk"
		}
}

另外,关于productFlavor产品风格的配置也有一个问题需要注意,现在必须配置一个产品维度flavorDimensions,然后必须将风格分配到指定的风格维度,否则将会报错:Error:All flavors must now belong to a named flavor dimension.

详情参考官方文档配置产品风格

比如:

    flavorDimensions "version"
    productFlavors {
        Offline {
            dimension "version"
        }
        Online {
            dimension "version"
        }
    }

再次感谢vhgcc同学!

2018-10-26 17:04:11 wlj644920158 阅读数 356
  • 快速入门Android开发 视频 教程 android studio

    这是一门快速入门Android开发课程,顾名思义是让大家能快速入门Android开发。 学完能让你学会如下知识点: Android的发展历程 搭建Java开发环境 搭建Android开发环境 Android Studio基础使用方法 Android Studio创建项目 项目运行到模拟器 项目运行到真实手机 Android中常用控件 排查开发中的错误 Android中请求网络 常用Android开发命令 快速入门Gradle构建系统 项目实战:看美图 常用Android Studio使用技巧 项目签名打包 如何上架市场

    19571 人正在学习 去看看 任苹蜻

前言

从毕业到现在,做了整整3年Android开发,兜兜转转又回到了南京.哎…
今天主要记录下,来到新公司实现一个打包工具的过程,目前我们Android端的任务除了修改已经存在的bug和开发新的功能外,就是对于不同的买家输出对应的系统,说白了就是基于一套模板代码,要打成不同的APK,然后通过替换一些图片来达到样子长得不一样的目的,就这么简单,目前呢没有实现通过网络下载图片来实现,还是通过替换本地文件来进行输出的.所以一个打包工具就是必须的了.

正题

那么问题来了这个打包工具应该要具备什么功能呢?

  1. 要会查找UI文件,包括从本地查找和从SVN查找
  2. 从模板代码自动创建一个对应的Android工程
  3. 自动替换工程里面的图片文件
  4. 自动修改app.gradle文件(修改appid,baseurl等等)
  5. 自动打包成APK文件
  6. 自动加固应用
  7. 上传打包记录到数据库(包括应用名称,id等等)
  8. 自动安装到手机并且打开应用

OK!大体上的功能就是这些了,接下来具体说下利用C#语言怎么实现这些功能,首先上几个最终的效果图
在这里插入图片描述
上图是每次打包都需要修改的配置
在这里插入图片描述
上图是配置一些路径信息
在这里插入图片描述
上图是配置SVN账号信息
在这里插入图片描述
上图是配置下加固的信息,当前使用的加固是360加固
在这里插入图片描述
上图是配置数据库信息,用来保存打包记录
在这里插入图片描述
上图就是打包的过程截图

首先我们需要一个配置文件来保存,我们一些不怎么变动的打包信息,就可以保存在里面,这里我建了一个config.ini文件用来保存配置信息.

[app]
project_directory_name =
app_name =
base_url =
app_id =
version_code =
version_name =


[check]
is_install_jiagu_apk = false

[path]
ui_root_path =D:\UI
out_root_path =D:\OutService
model_path =D:\BtyProjects\MuYeHua

[svn]
svn_username =xxxx
svn_password =xxxx
svn_path =svn://xx.xx.xx.xx/

[jiagu]
jiagu_username =xxxxx
jiagu_password =xxxxxx
jiagu_path =D:\xxx\jiagu
jiagu_out_path =D:\OutApks

[db]
db_host =xx.xx.xx.xx
db_port =xx
db_user =xxx
db_pwd =xxxxx
db_name =xxx
db_table =xxxx

接下来我们针对上面提出的功能点一个个分析实现的过程:
1.查找本地和SVN上的UI文件
对于查找本地文件很简单UI的文件夹都是用项目名称来命名的只需要利用文件操作检查本地UI目录下是不是有指定的文件夹就行,


DirectoryInfo directoryInfo = new DirectoryInfo(config.ui_root_path);
                DirectoryInfo[] uis = directoryInfo.GetDirectories();
                foreach (DirectoryInfo info in uis)
                {
                    if (info.Name.Contains(config.app_name))
                    {
                        CheckAppColor(info.Name);
                        apendResultString("本地存在UI文件:" + info.Name + "    颜色值:" + app_color);
                        changeLogo();
                        return;
                    }
                }

那么对于SVN上的目录遍历我们就需要利用SVN工具来进行了,这里我们需要知道一点的是C#怎么调用其他应用程序并且截取标准输出

//同步模式调用其他程序,截取输出
        public List<string> exec(string exePath, string parameters)
        {
            List<string> list = new List<string>();
            ProcessStartInfo psi = new ProcessStartInfo();
            psi.RedirectStandardOutput = true;
            psi.CreateNoWindow = true;
            psi.UseShellExecute = false;
            psi.FileName = exePath;
            psi.Arguments = parameters;
            Process process = Process.Start(psi);
            StreamReader outputStreamReader = process.StandardOutput;
            string line = outputStreamReader.ReadLine();//每次读取一行
            while (!outputStreamReader.EndOfStream)
            {
                apendResultString(line);
                list.Add(line);
                line = outputStreamReader.ReadLine();
            }
            process.WaitForExit();//等待程序执行完退出进程
            process.Close();//关闭进程
            outputStreamReader.Close();//关闭流
            return list;
        }

有了这个基础我们就好办了,先遍历SVN指定目录下的文件夹,判断是否有我们项目的UI文件

 List<string> list = exec("svn", ls_svn_dir);

                    if (list.Count() > 0)
                    {
                        foreach (string path in list)
                        {
                            if (path.Contains(config.app_name))
                            {
                                ui_addr_on_svn = config.svn_path + svn_ui_dir + "/" + path;
                                CheckAppColor(ui_addr_on_svn);
                                apendResultString("SVN存在UI文件:" + ui_addr_on_svn + "    颜色值:" + app_color);
                                break;
                            }
                        }
                    }

如果SVN存在UI文件的情况下我们利用svn 的export命令进行下载(export和checkout的区别?)

//如果SVN存在UI就要开始下载了
                    apendResultString("######开始从SVN下载UI文件######");
                    string local_ui_path = config.ui_root_path + "\\" + config.app_name + app_color;
                    string projectPath = "export " + ui_addr_on_svn + " " + local_ui_path + " --username " + config.svn_username + " --password " + config.svn_password;
                    apendResultString(local_ui_path);
                    apendResultString(projectPath);

                    exec("svn", projectPath);
                    apendResultString("######UI文件下载完成!!!######");

UI文件的处理基本就是这样,然后接下来就是工程的创建,我们只需要从模板目录copy一份然后重新命名(命名规则工程名称+日期),这其中过滤掉.svn目和build目录就行了

final_project_name = config.project_directory_name + "_" + config.version_code + "_" + DateTime.Now.ToString("yyyy-MM-dd-hh-mm-ss");
            apendResultString("######开始创建Android工程" + final_project_name + "######");
            string desPath = config.out_root_path + "\\" + final_project_name;
            CopyDirectory(config.model_path, desPath);

工程创建成功之后我们就可以进行图片的替换了,

 foreach (string drawable in drawables_list)
                {
                    DirectoryInfo directory = new DirectoryInfo(config.ui_root_path + "\\" + config.app_name + app_color + "\\android\\" + drawable);
                    foreach (FileInfo f in directory.GetFiles())
                    {
                        if (f.Name.EndsWith(".png") || f.Name.EndsWith(".jpg") || f.Name.EndsWith(".jpeg"))
                        {
                            apendResultString("覆盖:" + f.Name);
                            f.CopyTo(config.out_root_path + "\\" + final_project_name + "\\" + res + "\\" + drawable + "\\" + f.Name, true);
                        }
                    }
                }

图片替换的过程中我们注意只替换图片文件就行了,接下来修改一下gradle文件一个新的Android项目就算完成了

string config_path = config.out_root_path + "\\" + final_project_name + "\\config\\config.gradle";
                string colors_path = config.out_root_path + "\\" + final_project_name + "\\" + res + "\\values\\colors.xml";
                string vcs_path = config.out_root_path + "\\" + final_project_name + "\\.idea\\vcs.xml";

                string[] congig_lines = File.ReadAllLines(config_path);
                for (int i = 0; i < congig_lines.Length; i++)
                {
                    if (congig_lines[i].Contains("application_id"))
                    {
                        congig_lines[i] = "     application_id  : \"" + config.app_id + "\",";
                        continue;
                    }
                    if (congig_lines[i].Contains("key_storefile"))
                    {
                        congig_lines[i] = "     key_storefile  : \"" + config.model_path + "/myh.jks\",";
                        congig_lines[i] = congig_lines[i].Replace('\\', '/');
                        continue;
                    }
                    if (congig_lines[i].Contains("outFile_name"))
                    {
                        congig_lines[i] = "     outFile_name  : \"" + config.project_directory_name + "\",";
                        continue;
                    }

                    if (congig_lines[i].Contains("url"))
                    {
                        congig_lines[i] = "     url  : \"" + config.app_url + "\",";
                        continue;
                    }
                    if (congig_lines[i].Contains("appname"))
                    {
                        congig_lines[i] = "     appname  : \"" + config.app_name + "\"";
                        continue;
                    }
                    if (congig_lines[i].Contains("version_code"))
                    {
                        congig_lines[i] = "     version_code  : " + config.version_code + ",";
                        continue;
                    }
                    if (congig_lines[i].Contains("version_name"))
                    {
                        congig_lines[i] = "     version_name  : \"" + config.version_name + "\",";
                        continue;
                    }
                }
                File.WriteAllLines(config_path, congig_lines);

                string[] colors_lines = File.ReadAllLines(colors_path);
                for (int i = 0; i < colors_lines.Length; i++)
                {
                    if (colors_lines[i].Contains("colorPrimary") && !colors_lines[i].Contains("Dark"))
                    {
                        colors_lines[i] = "    <color name=\"colorPrimary\">#" + app_color + "</color>";
                        continue;
                    }

                    if (colors_lines[i].Contains("colorPrimaryDark"))
                    {
                        colors_lines[i] = "    <color name=\"colorPrimaryDark\">#" + app_color + "</color>";
                        continue;
                    }
                    if (colors_lines[i].Contains("colorAccent"))
                    {
                        colors_lines[i] = "    <color name=\"colorAccent\">#" + app_color + "</color>";
                        continue;
                    }
                    if (colors_lines[i].Contains("color_theme"))
                    {
                        colors_lines[i] = "    <color name=\"color_theme\">#" + app_color + "</color>";
                        continue;
                    }
                }
                File.WriteAllLines(colors_path, colors_lines);

接下来就是最重要的一个步骤了,编译我们的工程生成APK文件,这里我是利用了控制台去执行的gradlew clean assembleLocalRelease然后截取的控制台的输出

string gradle_dir = config.out_root_path + "\\" + final_project_name + "\\";
            string cd_project_pan = gradle_dir.Substring(0, 2);
            string cd_project_directory = "cd " + gradle_dir;
            string buidl_project = "gradlew clean assembleLocalRelease";
            buidl_project = buidl_project.Trim().TrimEnd('&') + "&exit";//说明:不管命令是否成功均执行exit命令,否则当调用ReadToEnd()方法时,会处于假死状态
            using (Process p = new Process())
            {
                p.StartInfo.FileName = "cmd.exe";
                p.StartInfo.UseShellExecute = false;        //是否使用操作系统shell启动
                p.StartInfo.RedirectStandardInput = true;   //接受来自调用程序的输入信息
                p.StartInfo.RedirectStandardOutput = true;  //由调用程序获取输出信息
                p.StartInfo.CreateNoWindow = true;          //不显示程序窗口
                p.Start();//启动程序
                          //编译命令
                p.StandardInput.WriteLine(cd_project_pan);
                p.StandardInput.AutoFlush = true;
                p.StandardInput.WriteLine(cd_project_directory);
                p.StandardInput.AutoFlush = true;
                p.StandardInput.WriteLine(buidl_project);
                p.StandardInput.AutoFlush = true;
                StreamReader reader = p.StandardOutput;//截取输出流
                string line = reader.ReadLine();//每次读取一行
                apendResultString(line);
                while (!reader.EndOfStream)
                {
                    line = reader.ReadLine();
                    apendResultString(line);
                }
                p.WaitForExit();//等待程序执行完退出进程
                p.Close();
            }

编译成APK后我们记录下apk的路径然后同样的方式我们调用jiagu命令,这里需要注意的是360加固一般我们用的都是可视化的窗口工具,但是人性化的是他还提供了jar 的调用方式,这里我们依然使用控制台进行操作,注意导入签名信息就行了

//加固命令
            string cd_jiagu_pan = config.jiagu_path.Substring(0, 2);
            string cd_jiagu_directory = "cd " + config.jiagu_path;
            string login_jiagu = "java -jar jiagu.jar -login " + config.jiagu_username + " " + config.jiagu_password;
            string apk_release_directory = config.out_root_path + "\\" + final_project_name + "\\app\\build\\outputs\\apk\\local\\release";

            FileInfo[] apks = new DirectoryInfo(apk_release_directory).GetFiles();
            foreach (FileInfo apkInfo in apks)
            {
                if (apkInfo.Name.Contains(config.project_directory_name))
                {
                    final_apk_path = apkInfo.FullName;
                    break;
                }
            }
            string jiagu_project = "java -jar jiagu.jar -jiagu " + final_apk_path + " " + config.jiagu_out_path + "  -autosign";
            jiagu_project = jiagu_project.Trim().TrimEnd('&') + "&exit";//说明:不管命令是否成功均执行exit命令,否则当调用ReadToEnd()方法时,会处于假死状态
            using (Process p = new Process())
            {
                p.StartInfo.FileName = "cmd.exe";
                p.StartInfo.UseShellExecute = false;        //是否使用操作系统shell启动
                p.StartInfo.RedirectStandardInput = true;   //接受来自调用程序的输入信息
                p.StartInfo.RedirectStandardOutput = true;  //由调用程序获取输出信息
                p.StartInfo.CreateNoWindow = true;          //不显示程序窗口
                p.Start();
                //启动程序
                //编译命令
                p.StandardInput.WriteLine(cd_jiagu_pan);
                p.StandardInput.AutoFlush = true;
                p.StandardInput.WriteLine(cd_jiagu_directory);
                p.StandardInput.AutoFlush = true;
                p.StandardInput.WriteLine(jiagu_project);
                p.StandardInput.AutoFlush = true;
                //获取cmd窗口的输出信息
                StreamReader reader = p.StandardOutput;//截取输出流
                string line = reader.ReadLine();//每次读取一行
                apendResultString(line);
                while (!reader.EndOfStream)
                {
                    line = reader.ReadLine();
                    apendResultString(line);
                }
                p.WaitForExit();//等待程序执行完退出进程
                reader.Close();
                p.Close();
            }

等待加固完成了,我这里会吧打包的信息上传到数据库进行保存

// 数据库配置
            string connStr = "server=" + config.db_host + ";port=" + config.db_port + ";database=" + config.db_name + ";user=" + config.db_user + ";password=" + config.db_pwd + ";";
            MySqlConnection connection = null;
            bool exitsInDb = false;
            try
            {
                connection = new MySqlConnection(connStr);
                connection.Open();
                string selectByAppNameStr = "select * from " + config.db_table + " where app_name = '" + config.app_name + "'";
                MySqlCommand com = new MySqlCommand(selectByAppNameStr, connection);
                MySqlDataReader reader = com.ExecuteReader();
                while (reader.Read())
                {
                    string app_name_ = reader.GetString("app_name");
                    if (app_name_.Equals(config.app_name))
                    {
                        exitsInDb = true;
                    }
                }
                reader.Close();
                string updateStr;
                string date_string = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
                if (exitsInDb)
                {
                    updateStr = "update " + config.db_table + " set " +
                     "app_name = '" + config.app_name + "'," +
                     "app_file_name = '" + config.project_directory_name + "'," +
                     "app_url='" + config.app_url + "'," +
                     "app_version_code='" + config.version_code + "'," +
                     "app_version_name='" + config.version_name + "'," +
                     "update_date = '" + date_string + "'," +
                     "app_color = '" + app_color + "'," +
                     "user_name = '" + config.svn_username + "'" +
                     " where " +
                     "app_name = '" + config.app_name + "' " +
                     "or " +
                     "app_id = '" + config.app_id + "'";
                }
                else
                {
                    updateStr = "insert into " + config.db_table + " (app_name,app_file_name,app_url,app_version_code ,app_version_name ,app_id,create_date,update_date,app_color,user_name)" +
                              " values ('" + config.app_name + "','" + config.project_directory_name
                              + "','" + config.app_url + "','" + config.version_code + "','" + config.version_name
                              + "','" + config.app_id + "','" + date_string + "','" + date_string + "','" + app_color + "','" + config.svn_username + "')";
                }
                MySqlCommand updateCom = new MySqlCommand(updateStr, connection);
                updateCom.ExecuteNonQuery();

            }

OK,到这里基本上是所有的事情都做完了,但是这里为了方便测试,我会连接上手机进行安装和启动应用,这所有的操作都是依靠adb命令来完成的

 string install_com = "install -r " + final_apk_path;
            apendResultString("######开始安装应用,请确保USB连接######");
            exec("adb", install_com);
            apendResultString("######开始启动应用######");
            string start_com = "shell am start -n \"" + config.app_id + "/com.qfwl.lelexin.modules.other.view.activity.SplashActivity\" -a android.intent.action.MAIN -c android.intent.category.LAUNCHER";
            exec("adb", start_com);
            apendResultString("######应用已经启动######");

一个像模像样的打包工具就这么完成了!当然有人说了,如果是mac系统呢?这里为了mac也能顺利的打包成功,我们也同样谢了python的打包脚本.

2018-10-23 09:45:28 weixin_40251830 阅读数 417
  • 快速入门Android开发 视频 教程 android studio

    这是一门快速入门Android开发课程,顾名思义是让大家能快速入门Android开发。 学完能让你学会如下知识点: Android的发展历程 搭建Java开发环境 搭建Android开发环境 Android Studio基础使用方法 Android Studio创建项目 项目运行到模拟器 项目运行到真实手机 Android中常用控件 排查开发中的错误 Android中请求网络 常用Android开发命令 快速入门Gradle构建系统 项目实战:看美图 常用Android Studio使用技巧 项目签名打包 如何上架市场

    19571 人正在学习 去看看 任苹蜻

在app的build.gradle文件的android{}目录下添加

android.applicationVariants.all { variant ->
    variant.outputs.each { output ->
        def outputFile = output.outputFile
        if (outputFile != null && outputFile.name.endsWith('.apk')) {
            //这里修改apk文件名
            def fileName = "指定的文件名.apk"
            output.outputFile = new File(outputFile.parent, fileName)
        }
    }
}

 gradle 3.0以上版本改用以下代码添加

android.applicationVariants.all {
    variant ->
        variant.outputs.all {
            //这里修改apk文件名
            outputFileName = "${variant.name}-v${variant.versionName}.apk"
        }
}

 

如果有问题,可以直接评论,我每天都上线

没有更多推荐了,返回首页