场景

项目中的广告详情页面是个webView加载的富文本,包含图片,需要点击查看大图,长按识别二维码功能。

实现

  • webView基础设置
        val webView = fragment.binding.webView        webView.settings.javaScriptEnabled = true        webView.settings.builtInZoomControls = false        webView.settings.displayZoomControls = true        webView.settings.setSupportZoom(false)//不支持缩放功能        webView.scrollBarStyle = View.SCROLLBARS_INSIDE_OVERLAY //取消滚动条白边效果        webView.webChromeClient = WebChromeClient()        webView.webViewClient = MyWebViewClient()        webView.addJavascriptInterface(MJavascriptInterface(fragment.activity,fragment),"imagelistener")        webView.settings.defaultTextEncodingName = "UTF-8"        webView.settings.blockNetworkImage = false        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {            webView.settings.mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW  //注意安卓5.0以上的权限        }        if (detail.content.checkNotNull()) {            val css = ""            val html = css + "" + detail.content + ""            webView.loadDataWithBaseURL(null, ImageUtil.getNewContent(html), "text/html", "UTF-8", null)        }        webView.setOnLongClickListener(object : View.OnLongClickListener {            override fun onLongClick(v: View?): Boolean {                val result =webView.hitTestResult                if (!result.checkNotNull()) {                    return false                }                val type = result.type                when (type) {                // 超链接                    WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE,/*带有链接的图片类型*/WebView.HitTestResult.IMAGE_TYPE -> {                        // 处理长按图片的菜单项                        val coverUrl = result.extra                        if (URLUtil.isValidUrl(coverUrl) || coverUrl.startsWith("data:image")) {                            UiUtils.webViewLongClick(fragment, webView.context, coverUrl)                            return true                        }                    }                }                return false            }        })
  • webViewLongClick
    /*网页长按弹窗(识别二维码,下载图片)*/    @JvmStatic    fun webViewLongClick(fragment: BaseFragment, context: Context, coverUrl: String) {        openSelect(fragment, context, coverUrl)    }    /*网页长按弹窗(识别二维码,下载图片)*/    private fun openSelect(fragment: BaseFragment, context: Context, coverUrl: String) {        val dialog = BottomSheetDialog(context)        val layoutView = LayoutInflater.from(context).inflate(R.layout.dialog_select_qrcode_down_img, null)        layoutView.findViewById(R.id.tv_qrcode).setOnClickListener {            //图片url                  Glide.with(context.applicationContext).asBitmap().load(coverUrl)                          .into(object : SimpleTarget() {                              override fun onResourceReady(resource: Bitmap, transition: Transition?) {                                  CodeUtils.analyzeBitmap(resource, object : CodeUtils.AnalyzeCallback {                                      override fun onAnalyzeSuccess(mBitmap: Bitmap, result: String) {                                          fragment.start(WebFragment.newInstance("", result))                                      }                                      override fun onAnalyzeFailed() {                                          "未识别到二维码".toast()                                      }                                  })                                  dialog.dismiss()                              }                          })        }        layoutView.findViewById(R.id.tv_download).setOnClickListener {            if (coverUrl.startsWith("data:image")) {                var fileName: String? = null                if (MimeTypeMap.getFileExtensionFromUrl(coverUrl) == "") {                    fileName = System.currentTimeMillis().toString() + ".jpg"                } else {                    fileName = System.currentTimeMillis().toString() + "." + MimeTypeMap.getFileExtensionFromUrl(coverUrl)                }                val file = BitmapUtils.saveBitmapFile(AndroidtoJs.stringToBitmap(coverUrl), DownLoadImageRunnable.SAVE_DOWNLOAD_IMAGE_PATH + fileName)                if (file.checkNotNull()) {                    "已保存".toast()                } else {                    "保存失败".toast()                }            } else {                ImageUtil.downLoadImg(context, coverUrl)            }            dialog.dismiss()        }        dialog.setContentView(layoutView)        dialog.show()    }
  • 弹窗布局dialog_select_qrcode_down_img.xml
<?xml version="1.0" encoding="utf-8"?>            
  • MyWebViewClient
import android.graphics.Bitmap;import android.webkit.WebView;import android.webkit.WebViewClient;/** * Created by Administrator on 2017/2/10. */public class MyWebViewClient extends WebViewClient {    @Override    public void onPageFinished(WebView view, String url) {        view.getSettings().setJavaScriptEnabled(true);        super.onPageFinished(view, url);        addImageClickListener(view);//待网页加载完全后设置图片点击的监听方法    }    @Override    public void onPageStarted(WebView view, String url, Bitmap favicon) {        view.getSettings().setJavaScriptEnabled(true);        super.onPageStarted(view, url, favicon);    }    private void addImageClickListener(WebView webView) {        webView.loadUrl("javascript:(function(){" + "var objs = document.getElementsByTagName(\"img\");" +                " " + " var array=new Array(); " +                " for(var j=0;j
  • MJavascriptInterface
import android.app.Activity;import android.widget.ImageView;import com.xlj.app.global.base.BaseFragment;import com.xlj.app.widget.ninegrid.ImageInfo;import java.util.ArrayList;public class MJavascriptInterface {    private Activity context;    private BaseFragment fragment;    private static final String TAG = "SIMON";    ArrayList images = new ArrayList<>();    public MJavascriptInterface(Activity context, BaseFragment fragment) {        this.context = context;        this.fragment = fragment;    }    @android.webkit.JavascriptInterface //必须添加    public void openImage(String img, String[] array) {        int index = 0;        ArrayList imageInfo = new ArrayList<>();        for (int i = 0; i < array.length; i++) {            ImageInfo imInfo = new ImageInfo();            imInfo.thumbnailUrl = array[i];            imInfo.bigImageUrl = array[i];            imageInfo.add(imInfo);            if (array[i].equals(img)) {                index = printArray(array, img);            }        }        ImageView imageView = new ImageView(context);        fragment.previewPhoto(imageView, imageInfo, index, false, true,true);    }    //遍历数组    private int printArray(String[] array, String value) {        for (int i = 0; i < array.length; i++) {            if (array[i].equals(value)) {                return i;            }        }        return -1;//当if条件不成立时,默认返回一个负数值-1    }}
  • 大图查看
    //图片预览    fun previewPhoto(clickImageView: ImageView, imageInfo: List, index: Int, finishAnimator: Boolean = true, isShowShare: Boolean = false,isSeeCode:Boolean=false) {        if (imageInfo.isNotEmpty()) {            val info: ImageInfo = imageInfo[0]            imageInfo.forEach {                it.imageViewWidth = clickImageView.width                it.imageViewHeight = clickImageView.height                val points = IntArray(2)                clickImageView.getLocationInWindow(points)                info.imageViewX = points[0]                info.imageViewY = points[1] - StatusBarUtil.getStatusBarHeight(activity)            }            val intent = Intent(context, ImagePreviewActivity::class.java)            val bundle = Bundle()            bundle.putSerializable(ImagePreviewActivity.IMAGE_INFO, imageInfo as Serializable)            bundle.putInt(ImagePreviewActivity.CURRENT_ITEM, index)            bundle.putBoolean(ImagePreviewActivity.FINISH_ANIMATION, finishAnimator)            bundle.putBoolean(ImagePreviewActivity.IS_SHOW_SHARE, isShowShare)            bundle.putBoolean(ImagePreviewActivity.IS_SEE_CODE, isSeeCode)            intent.putExtras(bundle)            context!!.startActivity(intent)            activity!!.overridePendingTransition(0, 0)        }    }
  • 下面是图片预览的activity -----ImagePreviewActivity
import android.animation.Animator;import android.animation.ValueAnimator;import android.app.Activity;import android.content.Intent;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.Color;import android.graphics.drawable.Drawable;import android.os.Bundle;import android.support.annotation.NonNull;import android.support.annotation.Nullable;import android.support.v4.view.ViewPager;import android.util.DisplayMetrics;import android.view.View;import android.view.ViewTreeObserver;import android.widget.ImageView;import android.widget.RelativeLayout;import android.widget.TextView;import com.bigkoo.alertview.AlertView;import com.bigkoo.alertview.OnItemClickListener;import com.bumptech.glide.Glide;import com.bumptech.glide.request.target.SimpleTarget;import com.bumptech.glide.request.transition.Transition;import com.dtr.zxing.utils.CodeUtils;import com.kaopiz.kprogresshud.KProgressHUD;import com.tencent.qcloud.tim.uikit.component.photoview.downloadimg.ImageUtil;import com.tencent.qcloud.tim.uikit.utils.ToastUtil;import com.umeng.analytics.MobclickAgent;import com.umeng.socialize.UMShareAPI;import com.xlj.app.R;import com.xlj.app.global.Constant;import com.xlj.app.mvvm.main.activity.WebActivity;import com.xlj.app.mvvm.main.fragment.WebFragment;import com.xlj.app.utils.EventBusUtils;import com.xlj.app.utils.Toast.ToastUtils;import com.xlj.app.widget.ninegrid.ImageInfo;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.util.List;public class ImagePreviewActivity extends Activity implements ViewTreeObserver.OnPreDrawListener {    public static final String IMAGE_INFO = "IMAGE_INFO";    public static final String CURRENT_ITEM = "CURRENT_ITEM";    public static final String FINISH_ANIMATION = "FINISH_ANIMATION";    public static final String IS_SHOW_SHARE = "IS_SHOW_SHARE";    //是否有 识别二维码    public static final String IS_SEE_CODE = "IS_SEE_CODE";    public static final int ANIMATE_DURATION = 200;    private RelativeLayout rootView;    private ImagePreviewAdapter imagePreviewAdapter;    private List imageInfo;    private int currentItem;    private int imageHeight;    private int imageWidth;    private int screenWidth;    private int screenHeight;    private boolean isUseFinishAnimator, isShowShare, isSeeCode;    private KProgressHUD loading;    private String bigImageUrl;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_preview);        loading = KProgressHUD.create(ImagePreviewActivity.this).setStyle(KProgressHUD.Style.SPIN_INDETERMINATE).setWindowColor(ImagePreviewActivity.this.getResources().getColor(R.color.color_trans)).setCancellable(false);        ViewPager viewPager = findViewById(R.id.viewPager);        final TextView tv_pager = findViewById(R.id.tv_pager);        ImageView imgShare = findViewById(R.id.img_share);        rootView = findViewById(R.id.rootView);        DisplayMetrics metric = new DisplayMetrics();        getWindowManager().getDefaultDisplay().getMetrics(metric);        screenWidth = metric.widthPixels;        screenHeight = metric.heightPixels;        Intent intent = getIntent();        imageInfo = (List) intent.getSerializableExtra(IMAGE_INFO);        currentItem = intent.getIntExtra(CURRENT_ITEM, 0);        isUseFinishAnimator = intent.getBooleanExtra(FINISH_ANIMATION, true);        isShowShare = intent.getBooleanExtra(IS_SHOW_SHARE, false);//是否有弹窗菜单(转发。保存)        isSeeCode = intent.getBooleanExtra(IS_SEE_CODE, false);//是否有弹窗菜单(转发。保存)        imgShare.setVisibility(isShowShare ? View.VISIBLE : View.GONE);        imagePreviewAdapter = new ImagePreviewAdapter(this, imageInfo);        imagePreviewAdapter.setIsShowOrginal(isShowShare);        imagePreviewAdapter.setSeeCode(isSeeCode);        viewPager.setAdapter(imagePreviewAdapter);        viewPager.setCurrentItem(currentItem);        viewPager.getViewTreeObserver().addOnPreDrawListener(this);        viewPager.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {            @Override            public void onPageSelected(int position) {                currentItem = position;                tv_pager.setText(String.format(getString(R.string.select), currentItem + 1, imageInfo.size()));            }        });        tv_pager.setText(String.format(getString(R.string.select), currentItem + 1, imageInfo.size()));        bigImageUrl = imageInfo.get(currentItem).thumbnailUrl;        imgShare.setOnClickListener(v -> {            if (bigImageUrl != null && !"".equals(bigImageUrl)) {                menuPop(v, bigImageUrl);            }//            DialogUtils.umShare(ImagePreviewActivity.this,imgShare.getContext(),bigImageUrl,"分享到", loading);/*            new Thread(() -> ImageUtil.url2Bitmap(ImagePreviewActivity.this, bigImageUrl, new ImageUtil.GetCallBackInterface() {                @Override                public void onSuccess(Bitmap bitmap) {                    //点击分享                    if (bitmap != null) {                        runOnUiThread(() -> DialogUtils.shareWeChatDialog(ImagePreviewActivity.this, bitmap, "分享到").show());                    }                }                @Override                public void onFail(String s) {                }            })).start();*/        });    }    private void menuPop(View v, String bigImageUrl) {        if (isSeeCode) {            showSeeCodeDialog(v);            return;        }        new AlertView("操作", null, "取消", null, new String[]{"转发", "保存"}, v.getContext(), AlertView.Style.ActionSheet, new OnItemClickListener() {            @Override            public void onItemClick(Object o, int position) {                if (position == -1) return;                if (position == 0) {                    //转发                    if (currentItem == -1) return;                    EventBusUtils.forwordImgMessage(currentItem);                    onBackPressed();                } else {                    if (bigImageUrl.contains("http")) {                        ImageUtil.downLoadImg(ImagePreviewActivity.this, bigImageUrl);                    } else {                        try {                            FileInputStream fis = new FileInputStream(bigImageUrl);                            Bitmap bitmap = BitmapFactory.decodeStream(fis);                            boolean succ = ImageUtil.saveImageToGallery(ImagePreviewActivity.this, bitmap);                            String tip = "";                            if (succ) {                                tip = "已保存到相册";                            } else {                                tip = "保存失败";                            }                            ToastUtil.toastShortMessage(tip);                        } catch (FileNotFoundException e) {                            e.printStackTrace();                        }                    }                }            }        }).setCancelable(true).show();    }    private void showSeeCodeDialog(View v) {        new AlertView("操作", null, "取消", null, new String[]{"识别二维码", "保存"}, v.getContext(), AlertView.Style.ActionSheet, new OnItemClickListener() {            @Override            public void onItemClick(Object o, int position) {                if (position == -1) return;                if (position == 0) {                    // 识别二维码                    Glide.with(v.getContext()).asBitmap().load(bigImageUrl)                            .into(new SimpleTarget() {                                @Override                                public void onResourceReady(@NonNull Bitmap resource, @Nullable Transition<? super Bitmap> transition) {                                    CodeUtils.analyzeBitmap(resource, new CodeUtils.AnalyzeCallback() {                                        @Override                                        public void onAnalyzeSuccess(Bitmap mBitmap, String result) {                                            WebActivity.Companion.start(v.getContext(),result,"");                                        }                                        @Override                                        public void onAnalyzeFailed() {                                            ToastUtils.showShortToast(v.getContext(), "未识别到二维码");                                        }                                    });                                }                            });                } else {                    if (bigImageUrl.contains("http")) {                        ImageUtil.downLoadImg(ImagePreviewActivity.this, bigImageUrl);                    } else {                        try {                            FileInputStream fis = new FileInputStream(bigImageUrl);                            Bitmap bitmap = BitmapFactory.decodeStream(fis);                            boolean succ = ImageUtil.saveImageToGallery(ImagePreviewActivity.this, bitmap);                            String tip = "";                            if (succ) {                                tip = "已保存到相册";                            } else {                                tip = "保存失败";                            }                            ToastUtil.toastShortMessage(tip);                        } catch (FileNotFoundException e) {                            e.printStackTrace();                        }                    }                }            }        }).setCancelable(true).show();    }    @Override    public void onBackPressed() {        finishActivityAnim();    }    /**     * 绘制前开始动画     */    @Override    public boolean onPreDraw() {        rootView.getViewTreeObserver().removeOnPreDrawListener(this);        final View view = imagePreviewAdapter.getPrimaryItem();        final ImageView imageView = imagePreviewAdapter.getPrimaryImageView();        computeImageWidthAndHeight(imageView);        final ImageInfo imageData = imageInfo.get(currentItem);        final float vx = imageData.imageViewWidth * 1.0f / imageWidth;        final float vy = imageData.imageViewHeight * 1.0f / imageHeight;        ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1.0f);        valueAnimator.addUpdateListener(animation -> {            long duration = animation.getDuration();            long playTime = animation.getCurrentPlayTime();            float fraction = duration > 0 ? (float) playTime / duration : 1f;            if (fraction > 1) {                fraction = 1;            }            view.setTranslationX(evaluateInt(fraction, imageData.imageViewX + imageData.imageViewWidth / 2 - imageView.getWidth() / 2, 0));            view.setTranslationY(evaluateInt(fraction, imageData.imageViewY + imageData.imageViewHeight / 2 - imageView.getHeight() / 2, 0));            view.setScaleX(evaluateFloat(fraction, vx, 1));            view.setScaleY(evaluateFloat(fraction, vy, 1));            view.setAlpha(fraction);            rootView.setBackgroundColor(evaluateArgb(fraction, Color.TRANSPARENT, Color.BLACK));        });        addIntoListener(valueAnimator);        valueAnimator.setDuration(ANIMATE_DURATION);        valueAnimator.start();        return true;    }    @Override    protected void onResume() {        super.onResume();        MobclickAgent.onPageStart(this.getClass().getSimpleName());        MobclickAgent.onResume(this);        if (loading.isShowing()) {            loading.dismiss();        }    }    @Override    protected void onPause() {        super.onPause();        MobclickAgent.onPageEnd(this.getClass().getSimpleName());        MobclickAgent.onPause(this);    }    public void longClick(View v) {        if (!isShowShare) return;//        if (bigImageUrl != null && !"".equals(bigImageUrl)) {            menuPop(v, bigImageUrl);        }    }    /**     * activity的退场动画     */    public void finishActivityAnim() {        if (!isUseFinishAnimator) {            finish();            overridePendingTransition(0, 0);        } else {            final View view = imagePreviewAdapter.getPrimaryItem();            final ImageView imageView = imagePreviewAdapter.getPrimaryImageView();            computeImageWidthAndHeight(imageView);            final ImageInfo imageData = imageInfo.get(currentItem);            final float vx = imageData.imageViewWidth * 1.0f / imageWidth;            final float vy = imageData.imageViewHeight * 1.0f / imageHeight;            final ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1.0f);            valueAnimator.addUpdateListener(animation -> {                long duration = animation.getDuration();                long playTime = animation.getCurrentPlayTime();                float fraction = duration > 0 ? (float) playTime / duration : 1f;                if (fraction > 1) {                    fraction = 1;                }                view.setTranslationX(evaluateInt(fraction, 0, imageData.imageViewX + imageData.imageViewWidth / 2 - imageView.getWidth() / 2));                view.setTranslationY(evaluateInt(fraction, 0, imageData.imageViewY + imageData.imageViewHeight / 2 - imageView.getHeight() / 2));                view.setScaleX(evaluateFloat(fraction, 1, vx));                view.setScaleY(evaluateFloat(fraction, 1, vy));                view.setAlpha(1 - fraction);                rootView.setBackgroundColor(evaluateArgb(fraction, Color.BLACK, Color.TRANSPARENT));            });            addOutListener(valueAnimator);            valueAnimator.setDuration(ANIMATE_DURATION);            valueAnimator.start();        }    }    /**     * 计算图片的宽高     */    private void computeImageWidthAndHeight(ImageView imageView) {        // 获取真实大小        Drawable drawable = imageView.getDrawable();        int intrinsicHeight = drawable.getIntrinsicHeight();        int intrinsicWidth = drawable.getIntrinsicWidth();        // 计算出与屏幕的比例,用于比较以宽的比例为准还是高的比例为准,因为很多时候不是高度没充满,就是宽度没充满        float h = screenHeight * 1.0f / intrinsicHeight;        float w = screenWidth * 1.0f / intrinsicWidth;        if (h > w) h = w;        else w = h;        // 得出当宽高至少有一个充满的时候图片对应的宽高        imageHeight = (int) (intrinsicHeight * h);        imageWidth = (int) (intrinsicWidth * w);    }    /**     * 进场动画过程监听     */    private void addIntoListener(ValueAnimator valueAnimator) {        valueAnimator.addListener(new Animator.AnimatorListener() {            @Override            public void onAnimationStart(Animator animation) {                rootView.setBackgroundColor(0x0);            }            @Override            public void onAnimationEnd(Animator animation) {            }            @Override            public void onAnimationCancel(Animator animation) {            }            @Override            public void onAnimationRepeat(Animator animation) {            }        });    }    /**     * 退场动画过程监听     */    private void addOutListener(ValueAnimator valueAnimator) {        valueAnimator.addListener(new Animator.AnimatorListener() {            @Override            public void onAnimationStart(Animator animation) {                rootView.setBackgroundColor(0x0);            }            @Override            public void onAnimationEnd(Animator animation) {                finish();                overridePendingTransition(0, 0);            }            @Override            public void onAnimationCancel(Animator animation) {            }            @Override            public void onAnimationRepeat(Animator animation) {            }        });    }    /**     * Integer 估值器     */    public Integer evaluateInt(float fraction, Integer startValue, Integer endValue) {        int startInt = startValue;        return (int) (startInt + fraction * (endValue - startInt));    }    /**     * Float 估值器     */    public Float evaluateFloat(float fraction, Number startValue, Number endValue) {        float startFloat = startValue.floatValue();        return startFloat + fraction * (endValue.floatValue() - startFloat);    }    /**     * Argb 估值器     */    public int evaluateArgb(float fraction, int startValue, int endValue) {        int startA = (startValue >> 24) & 0xff;        int startR = (startValue >> 16) & 0xff;        int startG = (startValue >> 8) & 0xff;        int startB = startValue & 0xff;        int endA = (endValue >> 24) & 0xff;        int endR = (endValue >> 16) & 0xff;        int endG = (endValue >> 8) & 0xff;        int endB = endValue & 0xff;        return (startA + (int) (fraction * (endA - startA))) << 24                | (startR + (int) (fraction * (endR - startR))) << 16                | (startG + (int) (fraction * (endG - startG))) << 8                | (startB + (int) (fraction * (endB - startB)));    }    @Override    protected void onActivityResult(int requestCode, int resultCode, Intent data) {        super.onActivityResult(requestCode, resultCode, data);        UMShareAPI.get(this).onActivityResult(requestCode, resultCode, data);    }}
  • 预览的xml文件activity_preview.xml
<?xml version="1.0" encoding="utf-8"?>            
  • 用到了一个自定义的HackyViewPager
import android.content.Context;import android.support.v4.view.ViewPager;import android.util.AttributeSet;import android.view.MotionEvent;/** 修复图片在ViewPager控件中缩放报错的BUG */public class HackyViewPager extends ViewPager {    public HackyViewPager(Context context) {        super(context);    }    public HackyViewPager(Context context, AttributeSet attrs) {        super(context, attrs);    }    @Override    public boolean onTouchEvent(MotionEvent ev) {        try {            return super.onTouchEvent(ev);        } catch (IllegalArgumentException ex) {            ex.printStackTrace();        }        return false;    }    @Override    public boolean onInterceptTouchEvent(MotionEvent ev) {        try {            return super.onInterceptTouchEvent(ev);        } catch (IllegalArgumentException ex) {            ex.printStackTrace();        }        return false;    }}

参考链接

  • Android 实现WebView点击图片查看大图列表及图片保存
  • webview 获取html中所有的图片资源并给图片添加点击事件
  • android 获取webview中所有的图片
  • Android-通过WebView获取html内容

更多相关文章

  1. Android中ConvenientBanner的使用
  2. Android(安卓)学习笔记(十五):Activity-GalleryView
  3. 6.22 android计算字符高度宽度,红蓝3D图片的制作原理及NDK生成实
  4. 学习笔记-android imageSwitcher使用
  5. 图片加载和处理的又一个神器 Fresco 的使用摘要记录
  6. android 拍照图片旋转问题
  7. Android(安卓)实现图片圆角
  8. Android简单模糊背景和圆形ImageView
  9. Android调用相机拍照获取原始照片

随机推荐

  1. Gallery自动循环滚动以及手动滚动的平滑
  2. 全套Java、Android、HTML5、前端视频,史上
  3. android 面试经典(5)
  4. Android中的支付(支付宝)
  5. Android防止重复点击的解决办法
  6. android 使用 service 实现音乐
  7. 2012年4月7日学习记录
  8. 拿来主义Android优秀开源项目(二)
  9. 免费Android客户端静态代码安全分析工具
  10. Android抓包分析-fiddler版