本程序适用于下载http://androidxref.com/网站的ANDROID SOURCE 与KERNEL SOURCE。 由于是原型,所以完全没考虑下载效率,代码结构等问题,此类问题有待读者继续完善。
新建一个android5.0的项目,然后创建以下文件
\Download\AndroidManifents.xml 里面只定义了一个activity
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.androidxref.download" android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="21" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
<application android:allowBackup="true" android:icon="@drawable/ic_launcher"
android:label="@string/app_name" android:theme="@android:style/Theme.Holo.Light.NoActionBar">
<activity android:name="com.androidxref.download.ui.MainActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
\Download\libs\jsoup-1.8.3.jar 自行在百度下载jsoup-1.8.3.jar库
Download\src\com\androidxref\download\downloader\DownloaderAsyncTask.java
package com.androidxref.download.downloader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.net.URLConnection;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import android.content.ContentValues;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Handler;
import android.text.TextUtils;
import android.view.View;
import android.widget.ScrollView;
import android.widget.TextView;
import com.androidxref.download.tools.FileUtil;
import com.androidxref.download.tools.LogUtil;
public class DownloaderAsyncTask extends AsyncTask<String, String, Float>{
String TAG = DownloaderAsyncTask.class.getName();
Context mContext;
TextView mTextView;
ScrollView mScrollView;
public DownloaderAsyncTask(Context context, TextView textView, ScrollView scrollView) {
mContext = context;
mTextView = textView;
mScrollView = scrollView;
}
@Override
protected Float doInBackground(String... params) {
String androidVersion = FileUtil.getAndroidVersionByUri(params[0]);
// 获取要下载的Android版本
if(TextUtils.isEmpty(androidVersion)){
publishProgress("android version is empty");
publishProgress("please according to the following format and try again");
publishProgress("http://androidxref.com/XXXXXXX/xref/");
} else {
LogUtil.i(TAG, androidVersion);
try{
String uri = params[0];
LogUtil.i(TAG, uri.toString());
//开始下载
publishProgress("downloaduri = " + uri);
startDownload(uri);
}catch(Exception e) {
LogUtil.e(TAG, e.toString() );
publishProgress(e.toString());
e.printStackTrace();
}
}
return null;
}
private void startDownload(String uri) {
try {
Document doc = Jsoup.connect(uri).timeout(5000).post();
Document content = Jsoup.parse(doc.toString());
Elements divs = content.select("#download"); // 获取download
if(divs.size() == 0){ // 获取所有可下载的目录
divs = content.select("#dirlist"); // 获取dirlist
Document divcontions = Jsoup.parse(divs.toString());
Elements element = divcontions.getElementsByTag("a");
for (Element links : element) {
String title = links.getElementsByTag("a").text();
if(title.contains("..")) {
continue;
}
String link = links.select("a").attr("href").replace("/", "")
.trim();
String url = uri.endsWith("/") ? (uri + link) : (uri + "/" + link);
LogUtil.i(TAG, "startDownload url = " + url);
publishProgress("startDownload " + url);
startDownload(url); // 递归调用startDownload下载当前目录下所有文件
}
}
// 获取要下载的url
Elements parents = divs.parents();
String downloadLink = parents.get(0).select("a").attr("href").trim();
if(downloadLink.contains("..")) {
return;
}
downloadLink = FileUtil.formatDownloadLink(downloadLink);
// 下载到指定位置
downloadFile(downloadLink,uri);
} catch (IOException e) {
e.printStackTrace();
}
}
private void downloadFile(String downloadLink, String filePath) {
File newFile = FileUtil.getEmptyFile(downloadLink,filePath,mContext);
publishProgress("downloadFile " + downloadLink + " to " + newFile.getPath());
LogUtil.i(TAG, "downloadFile " + downloadLink + " to " + newFile.getPath());
try {
// 构造URL
URL url = new URL(downloadLink);
// 打开连接
URLConnection con = url.openConnection();
// 输入流
InputStream is = con.getInputStream();
// 1K的数据缓冲
byte[] bs = new byte[1024];
// 读取到的数据长度
int len;
// 输出的文件流
OutputStream os = new FileOutputStream(newFile);
// 开始读取
while ((len = is.read(bs)) != -1) {
os.write(bs, 0, len);
}
// 完毕,关闭所有链接
os.close();
is.close();
} catch (Exception e) {
LogUtil.e(TAG, "downloadFile e.toString() = " + e.toString());
LogUtil.e(TAG, "downloadFile downloadLink = " + downloadLink);
LogUtil.e(TAG, "downloadFile file = " + newFile);
publishProgress("downloadFile e = " + e.toString());
e.printStackTrace();
}
}
@Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
mTextView.append(values[0] + "\n\n");
scrollToBottom(mScrollView,mTextView);
}
public static void scrollToBottom(final View scroll, final View inner) {
Handler mHandler = new Handler();
mHandler.post(new Runnable() {
public void run() {
if (scroll == null || inner == null) {
return;
}
int offset = inner.getMeasuredHeight() - scroll.getHeight();
if (offset < 0) {
offset = 0;
}
scroll.scrollTo(0, offset);
}
});
}
@Override
protected void onPostExecute(Float result) {
super.onPostExecute(result);
publishProgress("...stoping...");
}
@Override
protected void onPreExecute() {
super.onPreExecute();
mTextView.setText("");
publishProgress("...initing...");
}
}
Download\src\com\androidxref\download\ui\MainActivity.java
package com.androidxref.download.ui;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ScrollView;
import android.widget.TextView;
import com.androidxref.download.R;
import com.androidxref.download.downloader.DownloaderAsyncTask;
import com.androidxref.download.tools.LogUtil;
public class MainActivity extends Activity {
private final static String TAG = MainActivity.class.getName();
private static String mDownloadUri;
private EditText mDownloadUriEditText;
private TextView mDownloadLogs;
ScrollView mScrollView;
private static DownloaderAsyncTask mDownloaderAsyncTask;
private final static int MSG_START_DOWNLOAD = 0X00001;
private final static int MSG_STOP_DOWNLOAD = 0X11110;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button download = (Button) findViewById(R.id.button_download);
mDownloadUriEditText = (EditText) findViewById(R.id.download_uri);
mDownloadLogs = (TextView) findViewById(R.id.download_logs);
mScrollView = (ScrollView) findViewById(R.id.download_logs_scrollview);
download.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
mDownloadUri = mDownloadUriEditText.getText().toString();
Message msg = new Message();
msg.what = MSG_START_DOWNLOAD;
mHandler.removeMessages(MSG_START_DOWNLOAD);
mHandler.sendMessageDelayed(msg, 200);
} catch (Exception e) {
LogUtil.e(TAG, "error = "+e.toString());
e.printStackTrace();
}
}
});
}
@SuppressLint("HandlerLeak")
Handler mHandler = new Handler(){
public void handleMessage(Message msg) {
LogUtil.i(TAG, "mHandler.handleMessage( "+ msg.what + " );");
switch (msg.what) {
case MSG_START_DOWNLOAD:
if(mDownloaderAsyncTask == null){
mDownloaderAsyncTask = new DownloaderAsyncTask(MainActivity.this,mDownloadLogs,mScrollView);
mDownloaderAsyncTask.execute(mDownloadUri);
}
break;
case MSG_STOP_DOWNLOAD:
if(mDownloaderAsyncTask != null){
mDownloaderAsyncTask.cancel(true);
mDownloaderAsyncTask = null;
}
break;
default:
break;
}
};
};
}
Download\src\com\androidxref\download\tools\FileUtil.java
package com.androidxref.download.tools;
import java.io.File;
import android.content.Context;
import android.os.Environment;
import android.os.storage.StorageManager;
import android.text.TextUtils;
public class FileUtil {
final static String TAG = FileUtil.class.getName();
private static String mFileNamePrefix = "Android";
private static String mAndroidVersion = mFileNamePrefix;
final static String MUNSTCONTAINSTR[] = {"/xref/","http://androidxref.com/"};
/**
* @param downloaduri download url
* @return android version
*/
public static String getAndroidVersionByUri(String downloaduri) {
String result ;
// 判断string中是否存在MUNSTCONTAINSTR中的字段
if(!isContains(downloaduri)) {
return null;
}
// 获取android的版本号
result = downloaduri.substring(downloaduri.lastIndexOf(MUNSTCONTAINSTR[1])+MUNSTCONTAINSTR[1].length(), downloaduri.indexOf(MUNSTCONTAINSTR[0]));
mAndroidVersion = null == result ? result : mFileNamePrefix+result;
return mAndroidVersion;
}
private static boolean isContains(String str) {
boolean result = true;
if(!TextUtils.isEmpty(str)){
for(int i = 0; i < MUNSTCONTAINSTR.length; i++){
result &= str.contains(MUNSTCONTAINSTR[i]);
}
return result;
}
return false;
}
public static File convertUriToLocalPath(String string,Context context) {
String path = string.substring(string.indexOf(MUNSTCONTAINSTR[0])+MUNSTCONTAINSTR[0].length(),
string.lastIndexOf("/")+1);
LogUtil.i(TAG, "convertUriToLocalPath path = " + path);
// 递归创建文件目录
File file = FileUtil.createFiles(new File("/sdcard/"+mAndroidVersion+"/"+path));
return file;
}
public static File createFiles(File file) {
LogUtil.i(TAG, "createFiles file.getPath() = "+file.getPath());
if(file.exists()){
return file;
}
// /sdcard/Android1.1/developers/demos/JustForUs/gradle/wrapper/
String path = file.getPath();
if(path.endsWith("/")){
path = path.substring(0,path.lastIndexOf("/"));
}
LogUtil.i(TAG, "createFiles path = "+path);
File newFile = new File(file.getPath().substring(0, file.getPath().lastIndexOf("/")));
createFiles(newFile);
file.mkdir();
return file;
}
public static String formatDownloadLink(String downloadLink) {
downloadLink = MUNSTCONTAINSTR[1].substring(0, MUNSTCONTAINSTR[1].length()-1) + downloadLink;
return downloadLink;
}
public static File getEmptyFile(String downloadLink, String filePath,Context mContext) {
File file = FileUtil.convertUriToLocalPath(filePath, mContext);
if (!file.exists()) {
LogUtil.e(TAG, "downloadFile : " + file.getPath() + " not created");
}
// 如果目标文件已经存在,则删除。产生覆盖旧文件的效果
String fileName = file.getPath() + "/" + downloadLink.substring(downloadLink.lastIndexOf("/") + 1, downloadLink.length());
File newFile = new File(fileName);
if (newFile.exists()) {
newFile.delete();
}
return newFile;
}
}
Download\src\com\androidxref\download\tools\LogUtil.java
package com.androidxref.download.tools;
import android.util.Log;
public final class LogUtil {
final static int LOGLEV = 10;
final static String LOGPREF = "======> ";
final static String LOGSUFF = " <======";
/**
* Priority constant for the println method; use Log.v.
*/
public static final int VERBOSE = 2;
public static int v(String tag, String msg) {
if(LOGLEV > VERBOSE){
Log.v(tag, LOGPREF + msg + LOGSUFF);
}
return -1;
}
/**
* Priority constant for the println method; use Log.d.
*/
public static final int DEBUG = 3;
public static int d(String tag, String msg) {
if(LOGLEV > DEBUG){
Log.d(tag, LOGPREF + msg + LOGSUFF);
}
return -1;
}
/**
* Priority constant for the println method; use Log.i.
*/
public static final int INFO = 4;
public static int i(String tag, String msg) {
if(LOGLEV > INFO){
Log.i(tag, LOGPREF + msg + LOGSUFF);
}
return -1;
}
/**
* Priority constant for the println method; use Log.w.
*/
public static final int WARN = 5;
public static int w(String tag, String msg) {
if(LOGLEV > INFO){
Log.w(tag, LOGPREF + msg + LOGSUFF);
}
return -1;
}
/**
* Priority constant for the println method; use Log.e.
*/
public static final int ERROR = 6;
public static int e(String tag, String msg) {
if(LOGLEV > INFO){
Log.e(tag, LOGPREF + msg + LOGSUFF);
}
return -1;
}
}
\Download\res\layout\activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<EditText android:id="@+id/download_uri"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/download_uri_text"
android:hint="@string/download_uri"/>
<Button android:id="@+id/button_download"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/button_download"/>
</LinearLayout>
<ScrollView
android:id="@+id/download_logs_scrollview"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/download_logs"
android:layout_width="match_parent"
android:textSize="16sp"
android:layout_height="wrap_content"/>
</ScrollView>
</LinearLayout>
Download\res\values\strings.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">demo</string>
<string name="action_settings">Settings</string>
<string name="button_download">Download</string>
<string name="download_uri">download uri</string>
<string name="download_uri_text">http://androidxref.com/6.0.0_r1/xref/external/flac</string>
</resources>
关键文件就这么几个,其他都是一些eclipse自动生成的文件