不知道什么是Perl猛戳这个链接 http://zh.wikipedia.org/wiki/Perl



   
任务:    

           
随着手机/平板的各方面性能的不断发展(CPU,内存,存储),Android这个移动领域绝对的霸主也升级到了4.1版本,软硬件的提高意味着人们对使用体验有了越来越高的要求,在移动设备里面安装的App也越来越多,但是Android总是以刷机为乐趣的,每次刷机就意味着要备份软件(这里不讨论软件数据的备份),也就意味着备份apk,apk一多,管理起来就成了一件头痛的事情,最起码的,我们要知道我们都备份了哪些apk,最最起码要知道它们叫什么名字,因为不管在windows还是linux平台下面,都是无法直接解析apk的名字的。所以不管你是以什么样的方式备份出来的apk,它总不可能是按你的要求来命名的,今天的目标/任务就是把apk按你的要求来命名。

方法:

           
由于在windows/linux上无法直接通过系统的文件管理器解析apk的名字等等属性,所以必须要借助别的工具,这其中最好的必须是Google自家的aapt工具,不知道aapt是什么?猛戳这个链接http://www.ltesting.net/ceshi/ceshijishu/sjcs/android/2012/0511/204843.html。aapt可以直接读取出来一个apk的各种属性,比如AndroidManifest.xml里面定义的包名,软件名,版本号,使用的权限等等信息。使用aapt读取出来的信息是一大堆,所以必须要使用正则表达式的模式匹配获取我们所需要的信息,然后再根据要求来给相应的apk重命名。注意,这个地方是要给当前目录下所有的apk自动重命名,所以,必然要用到for语句(在perl里面是foreach)。

先介绍一下aapt的使用。这里只介绍用到的功能,dump,具体命令是aapt d(ump) badging
mms.apk。它会打印出如下的信息:



package: name='com.elsdoerfer.android.autostarts' versionCode='24'
versionName='1.7.7'

sdkVersion:'4'

targetSdkVersion:'14'

application-label:'Autostarts'

application-label-zh:'自启管家'

application-icon-160:'res/drawable/icon.png'

application-icon-240:'res/drawable-hdpi/icon.png'

application: label='Autostarts' icon='res/drawable/icon.png'

launchable-activity:
name='com.elsdoerfer.android.autostarts.ListActivity' 
label='Autostarts' icon=''

uses-permission:'android.permission.WRITE_SETTINGS'

uses-permission:'android.permission.WRITE_SECURE_SETTINGS'

uses-permission:'android.permission.CHANGE_COMPONENT_ENABLED_STATE'

uses-configuration:

uses-gl-es:'0xffffffff'

uses-feature:'android.hardware.touchscreen'

uses-implied-feature:'android.hardware.touchscreen','assumed you
require a touch screen unless explicitly made optional'

main

other-activities

supports-screens: 'small' 'normal' 'large' 'xlarge'

supports-any-density: 'true'

locales: '--_--' 'zh'

densities: '160' '240'



   
注意,在windows的cmd里面,编码是cp936,和aapt默认输出的utf8是冲突的,所以如果你直接执行上述命令,会在cmd的窗口中看到所有的中文都是乱码的,正确的方法是把输出的结果重定向到文本文件里面,再用记事本或其它的工具打开输出的文本文件,就不会有乱码了。关于aapt的其它用法请自行查看帮助,直接输入aapt即可。

我们的目标就是要从上面的那一堆的数据中,用perl里面的正则表达式提取出我们需要的信息,我所需要的信息数据于这样:Google
Play
音乐_v5.0.1053J.731804_(com.google.android.music).apk,软件名称_v版本号_(apk的包名).apk。

通过分析上面的输出结果可以看到:

       
name='com.elsdoerfer.android.autostarts'

       
versionName='1.7.7'

       
application-label:'Autostarts'

       
application-label-zh:'自启管家'

   
这四个字符串是我们要需要的,下面的任务就是如何把它们的值提取出来。下面上整个程序的perl源代码。





# use strict;

use Encode;

use open ':encoding(GBK)', ':std';

use open ':encoding(UTF-8)';



my @files = (glob(".*.apk"), glob("*.apk"));



foreach (@files)

{

    # print
"Start Processing -> $_ \n";



    #
执行aapt并赋值给$info

    $info =
`aapt d badging $_`;



    $info =~
m/name=\'(.*?)\'/;

    $pkg_name =
$1;  # apk的包名

    $info =~
m/versionName=\'(.*?)\'/;

    $version =
$1;  # apk的版本号



    # 判断是否存在
label-zh_CN名字,

    #
若不存在则以label名字代替

    if ($info =~
m/application-label-zh_CN:\'(.*?)\'/) {

  
   
 $name = $1;

    }

    else {

  
   
 $info =~ m/application-label:\'(.*?)\'/;

  
   
 $name = $1;  

    }



    #
拼接格式化后想要的文件名

  
 $out_filename =
"$name\_v$version\_($pkg_name).apk";



    open(LOG,
">>log.txt") || warn "Can't Open the file";

    print LOG
"$out_filename \n";



    #
必须要转换成gb2312编码,否则会造成中文乱码

  
 $out_filename = encode("gb2312",
$out_filename);

    print
decode("gb2312", $out_filename);



    #
若修改后导致文件重名,则输出警告,不作处理

    if(-e
$out_filename){

  
   
 warn "Can't rename $_ to $out_filename.

  
   
 The $out_filename exists!\n";

    }

    else{
 

  
   
 # 重命名文件,若重命名失败,则输出警告

  
   
 # 注意此处不要调用system("ren $a $b")或`ren a b`

  
   
 # 因为直接调用会造成文件名有空格会重命名失败的问题

  
   
 rename $_, $out_filename

  
   
   
 or warn "Rename $_ to $out_filename failed:
$!\n";



    }



    print
"\n";

}



close LOG || warn "Can't close the file";







   
对这个perl文件作一个小小的解释:

       
my @files = (glob(".*.apk"),
glob("*.apk"));   
使用glob()函数获取到目录下面的所有文件名,这里使用的是*.apk和.*.apk,这两个是有区别的,因为perl源于unix/linux,在linux下面,所有以点开头的文件都是隐藏文件,程序默认是不解析的,所以我们必须要加上.*.apk。

foreach
(@files)   
{  }  
perl里面的for循环是用foreach来实现的,对于@files这个数组里面的所有元素,它会依次执行大括号里面的语句。

       
$info =~ m/name=\'(.*?)\'/; 
正则表达式,=~m表示模式匹配,/.../之间的内容是正则表达式的主体,name=\'(.*?)\'表示取name='...'单引号里面的内容,就是我们所需要的。具体正则表达式的语法,请自行google。

$out_filename = encode("gb2312",
$out_filename);   由于
perl起码起源于linux/unix,故其内部处理数据都是以utf8编码来实现的,而windows的cmd是cp936,如果不做编码转换的话,直接调用perl的rename对文件重命名的时候就会出现中文乱码的情况,所以这里用encode()函数把所需要的目标文件名转换成gb2312编码,即cp936。

执行perl
rename_apk.pl,它会自动查找当前目录下的所有apk,并按给定的 软件名称_v版本号_(apk的包名).apk
这个规则重命名,同时会在当前目录下输出一个log.txt文件,它会记录所有已经格式化好的目标文件名,一来是可以查看目标文件名有没有正确,二来是可以给那些因为有特殊字符而不能自动重命名的apk一个供修改的文件名,方便手动修改文件名然后再手动重命名。

好了,以上这个perl文件就是我花了一天时间从零开始学习perl和正则表达式所写出来的东西,达到了我所要的目标,现总结一下对perl印象深刻的几个地方:

1. 它的变量不分类型,什么整数啊,浮点数啊,字符串啊,都是直接用$var来定义的。

       
2.
`...`,可以使用这条语句执行原本可以在cmd里面执行的命令,即直接调用外部shell的命令,当然,也可以用system()来调用,作用貌似是一样的。

3. 数组使用@var来定义,可以直接用foreach(@var)来遍历。

       
4.
在foreach中,直接使用$_这个变量来调用数组中存在的当前正在使用的元素的值。比如数据中存的是5个字符串,foreach就是依次遍历5次,然后每次使用$_就是直接调用当前个元素的值。

5. 在print里面,可以直接把变量替换成对应的值输出。比如$a = "abc",  print
"123$a"输出的结果就是123abc,需要注意的是此处的print后面是用的双引号,如果是用单引号,则不解析变量的值,这里有点类似于PHP的语法。

OK,学习笔记记录完毕,凌晨12点40分,准备睡觉。

最新文章

  1. 自定义样式RatingBar的使用
  2. CXF WebService整合SpringMVC的maven项目
  3. LayaAir引擎——(七)
  4. python之购物车的编写(熬夜撸代码中。。。)
  5. JSP标准标签库(JSTL)之核心标签(下)
  6. [CareerCup] 1.7 Set Matrix Zeroes 矩阵赋零
  7. Mysql 自动化任务
  8. iOS 面试基础题目
  9. comet4j文档
  10. 由c#的值类型与引用类型说开去
  11. iOS-深复制(mutableCopy)与浅复制(copy)
  12. DevExpress 控件 GridControl常见用法
  13. (转)window.location.search的用法
  14. Swift - 歌曲播放样例(附带播放时间和播放进度)
  15. java中System类简介(转)
  16. 可能是最详细的 Hexo + GitHub Pages 搭建博客的教程
  17. CCF系列之最优灌溉(201412-4)
  18. JS table内容转成二维数组,支持colspan和rowspan
  19. 非常全的VsCode快捷键
  20. Python 字典(Dictionary) 基本操作

热门文章

  1. nginx模块开发
  2. 关于有的Apk无法反编译的探究
  3. IIS访问站点,出现connection refused
  4. linux中不同颜色的文件代表什么不同的类型
  5. java9新特性-12-集合工厂方法:快速创建只读集合
  6. pyton写购物车
  7. 【转载】eclipse中批量修改Java类文件中引入的package包路径
  8. 洛谷 P1501 [国家集训队]Tree II Link-Cut-Tree
  9. linux上编译好的php添加memcache扩展
  10. mysql主从复制主服务器日志格式的区别