不好要说好
在上一篇中,我解释了为什么我们不通过反射就会很难使用internal和hidden API。这是因为android.jar中就没包含这些API,因此,没人能够在编译时引用这些类。
这篇文章将描述如何还原最初的android.jar。这将允许我们像使用公开的API那样使用internal和hidden API。
如何得到原版android.jar?
我们需要修改android.jar,这样它才能包含所有的*.class文件(包括internal和hidden API类)。有两种办法:
1) Android是一个开源工程。我们可以下载源码并搭建编译环境,这样它就不能移除那些internal和hidden的类了。这个办法比较困难;
2) 每个模拟器或真机在运行时都会有一个等同android.jar的东西。我们可以从这里拿到jar文件,提取出原始的.class文件,并拷贝到Android SDK的android.jar中。
我将采用方案2。它易于开始,还不需要搭建Linux环境及编译环境等。
从设备上获取framework.jar
你可以使用命令行(adb pull)从模拟器或设备上下载文件,或者使用DDMS(借助Eclipse或SDK中的应用)。
注意:模拟器通常在.dex文件中包含代码,而真机一般在优化版的dex文件中包含代码——odex文件。操作odex文件比较困难,这也是为什么我选择模拟器的原因。
与Android SDK中的android.jar等同的文件是framework.jar。这个文件位于设备的:/system/framework/framework.jar
adb pull /system/framework/framework.jar
当framework.jar从设备上下下来之后,重命名为framework.zip并解压到独立的文件夹中,看起来是这个样子的:
classes.dex正是我们需要的。
创建framework-classes.zip
首先,我们需要把.dex文件转换成.jar格式。你可以使用通用的工具dex2jar。只需要运行:
dev2jar classes.dex
当转换结束时,你应该得到了classes.dex.dex2jar.jar文件。重命名为framework-classes.zip。使用zip查看器,进入到framework-classes.zip/com/android/internal/:
恭喜你,你已经拥有了所有的.class文件,包括internal和hidden API(尽管截图只确认了internal部分)。
创建original-android.jar
Android SDK的android.jar位于ANDROID_SDK/platforms/android-X/android.jar(X表示API等级)。
拷贝android.jar成custom-android.jar。解压至custom-android文件夹。将framework-classes.zip中所有的.class文件拷贝到custom-android文件夹中(你需要覆盖所有已经存在的.class文件)。
然后,压缩custom-android文件成original-android.zip。重命名为original-android.jar。
步骤总结
1. 选择你的目标平台X
2. 创建目标平台X的模拟器
3. 启动模拟器,下载/system/framework/framework.jar
4. 重命名framework.jar -> framework.zip
5. 从framework.zip中抽取classes.dex
6. 使用dex2jar工具,将其转换成classes.jar
7. 重命名classes.jar -> framework-classes.zip
8. 拷贝android.jar –> custom-android.zip
9. 解压custom-android.zip至custom-android文件夹
10. 将framework-classes.zip中所有文件拷贝至custom-android文件夹(覆盖存在的文件)
11. 压缩custom-android文件夹成original-android.zip
12. 重命名original-android.zip -> original-android.jar
打完收功。
总结
我们还原了android.jar,使其包含所有的internal和hidden API的.class文件。这只是第一步。下一步将创建定制的android平台,使其使用未删节版的android.jar,并将其添加到Android SDK platforms文件夹中。
1.Projection的作用
2.在Google Map上绘制直线的方法
绘制路线的步骤
1.确定路线的其实和终止的经纬度坐标;
2.在起点和终点上绘制图标;
3,将经纬度坐标换算成屏幕上的x轴/y轴
4,在起点和终点之间绘制路线;
Projection的作用
1.将地图上的经纬度坐标转化层层屏幕上的x轴和y轴的坐标
android.graphics.Point toPixels(GeoPoint in,android.graphics.Point out)
2.将x轴和y轴的坐标转换成地图上的经纬度坐标
GeoPoint fromPixels(int x,int y)
main.xml
<com.google.android.maps.MapView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:enabled="true"
android:id="@+id/mapViewId"
android:apiKey=""
/>
//在MapView之上创建一个图层,需要创建一个类,实现Overlay,并生成该类的对象,然后将该队形加到MapView。getOverlay()
//一个OverlayItem对象就代表了一个在地图上显示的标记
public class FirstOverlay extends ItemizedOverlay<OverlayItem>{
//创建一个List对象,用于持有该图层当中所有的标记对象
private ArrayList<OverlayItem> overlayItems = new ArrayList<OverlayItem>();
private Context context;
//第一个参数用于指定标记所使用的默认图片
public FirstOverlay(Drawable defaultMarker,Context context){
//必须调用父类的构造函数
supper(boundCenterBotton(defaultMarker));
this.context = context;
}
public FirstOverlay(Drawable defaultMarker){
supper(boundCenterBotton(defaultMarker));
}
//用于将生成好的OverlayItem对象添加到List当中
public void addOverlay(OverlayItem overlay){
overlayItems.add(overlay);
populate();
}
//用于创建一个overlayItem对象
@Override
protected OverlayItem createItem(int i){
return overlayItems.get(i);
}
//返回当前的overlay当中所报涵的overlayItem
@Override
public int size(){
return overlayItems.size();
}
//当用户点击标记时,所调用的函数
@Override
public boolean onTap(int index){
OverlayItem item = overlayItems.get(index);
AlterDialog.Builder builder = new AlterDialog.Builder(context);
builder.setTitle(item.getTitle());
builder.setMessage(item.getSnippet());
Dialog dialog = builder.create();
dialog.show();
return true;
}
}
public class MainActivity extends Activity {
/** Called when the activity is first created. */
private Projection projection;
private List<Overlay> overlays;
private MapController mapContrroller;
private GeoPoint beginGeoPoint;
private GeoPoint endGeoPoint;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//指定起始和终止位置的经纬度
beginGeoPoint = new GeoPoint(19240000, -99120000);
endGeoPoint = new GeoPoint(19340000, -99220000);
MapView mapView = (MapView) findViewById(R.id.mapViewId);
mapView.setBuiltInZoomControls(true);
//mapContrroller对象只要用于对地图进项控制
mapContrroller = mapView.getController();
overlays = mapView.getOverlays();
projection = mapView.getProjection();
overlays.add(new PointOverlay(beginGeoPoint));
overlays.add(new PointOverlay(endGeoPoint));
overlays.add(new LineOverlay(beginGeoPoint, endGeoPoint));
//
mapContrroller.animateTo(beginGeoPoint);
mapContrroller.setZoom(12);
}
@Override
protected boolean isRouteDisplayed(){
return false;
}
//该类的对象用于在地图上绘制线条
class LineOverlay extends Overlay {
private GeoPoint begin;
private GeoPoint end;
public LineOverlay(){
}
public LineOverlay(GeoPoint begin, GeoPoint end){
this.begin = begin;
this.end = end;
}
public void draw(Canvas canvas,MapView mapv, boolean shadow){
super.draw(canvas, mapv, shadow);
Paint paint = new Paint();
paint.setColor(Color.BLUE);
paint.setStyle(Paint.Style.FILL_AND_STROKE);
paint.setStrokeWidth(2);
Point beginPoint = new Point();
Point endPoint = new Point();
Path path = new Path();
projection.toPixels(beginGeoPoint,beginPoint);
projection.toPixels(endGeoPoint,endPoint);
path.moveTo(endPoint.x, endPoint.y);
path.lineTo(beginPoint.x, beginPoint.y);
canvas.drawPath(path, paint);
}
}
//该类的对象的作用是在地图上绘制图标
class PointOverlay extends Overlay{
private GeoPoint geoPoint;
public PointOverlay(){
}
public PointOverlay(GeoPoint geoPoint){
this.geoPoint = geoPoint;
}
public void draw(Canvas canvas,MapView mapv, boolean shadow){
super.draw(canvas, mapv, shadow);
Point point = new Point();
projection.toPixels(geoPoint, point);
Bitmap bmp = BitmapFactory.decodeResource(getResources(), R.drawable.icon);
Paint paint = new Paint();
canvas.drawBitmap(bmp, point.x, point.y-20, paint);
}
}
}