合并apk和odex的方法
有时候发现别人手机里有一款 apk 挺好,想弄出来装自己手机上,可是却发现那个 apk 是残缺的,里面没有 classes.dex 文件,却有个跟 apk 同名的 odex 文件。残缺的 apk 是装不了的,只能把这个 apk 跟 odex 合并成一个完整的 apk 才能安装。
需要的工具:
1 . smali-1.2.2.jar 和 baksmali-1.2.2.jar
2 . 还需要这个 apk 所在的 rom 里面的一些 jar 文件,都在 /system/framework 里面: core.jar, ext. jar, framework. jar, android.policy. jar, services. Jar 。当然,这五个是最基本的,有可能还不够,这种情况下面会讲到。
总共分四步:
1 . 把下载好的 smali-1.2.2.jar 和 baksmali-1.2.2.jar ,还有 rom 里面抠出来的 5 个 jar ,放到工作目录,然后 apk 和 odex 也放到一起。
2 . 分解 odex 文件为 class 文件。
命令: java -jar baksmali-1.2.2.jar -x <a.odex>
<a.odex> 处是你要分解的 odex 文件的名字,命令完成之后,会生成一个 out 文件夹,里面就是所有的 class 文件。如果出现问题,比如什么异常,缺少包什么的,就更到 rom 里面把出错信息里面要求的包拿出来,放到当前目录下。
3. 将 class 生成为 classes.dex 文件。
命令: java -Xmx512M -jar smali-1.2.2.jar out -o classes.dex
这一步应该不会有什么问题,然后会生成 classes.dex 文件。
4. 把 classes.dex 放入 apk 里面,把盖子盖上。
最后这一步最简单了,用解压缩软件打开 apk ,然后把千辛万苦生成的 classes.dex 塞进去,就 ok 了。这个 apk 就能用了。如果想给他重新签个名的话,去找个 Auto Sign 签名工具签署一下就行。
===========================================================
用hardcode写动画遇到一个问题,pivot的值怎么设置。我一开始以为是相对于整个屏幕的,后来才发现,原来是相对于要实现动画的这个view的左上角的坐标。 在这个pivot上浪费了很长时间,在这里记一笔
===========================================================
1.从google搜索内容
Intent intent = new Intent();
intent.setAction(Intent.ACTION_WEB_SEARCH);
intent.putExtra(SearchManager.QUERY,"searchString")
startActivity(intent);
2.浏览网页
Uri uri = Uri.parse("http://www.google.com");
Intent it = new Intent(Intent.ACTION_VIEW,uri);
startActivity(it);
3.显示地图
Uri uri = Uri.parse("geo:38.899533,-77.036476");
Intent it = new Intent(Intent.Action_VIEW,uri);
startActivity(it);
4.路径规划
Uri uri = Uri.parse("http://maps.google.com/maps?f=dsaddr=startLat%20startLng&daddr=endLat%20endLng&hl=en");
Intent it = new Intent(Intent.ACTION_VIEW,URI);
startActivity(it);
5.拨打电话
Uri uri = Uri.parse("tel:xxxxxx");
Intent it = new Intent(Intent.ACTION_DIAL, uri);
startActivity(it);
6.调用发短信的程序
Intent it = new Intent(Intent.ACTION_VIEW);
it.putExtra("sms_body", "The SMS text");
it.setType("vnd.android-dir/mms-sms");
startActivity(it);
7.发送短信
Uri uri = Uri.parse("smsto:0800000123");
Intent it = new Intent(Intent.ACTION_SENDTO, uri);
it.putExtra("sms_body", "The SMS text");
startActivity(it);
String body="this is sms demo";
Intent mmsintent = new Intent(Intent.ACTION_SENDTO, Uri.fromParts("smsto", number, null));
mmsintent.putExtra(Messaging.KEY_ACTION_SENDTO_MESSAGE_BODY, body);
mmsintent.putExtra(Messaging.KEY_ACTION_SENDTO_COMPOSE_MODE, true);
mmsintent.putExtra(Messaging.KEY_ACTION_SENDTO_EXIT_ON_SENT, true);
startActivity(mmsintent);
8.发送彩信
Uri uri = Uri.parse("content://media/external/images/media/23");
Intent it = new Intent(Intent.ACTION_SEND);
it.putExtra("sms_body", "some text");
it.putExtra(Intent.EXTRA_STREAM, uri);
it.setType("image/png");
startActivity(it);
StringBuilder sb = new StringBuilder();
sb.append("file://");
sb.append(fd.getAbsoluteFile());
Intent intent = new Intent(Intent.ACTION_SENDTO, Uri.fromParts("mmsto", number, null));
// Below extra datas are all optional.
intent.putExtra(Messaging.KEY_ACTION_SENDTO_MESSAGE_SUBJECT, subject);
intent.putExtra(Messaging.KEY_ACTION_SENDTO_MESSAGE_BODY, body);
intent.putExtra(Messaging.KEY_ACTION_SENDTO_CONTENT_URI, sb.toString());
intent.putExtra(Messaging.KEY_ACTION_SENDTO_COMPOSE_MODE, composeMode);
intent.putExtra(Messaging.KEY_ACTION_SENDTO_EXIT_ON_SENT, exitOnSent);
startActivity(intent);
9.发送Email
Uri uri = Uri.parse("mailto:[email protected]");
Intent it = new Intent(Intent.ACTION_SENDTO, uri);
startActivity(it);
Intent it = new Intent(Intent.ACTION_SEND);
it.putExtra(Intent.EXTRA_EMAIL, "[email protected]");
it.putExtra(Intent.EXTRA_TEXT, "The email body text");
it.setType("text/plain");
startActivity(Intent.createChooser(it, "Choose Email Client"));
Intent it=new Intent(Intent.ACTION_SEND);
String[] tos={"[email protected]"};
String[] ccs={"[email protected]"};
it.putExtra(Intent.EXTRA_EMAIL, tos);
it.putExtra(Intent.EXTRA_CC, ccs);
it.putExtra(Intent.EXTRA_TEXT, "The email body text");
it.putExtra(Intent.EXTRA_SUBJECT, "The email subject text");
it.setType("message/rfc822");
startActivity(Intent.createChooser(it, "Choose Email Client"));
Intent it = new Intent(Intent.ACTION_SEND);
it.putExtra(Intent.EXTRA_SUBJECT, "The email subject text");
it.putExtra(Intent.EXTRA_STREAM, "file:///sdcard/mysong.mp3");
sendIntent.setType("audio/mp3");
startActivity(Intent.createChooser(it, "Choose Email Client"));
10.播放多媒体
Intent it = new Intent(Intent.ACTION_VIEW);
Uri uri = Uri.parse("file:///sdcard/song.mp3");
it.setDataAndType(uri, "audio/mp3");
startActivity(it);
Uri uri = Uri.withAppendedPath(MediaStore.Audio.Media.INTERNAL_CONTENT_URI, "1");
Intent it = new Intent(Intent.ACTION_VIEW, uri);
startActivity(it);
11.uninstall apk
Uri uri = Uri.fromParts("package", strPackageName, null);
Intent it = new Intent(Intent.ACTION_DELETE, uri);
startActivity(it);
12.install apk
Uri installUri = Uri.fromParts("package", "xxx", null);
returnIt = new Intent(Intent.ACTION_PACKAGE_ADDED, installUri);
===========================================================
很多人使用startActivity时候,会碰到如下的异常:
Caused by: android.util.AndroidRuntimeException: Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?
我曾经也遇到过,不过后来研究了一下之后,明白了原理,记下来,以为碰到同样困扰的兄弟们解惑。
都知道,Context中有一个startActivity方法,Activity继承自Context,重载了startActivity方法。如果使 用Activity的startActivity方法,不会有任何限制,而如果使用Context的startActivity方法的话,就需要开启一个 新的task,遇到上面那个异常的,都是因为使用了Context的startActivity方法。解决办法是,加一个flag。
===========================================================
用过ActivityManager的童鞋估计都知道,可以从ActivityManager里面可以获取到当前运行的所有任务,所有进程和所有服务,这是任务管理器的核心。
那么,从里面我们可以发掘点什么出来吗?
仔细看getRunningTasks的文档,里面说获取的是系统中"running"的所有task,"running"状态包括已经被系统冻结的task。而且返回的这个列表是按照顺序排列的,也就是说第一个肯定比第二个后运行。
getRunningTasks有个整型参数,表示返回列表的最大个数。那么,我们 如果把1作为参数给进去,那么他返回的task就是当前运行的那个task,然后从task中获取到最顶层的activity,这个activity就是 当前显示给用户的那个activity了。
至于这个能做什么,嘿嘿,我相信你知道的。
===========================================================
已知包名和类名,如何判断这个activity是否在系统中存在呢?很简单,通过intent就行。
===========================================================
android.os下的StatFs类主要用来获取文件系统的状态,能够获取sd卡的大小和剩余空间,获取系统内部空间也就是/system的大小和剩余空间等等。
看下读取sd卡的:
然后看下读取系统内部空间的:
StatFs获取的都是以block为单位的,这里我解释一下block的概念:
1.硬件上的 block size, 应该是"sector size",linux的扇区大小是512byte
2.有文件系统的分区的block size, 是"block size",大小不一,可以用工具查看
3.没有文件系统的分区的block size,也叫“block size”,大小指的是1024 byte
4.Kernel buffer cache 的block size, 就是"block size",大部分PC是1024
5.磁盘分区的"cylinder size",用fdisk 可以查看。
我们这里的block size是第二种情况,一般SD卡都是fat32的文件系统,block size是4096.
这样就可以知道手机的内部存储空间和sd卡存储空间的总大小和可用大小了。
===========================================================
如果大家在非黑色背景下使用ListView控件时,Android默认可能在滚动ListView时这个列表控件的背景突然变成黑色。这样可能导致程序 的黑色的背景和主程序的主题既不协调。解决的方法Google在设计Android时也考虑了,在Layout的ListView中加入 android:cacheColorHint="#00000000" 的属性即可。