android逆向分析之smali练习

来源:互联网 发布:淘宝售假三次 编辑:程序博客网 时间:2024/04/29 23:02

一、工具

第一章节分析了smali的语法

个人比较喜欢Sublime Text 2,多种语言的语法高亮,smali的语法插件,



二、java内部内访问外部类的私有属性补习

有的人不懂反编译后出现的this$0或者access$0等,如果你知道,就跳过该小节。

说起这个就要说java内部内是如何访问外部类的私有属性(private)的。

注意一点:java源码经过编译后无论是外部类还是内部类都是单独的文件,只不过内部类和它的外部类在同一目录。

OutClass源码

public class OutClass {private int temp1 = 1;private int temp2 = 2;private int temp3 = 3;private static int staticTemp4 = 4;private static int staticTemp5 = 5;private static int staticTemp6 = 6;public int temp7 = 7;private void setData(int data) {this.temp1 = data;}static class Inner01 {void getData() {System.out.println(staticTemp4);System.out.println(staticTemp5);System.out.println(staticTemp6);}}class Inner02 {void getData() {System.out.println(temp1);System.out.println(temp2);System.out.println(temp3);System.out.println(temp7);setData(12);}}}
我们在代码运行时利用反射

OutClass的反射后的代码

class OutClass{   public OutClass();   private void setData(int);   static int access$0();   static int access$1();   static int access$2();   static int access$3(OutClass);   static int access$4(OutClass);   static int access$5(OutClass);   static void access$6(OutClass,int);   private int temp1;   private int temp2;   private int temp3;   private static int staticTemp4;   private static int staticTemp5;   private static int staticTemp6;   public int temp7;}

看的出多了几个access$#的方法。其实access$#和一般的方法一样,但是它是static ,可以通过类名直接访问。

Inner01反射后的代码

Inner01是静态内部类,不会有外部类的引用,所以在构造函数里就不会有OutClass这个引用。


class OutClass$Inner01{    OutClass$Inner01();    void getData();}

Inner02反射后的代码

Inner02是非静态的,当我们Inner02 inner = new Inner02( )的时候,其实早就换成了

OutClass$Inner02 inner = new  OutClass$Inner02(this);

这样非静态的内部类就把外部类的引用传递进来了,保存在this$0 这个变量中。



class OutClass$Inner02{    OutClass$Inner02(OutClass);    void getData();   final OutClass this$0;}

看到了吗!静态内部类与非静态内部类也不一样

为了看的更清楚,我们对class字节码进行反编译,需要知道一点jVM指令

反编译OutClass.class

E:\eclipse-rcp-indigo-SR1-win32-x86_64\workspace\ReflectTest\bin>javap -c OutClass.classCompiled from "OutClass.java"public class OutClass {  public int temp7;  static {};    Code:       0: iconst_4       1: putstatic     #16                 // Field staticTemp4:I       4: iconst_5       5: putstatic     #18                 // Field staticTemp5:I       8: bipush        6      10: putstatic     #20                 // Field staticTemp6:I      13: return  public OutClass();    Code:       0: aload_0                           //aload_0,第一个参数,就是this       1: invokespecial #25                 // Method java/lang/Object."<init>":()V       4: aload_0       5: iconst_1       6: putfield      #27                 // Field temp1:I       9: aload_0      10: iconst_2      11: putfield      #29                 // Field temp2:I      14: aload_0      15: iconst_3      16: putfield      #31                 // Field temp3:I      19: aload_0      20: bipush        7      22: putfield      #33                 // Field temp7:I      25: return  static int access$0();                     Code:       0: getstatic     #16                 // Field staticTemp4:I       3: ireturn  static int access$1();    Code:       0: getstatic     #18                 // Field staticTemp5:I       3: ireturn  static int access$2();    Code:       0: getstatic     #20                 // Field staticTemp6:I       3: ireturn  static int access$3(OutClass);    Code:       0: aload_0       1: getfield      #27                 // Field temp1:I       4: ireturn  static int access$4(OutClass);    Code:       0: aload_0       1: getfield      #29                 // Field temp2:I       4: ireturn  static int access$5(OutClass);    Code:       0: aload_0       1: getfield      #31                 // Field temp3:I       4: ireturn  static void access$6(OutClass, int);    Code:       0: aload_0       1: iload_1       2: invokespecial #50                 // Method setData:(I)V       5: return}


反编译Inner01.class


E:\eclipse-rcp-indigo-SR1-win32-x86_64\workspace\ReflectTest\bin>javap -c OutClass$Inner01.classCompiled from "OutClass.java"class OutClass$Inner01 {  OutClass$Inner01();    Code:       0: aload_0                                    1: invokespecial #8                  // Method java/lang/Object."<init>":()V       4: return  void getData();    Code:       0: getstatic     #15                 // Field java/lang/System.out:Ljava/io/PrintStream;       3: invokestatic  #21                 // Method OutClass.access$0:()I       6: invokevirtual #27                 // Method java/io/PrintStream.println:(I)V       9: getstatic     #15                 // Field java/lang/System.out:Ljava/io/PrintStream;      12: invokestatic  #33                 // Method OutClass.access$1:()I      15: invokevirtual #27                 // Method java/io/PrintStream.println:(I)V      18: getstatic     #15                 // Field java/lang/System.out:Ljava/io/PrintStream;      21: invokestatic  #36                 // Method OutClass.access$2:()I      24: invokevirtual #27                 // Method java/io/PrintStream.println:(I)V      27: return}

反编译Inner02.class

E:\eclipse-rcp-indigo-SR1-win32-x86_64\workspace\ReflectTest\bin>javap -c OutClass$Inner02.classCompiled from "OutClass.java"class OutClass$Inner02 {  final OutClass this$0;  OutClass$Inner02(OutClass);    Code:       0: aload_0       1: aload_1       2: putfield      #10                 // Field this$0:LOutClass;       5: aload_0       6: invokespecial #12                 // Method java/lang/Object."<init>":()V       9: return  void getData();    Code:       0: getstatic     #20                 // Field java/lang/System.out:Ljava/io/PrintStream;       3: aload_0       4: getfield      #10                 // Field this$0:LOutClass;       7: invokestatic  #26                 // Method OutClass.access$3:(LOutClass;)I      10: invokevirtual #32                 // Method java/io/PrintStream.println:(I)V      13: getstatic     #20                 // Field java/lang/System.out:Ljava/io/PrintStream;      16: aload_0      17: getfield      #10                 // Field this$0:LOutClass;      20: invokestatic  #38                 // Method OutClass.access$4:(LOutClass;)I      23: invokevirtual #32                 // Method java/io/PrintStream.println:(I)V      26: getstatic     #20                 // Field java/lang/System.out:Ljava/io/PrintStream;      29: aload_0      30: getfield      #10                 // Field this$0:LOutClass;      33: invokestatic  #41                 // Method OutClass.access$5:(LOutClass;)I      36: invokevirtual #32                 // Method java/io/PrintStream.println:(I)V      39: getstatic     #20                 // Field java/lang/System.out:Ljava/io/PrintStream;      42: aload_0      43: getfield      #10                 // Field this$0:LOutClass;      46: getfield      #44                 // Field OutClass.temp7:I      49: invokevirtual #32                 // Method java/io/PrintStream.println:(I)V      52: aload_0      53: getfield      #10                 // Field this$0:LOutClass;      56: bipush        12      58: invokestatic  #48                 // Method OutClass.access$6:(LOutClass;I)V      61: return}

    非静态内部类中会有一个外部类的引用,this$0(内部类的嵌套可能会叫this$1),但是不能靠这个引用来访问外部类的私有域。那么非静态内部类是如何大摇大摆的访问外部类的私有域的呢?


  1)、非静态内部类访问外部类的字段,

     System.out.println(temp2);

      16: aload_0                           // this指的是<span style="font-size: 18px;">Inner02</span><span style="font-size: 14px; font-family: Arial, Helvetica, sans-serif;">这个类的实例</span>      17: getfield      #10                 // Field this$0:LOutClass;      20: invokestatic  #38                 // Method OutClass.access$4:(LOutClass;)I      23: invokevirtual #32                 // Method java/io/PrintStream.println:(I)V      26: getstatic     #20                 // Field java/lang/System.out:Ljava/io/PrintStream;

其实就是this$0.access$4(this$0)来获取temp2的值。access$#都是静态的,所以用类的实例来调用是可以的。

  2)、非静态内部类访问外部类的私有方法

  setData(12);

      52: aload_0                            //<span style="font-family: Arial, Helvetica, sans-serif;">this指的是</span><span style="font-family: Arial, Helvetica, sans-serif;"><span style="font-size:14px;">Inner02这个类的实例</span></span>      53: getfield      #10                 // Field this$0:LOutClass;      56: bipush        12      58: invokestatic  #48                 // Method OutClass.access$6:(LOutClass;I)V
其实就是调用this$0.access$6(this$0,12),将参数12传递过去。

  3)、静态内部类访问外部类的字段

           静态内部类只能访问外部类的静态属性(static,因为没有外部类的引用,只能靠外部类的类名访问)。

           静态内部类是没有外部类的引用的

    System.out.println(staticTemp5);

       9: getstatic     #15                 // Field java/lang/System.out:Ljava/io/PrintStream;      12: invokestatic  #33                 // Method OutClass.access$1:()I      15: invokevirtual #27                 // Method java/io/PrintStream.println:(I)V
      
   虽然没有引用,但是靠外部类的类名访问相应的access$#(  )方法可以操控外部类的静态字段。


  4)、静态内部类访问外部类的方法

          只能访问外部类的静方法,依然靠access$#(  )访问。


总结:静态的还是非静态的都是靠access方法访问,至于$后面的数字是根据私有属性的初始化位置来的(静态的早于非静态)。

smali里使内部类访问外部类的私有成员,编译器生成了形似 “外部类.access$XYZ”的函数。XYZ为数字。X是按照私有成员在内部类出现的顺序递增的。YZ为02的话,标明是基本变量成员;YZ为00的话标明是对象成员或者函数。


三、练习

我们拿魅族的应用中心做试验,来反编译一个可以折叠的TextView。

.class public Lcom/meizu/common/widget/FoldableTextView;.super Landroid/widget/TextView;.source "FoldableTextView.java"# interfaces.implements Landroid/view/View$OnClickListener;# annotations.annotation system Ldalvik/annotation/MemberClasses;    value = {        Lcom/meizu/common/widget/FoldableTextView$FoldingListener;,        Lcom/meizu/common/widget/FoldableTextView$MoreClickSpan;    }.end annotation# static fields.field private static final DEBUG:Z = false.field private static final ELLIPSIS_TWO_DOTS:Ljava/lang/String; = "\u2025".field private static final TAG:Ljava/lang/String; = "FoldableTextView"# instance fields.field private mAlignViewEdge:Z.field private mClickToFold:Z.field private mEllipseText:Ljava/lang/CharSequence;.field private mFoldLineMax:I.field private mIsClickSpan:Z.field private mIsfolded:Z.field private mLinkColor:I.field private mListener:Lcom/meizu/common/widget/FoldableTextView$FoldingListener;.field private mUnfoldText:Ljava/lang/CharSequence;.field private mainText:Ljava/lang/CharSequence;# direct methods.method public constructor <init>(Landroid/content/Context;)V    .locals 1    .param p1, "context"    # Landroid/content/Context;    .prologue    .line 48    const/4 v0, 0x0    invoke-direct {p0, p1, v0}, Lcom/meizu/common/widget/FoldableTextView;-><init>(Landroid/content/Context;Landroid/util/AttributeSet;)V    .line 49    return-void.end method.method public constructor <init>(Landroid/content/Context;Landroid/util/AttributeSet;)V    .locals 1    .param p1, "context"    # Landroid/content/Context;    .param p2, "attrs"    # Landroid/util/AttributeSet;    .prologue    .line 52    sget v0, Lcom/meizu/common/R$style;->Widget_MeizuCommon_FoldableTextView:I    invoke-direct {p0, p1, p2, v0}, Lcom/meizu/common/widget/FoldableTextView;-><init>(Landroid/content/Context;Landroid/util/AttributeSet;I)V    .line 53    return-void.end method.method public constructor <init>(Landroid/content/Context;Landroid/util/AttributeSet;I)V    .locals 8    .param p1, "context"    # Landroid/content/Context;    .param p2, "attrs"    # Landroid/util/AttributeSet;    .param p3, "defStyle"    # I    .prologue    const/4 v7, -0x1    const/4 v6, 0x1    const/4 v5, 0x0    .line 56    invoke-direct {p0, p1, p2, p3}, Landroid/widget/TextView;-><init>(Landroid/content/Context;Landroid/util/AttributeSet;I)V    .line 39    iput-boolean v6, p0, Lcom/meizu/common/widget/FoldableTextView;->mIsfolded:Z    .line 40    iput-boolean v5, p0, Lcom/meizu/common/widget/FoldableTextView;->mAlignViewEdge:Z    .line 41    iput-boolean v5, p0, Lcom/meizu/common/widget/FoldableTextView;->mIsClickSpan:Z    .line 42    iput-boolean v6, p0, Lcom/meizu/common/widget/FoldableTextView;->mClickToFold:Z    .line 43    iput v7, p0, Lcom/meizu/common/widget/FoldableTextView;->mLinkColor:I    .line 57    sget-object v4, Lcom/meizu/common/R$styleable;->FoldableTextView:[I    invoke-virtual {p1, p2, v4, p3, v5}, Landroid/content/Context;->obtainStyledAttributes(Landroid/util/AttributeSet;[III)Landroid/content/res/TypedArray;    move-result-object v0    .line 59    .local v0, "a":Landroid/content/res/TypedArray;    invoke-virtual {v0}, Landroid/content/res/TypedArray;->getIndexCount()I    move-result v3    .line 60    .local v3, "n":I    const/4 v2, 0x0    .local v2, "i":I    :goto_0    if-ge v2, v3, :cond_7    .line 61    invoke-virtual {v0, v2}, Landroid/content/res/TypedArray;->getIndex(I)I    move-result v1    .line 62    .local v1, "attr":I    sget v4, Lcom/meizu/common/R$styleable;->FoldableTextView_mzTextEllipse:I    if-ne v1, v4, :cond_1    .line 63    invoke-virtual {v0, v1}, Landroid/content/res/TypedArray;->getText(I)Ljava/lang/CharSequence;    move-result-object v4    iput-object v4, p0, Lcom/meizu/common/widget/FoldableTextView;->mEllipseText:Ljava/lang/CharSequence;    .line 60    :cond_0    :goto_1    add-int/lit8 v2, v2, 0x1    goto :goto_0    .line 64    :cond_1    sget v4, Lcom/meizu/common/R$styleable;->FoldableTextView_mzTextUnfold:I    if-ne v1, v4, :cond_2    .line 65    invoke-virtual {v0, v1}, Landroid/content/res/TypedArray;->getText(I)Ljava/lang/CharSequence;    move-result-object v4    iput-object v4, p0, Lcom/meizu/common/widget/FoldableTextView;->mUnfoldText:Ljava/lang/CharSequence;    goto :goto_1    .line 66    :cond_2    sget v4, Lcom/meizu/common/R$styleable;->FoldableTextView_mzMaxFoldLine:I    if-ne v1, v4, :cond_3    .line 67    invoke-virtual {v0, v1, v5}, Landroid/content/res/TypedArray;->getInt(II)I    move-result v4    iput v4, p0, Lcom/meizu/common/widget/FoldableTextView;->mFoldLineMax:I    goto :goto_1    .line 68    :cond_3    sget v4, Lcom/meizu/common/R$styleable;->FoldableTextView_mzUnfoldAlignViewEdge:I    if-ne v1, v4, :cond_4    .line 69    invoke-virtual {v0, v1, v5}, Landroid/content/res/TypedArray;->getBoolean(IZ)Z    move-result v4    iput-boolean v4, p0, Lcom/meizu/common/widget/FoldableTextView;->mAlignViewEdge:Z    goto :goto_1    .line 70    :cond_4    sget v4, Lcom/meizu/common/R$styleable;->FoldableTextView_mzClickToFold:I    if-ne v1, v4, :cond_5    .line 71    invoke-virtual {v0, v1, v5}, Landroid/content/res/TypedArray;->getBoolean(IZ)Z    move-result v4    iput-boolean v4, p0, Lcom/meizu/common/widget/FoldableTextView;->mClickToFold:Z    goto :goto_1    .line 72    :cond_5    sget v4, Lcom/meizu/common/R$styleable;->FoldableTextView_mzLinkColor:I    if-ne v1, v4, :cond_6    .line 73    invoke-virtual {v0, v1, v7}, Landroid/content/res/TypedArray;->getColor(II)I    move-result v4    iput v4, p0, Lcom/meizu/common/widget/FoldableTextView;->mLinkColor:I    goto :goto_1    .line 74    :cond_6    sget v4, Lcom/meizu/common/R$styleable;->FoldableTextView_mzIsFold:I    if-ne v1, v4, :cond_0    .line 75    invoke-virtual {v0, v1, v6}, Landroid/content/res/TypedArray;->getBoolean(IZ)Z    move-result v4    iput-boolean v4, p0, Lcom/meizu/common/widget/FoldableTextView;->mIsfolded:Z    goto :goto_1    .line 78    .end local v1    # "attr":I    :cond_7    invoke-virtual {v0}, Landroid/content/res/TypedArray;->recycle()V    .line 79    iget-object v4, p0, Lcom/meizu/common/widget/FoldableTextView;->mUnfoldText:Ljava/lang/CharSequence;    invoke-static {v4}, Landroid/text/TextUtils;->isEmpty(Ljava/lang/CharSequence;)Z    move-result v4    if-eqz v4, :cond_8    .line 80    sget v4, Lcom/meizu/common/R$string;->more_item_label:I    invoke-virtual {p1, v4}, Landroid/content/Context;->getString(I)Ljava/lang/String;    move-result-object v4    iput-object v4, p0, Lcom/meizu/common/widget/FoldableTextView;->mUnfoldText:Ljava/lang/CharSequence;    .line 85    :cond_8    iget-object v4, p0, Lcom/meizu/common/widget/FoldableTextView;->mEllipseText:Ljava/lang/CharSequence;    invoke-static {v4}, Landroid/text/TextUtils;->isEmpty(Ljava/lang/CharSequence;)Z    move-result v4    if-eqz v4, :cond_9    .line 86    const-string v4, "\u2025"    iput-object v4, p0, Lcom/meizu/common/widget/FoldableTextView;->mEllipseText:Ljava/lang/CharSequence;    .line 89    :cond_9    invoke-static {}, Landroid/text/method/LinkMovementMethod;->getInstance()Landroid/text/method/MovementMethod;    move-result-object v4    invoke-virtual {p0, v4}, Lcom/meizu/common/widget/FoldableTextView;->setMovementMethod(Landroid/text/method/MovementMethod;)V    .line 90    invoke-direct {p0, v6}, Lcom/meizu/common/widget/FoldableTextView;->setOnClickListener(Z)V    .line 91    return-void.end method.method static synthetic access$100(Lcom/meizu/common/widget/FoldableTextView;)I    .locals 1    .param p0, "x0"    # Lcom/meizu/common/widget/FoldableTextView;    .prologue    .line 33    iget v0, p0, Lcom/meizu/common/widget/FoldableTextView;->mLinkColor:I    return v0.end method.method static synthetic access$200(Lcom/meizu/common/widget/FoldableTextView;)Lcom/meizu/common/widget/FoldableTextView$FoldingListener;    .locals 1    .param p0, "x0"    # Lcom/meizu/common/widget/FoldableTextView;    .prologue    .line 33    iget-object v0, p0, Lcom/meizu/common/widget/FoldableTextView;->mListener:Lcom/meizu/common/widget/FoldableTextView$FoldingListener;    return-object v0.end method.method static synthetic access$302(Lcom/meizu/common/widget/FoldableTextView;Z)Z    .locals 0    .param p0, "x0"    # Lcom/meizu/common/widget/FoldableTextView;    .param p1, "x1"    # Z    .prologue    .line 33    iput-boolean p1, p0, Lcom/meizu/common/widget/FoldableTextView;->mIsfolded:Z    return p1.end method.method static synthetic access$402(Lcom/meizu/common/widget/FoldableTextView;Z)Z    .locals 0    .param p0, "x0"    # Lcom/meizu/common/widget/FoldableTextView;    .param p1, "x1"    # Z    .prologue    .line 33    iput-boolean p1, p0, Lcom/meizu/common/widget/FoldableTextView;->mIsClickSpan:Z    return p1.end method.method private foldText(Ljava/lang/CharSequence;)Ljava/lang/CharSequence;    .locals 14    .param p1, "text"    # Ljava/lang/CharSequence;    .prologue    .line 205    invoke-virtual {p0}, Lcom/meizu/common/widget/FoldableTextView;->getLayout()Landroid/text/Layout;    move-result-object v11    .line 206    .local v11, "layout":Landroid/text/Layout;    new-instance v1, Landroid/text/SpannableStringBuilder;    invoke-direct {v1, p1}, Landroid/text/SpannableStringBuilder;-><init>(Ljava/lang/CharSequence;)V    .line 207    .local v1, "sb":Landroid/text/SpannableStringBuilder;    new-instance v0, Landroid/text/DynamicLayout;    invoke-virtual {v11}, Landroid/text/Layout;->getPaint()Landroid/text/TextPaint;    move-result-object v2    invoke-virtual {v11}, Landroid/text/Layout;->getWidth()I    move-result v3    invoke-virtual {v11}, Landroid/text/Layout;->getAlignment()Landroid/text/Layout$Alignment;    move-result-object v4    const/high16 v5, 0x3f800000    # 1.0f    const/4 v6, 0x0    const/4 v7, 0x0    invoke-direct/range {v0 .. v7}, Landroid/text/DynamicLayout;-><init>(Ljava/lang/CharSequence;Landroid/text/TextPaint;ILandroid/text/Layout$Alignment;FFZ)V    .line 209    .local v0, "tmpLayout":Landroid/text/DynamicLayout;    invoke-virtual {v0}, Landroid/text/DynamicLayout;->getLineCount()I    move-result v2    iget v3, p0, Lcom/meizu/common/widget/FoldableTextView;->mFoldLineMax:I    if-gt v2, v3, :cond_0    .line 253    .end local p1    # "text":Ljava/lang/CharSequence;    :goto_0    return-object p1    .line 214    .restart local p1    # "text":Ljava/lang/CharSequence;    :cond_0    iget v13, p0, Lcom/meizu/common/widget/FoldableTextView;->mFoldLineMax:I    .line 215    .local v13, "lineMax":I    :goto_1    const/4 v2, 0x1    if-le v13, v2, :cond_1    .line 216    add-int/lit8 v12, v13, -0x1    .line 217    .local v12, "line":I    invoke-virtual {v0, v12}, Landroid/text/DynamicLayout;->getLineStart(I)I    move-result v2    invoke-virtual {v0, v12}, Landroid/text/DynamicLayout;->getLineVisibleEnd(I)I    move-result v3    if-ge v2, v3, :cond_4    .line 223    .end local v12    # "line":I    :cond_1    add-int/lit8 v2, v13, -0x1    invoke-virtual {v0, v2}, Landroid/text/DynamicLayout;->getLineVisibleEnd(I)I    move-result v10    .line 224    .local v10, "en":I    iget-object v2, p0, Lcom/meizu/common/widget/FoldableTextView;->mEllipseText:Ljava/lang/CharSequence;    invoke-static {v2}, Landroid/text/TextUtils;->isEmpty(Ljava/lang/CharSequence;)Z    move-result v2    if-eqz v2, :cond_5    .line 225    invoke-virtual {v1}, Landroid/text/SpannableStringBuilder;->length()I    move-result v2    invoke-virtual {v1, v10, v2}, Landroid/text/SpannableStringBuilder;->delete(II)Landroid/text/SpannableStringBuilder;    .line 229    :goto_2    const/16 v2, 0x20    invoke-virtual {v1, v2}, Landroid/text/SpannableStringBuilder;->append(C)Landroid/text/SpannableStringBuilder;    .line 231    invoke-virtual {v1}, Landroid/text/SpannableStringBuilder;->length()I    move-result v8    .line 232    .local v8, "addIndex":I    iget-object v2, p0, Lcom/meizu/common/widget/FoldableTextView;->mUnfoldText:Ljava/lang/CharSequence;    invoke-virtual {v1, v2}, Landroid/text/SpannableStringBuilder;->append(Ljava/lang/CharSequence;)Landroid/text/SpannableStringBuilder;    .line 233    new-instance v2, Lcom/meizu/common/widget/FoldableTextView$MoreClickSpan;    invoke-direct {v2, p0, p1}, Lcom/meizu/common/widget/FoldableTextView$MoreClickSpan;-><init>(Lcom/meizu/common/widget/FoldableTextView;Ljava/lang/CharSequence;)V    invoke-virtual {v1}, Landroid/text/SpannableStringBuilder;->length()I    move-result v3    const/16 v4, 0x21    invoke-virtual {v1, v2, v8, v3, v4}, Landroid/text/SpannableStringBuilder;->setSpan(Ljava/lang/Object;III)V    .line 236    if-lez v10, :cond_6    invoke-virtual {v0}, Landroid/text/DynamicLayout;->getLineCount()I    move-result v2    if-le v2, v13, :cond_6    .line 237    move v9, v10    .line 239    .local v9, "delIndex":I    :cond_2    add-int/lit8 v9, v9, -0x1    .line 240    add-int/lit8 v2, v9, 0x1    invoke-virtual {v1, v9, v2}, Landroid/text/SpannableStringBuilder;->delete(II)Landroid/text/SpannableStringBuilder;    .line 241    if-lez v9, :cond_3    invoke-virtual {v0}, Landroid/text/DynamicLayout;->getLineCount()I    move-result v2    if-gt v2, v13, :cond_2    .end local v9    # "delIndex":I    :cond_3    :goto_3    move-object p1, v1    .line 253    goto :goto_0    .line 220    .end local v8    # "addIndex":I    .end local v10    # "en":I    .restart local v12    # "line":I    :cond_4    move v13, v12    .line 221    goto :goto_1    .line 227    .end local v12    # "line":I    .restart local v10    # "en":I    :cond_5    invoke-virtual {v1}, Landroid/text/SpannableStringBuilder;->length()I    move-result v2    iget-object v3, p0, Lcom/meizu/common/widget/FoldableTextView;->mEllipseText:Ljava/lang/CharSequence;    invoke-virtual {v1, v10, v2, v3}, Landroid/text/SpannableStringBuilder;->replace(IILjava/lang/CharSequence;)Landroid/text/SpannableStringBuilder;    goto :goto_2    .line 242    .restart local v8    # "addIndex":I    :cond_6    iget-boolean v2, p0, Lcom/meizu/common/widget/FoldableTextView;->mAlignViewEdge:Z    if-eqz v2, :cond_3    .line 243    :goto_4    invoke-virtual {v0}, Landroid/text/DynamicLayout;->getLineCount()I    move-result v2    if-ne v2, v13, :cond_3    .line 244    const-string v2, " "    invoke-virtual {v1, v8, v8, v2}, Landroid/text/SpannableStringBuilder;->replace(IILjava/lang/CharSequence;)Landroid/text/SpannableStringBuilder;    .line 245    invoke-virtual {v0}, Landroid/text/DynamicLayout;->getLineCount()I    move-result v2    if-le v2, v13, :cond_7    .line 246    add-int/lit8 v2, v8, 0x1    invoke-virtual {v1, v8, v2}, Landroid/text/SpannableStringBuilder;->delete(II)Landroid/text/SpannableStringBuilder;    goto :goto_3    .line 249    :cond_7    add-int/lit8 v8, v8, 0x1    goto :goto_4.end method.method private setOnClickListener(Z)V    .locals 1    .param p1, "set"    # Z    .prologue    .line 285    if-eqz p1, :cond_0    .line 286    invoke-virtual {p0, p0}, Lcom/meizu/common/widget/FoldableTextView;->setOnClickListener(Landroid/view/View$OnClickListener;)V    .line 290    :goto_0    return-void    .line 288    :cond_0    const/4 v0, 0x0    invoke-virtual {p0, v0}, Lcom/meizu/common/widget/FoldableTextView;->setOnClickListener(Landroid/view/View$OnClickListener;)V    goto :goto_0.end method# virtual methods.method public getFoldStatus()Z    .locals 1    .prologue    .line 155    iget-boolean v0, p0, Lcom/meizu/common/widget/FoldableTextView;->mIsfolded:Z    return v0.end method.method public onClick(Landroid/view/View;)V    .locals 3    .param p1, "v"    # Landroid/view/View;    .prologue    const/4 v2, 0x1    const/4 v1, 0x0    .line 304    iget-boolean v0, p0, Lcom/meizu/common/widget/FoldableTextView;->mIsClickSpan:Z    if-eqz v0, :cond_1    .line 305    iput-boolean v1, p0, Lcom/meizu/common/widget/FoldableTextView;->mIsClickSpan:Z    .line 329    :cond_0    :goto_0    return-void    .line 308    :cond_1    iget-boolean v0, p0, Lcom/meizu/common/widget/FoldableTextView;->mClickToFold:Z    if-eqz v0, :cond_0    .line 312    iget-boolean v0, p0, Lcom/meizu/common/widget/FoldableTextView;->mIsfolded:Z    if-eqz v0, :cond_3    .line 314    iget-object v0, p0, Lcom/meizu/common/widget/FoldableTextView;->mListener:Lcom/meizu/common/widget/FoldableTextView$FoldingListener;    if-eqz v0, :cond_2    iget-object v0, p0, Lcom/meizu/common/widget/FoldableTextView;->mListener:Lcom/meizu/common/widget/FoldableTextView$FoldingListener;    invoke-interface {v0, p0, v1}, Lcom/meizu/common/widget/FoldableTextView$FoldingListener;->onFolding(Lcom/meizu/common/widget/FoldableTextView;Z)Z    move-result v0    if-eqz v0, :cond_0    .line 317    :cond_2    iput-boolean v1, p0, Lcom/meizu/common/widget/FoldableTextView;->mIsfolded:Z    .line 318    iget-object v0, p0, Lcom/meizu/common/widget/FoldableTextView;->mainText:Ljava/lang/CharSequence;    sget-object v1, Landroid/widget/TextView$BufferType;->NORMAL:Landroid/widget/TextView$BufferType;    invoke-virtual {p0, v0, v1}, Lcom/meizu/common/widget/FoldableTextView;->setText(Ljava/lang/CharSequence;Landroid/widget/TextView$BufferType;)V    goto :goto_0    .line 322    :cond_3    iget-object v0, p0, Lcom/meizu/common/widget/FoldableTextView;->mListener:Lcom/meizu/common/widget/FoldableTextView$FoldingListener;    if-eqz v0, :cond_4    iget-object v0, p0, Lcom/meizu/common/widget/FoldableTextView;->mListener:Lcom/meizu/common/widget/FoldableTextView$FoldingListener;    invoke-interface {v0, p0, v2}, Lcom/meizu/common/widget/FoldableTextView$FoldingListener;->onFolding(Lcom/meizu/common/widget/FoldableTextView;Z)Z    move-result v0    if-eqz v0, :cond_0    .line 325    :cond_4    iput-boolean v2, p0, Lcom/meizu/common/widget/FoldableTextView;->mIsfolded:Z    .line 326    invoke-virtual {p0}, Lcom/meizu/common/widget/FoldableTextView;->requestLayout()V    .line 327    invoke-virtual {p0}, Lcom/meizu/common/widget/FoldableTextView;->invalidate()V    goto :goto_0.end method.method protected onMeasure(II)V    .locals 7    .param p1, "widthMeasureSpec"    # I    .param p2, "heightMeasureSpec"    # I    .prologue    const/4 v6, 0x0    .line 179    invoke-super {p0, p1, p2}, Landroid/widget/TextView;->onMeasure(II)V    .line 180    iget-boolean v3, p0, Lcom/meizu/common/widget/FoldableTextView;->mIsfolded:Z    if-eqz v3, :cond_0    iget v3, p0, Lcom/meizu/common/widget/FoldableTextView;->mFoldLineMax:I    if-gtz v3, :cond_1    .line 202    :cond_0    :goto_0    return-void    .line 184    :cond_1    invoke-virtual {p0}, Lcom/meizu/common/widget/FoldableTextView;->getText()Ljava/lang/CharSequence;    move-result-object v2    .line 185    .local v2, "text":Ljava/lang/CharSequence;    iput-object v2, p0, Lcom/meizu/common/widget/FoldableTextView;->mainText:Ljava/lang/CharSequence;    .line 186    iget-object v3, p0, Lcom/meizu/common/widget/FoldableTextView;->mainText:Ljava/lang/CharSequence;    if-eqz v3, :cond_2    iget-object v3, p0, Lcom/meizu/common/widget/FoldableTextView;->mainText:Ljava/lang/CharSequence;    instance-of v3, v3, Landroid/text/Spanned;    if-eqz v3, :cond_2    .line 187    iget-object v3, p0, Lcom/meizu/common/widget/FoldableTextView;->mainText:Ljava/lang/CharSequence;    check-cast v3, Landroid/text/Spanned;    iget-object v4, p0, Lcom/meizu/common/widget/FoldableTextView;->mainText:Ljava/lang/CharSequence;    invoke-interface {v4}, Ljava/lang/CharSequence;->length()I    move-result v4    const-class v5, Lcom/meizu/common/widget/FoldableTextView$MoreClickSpan;    invoke-interface {v3, v6, v4, v5}, Landroid/text/Spanned;->getSpans(IILjava/lang/Class;)[Ljava/lang/Object;    move-result-object v1    check-cast v1, [Lcom/meizu/common/widget/FoldableTextView$MoreClickSpan;    .line 188    .local v1, "spans":[Lcom/meizu/common/widget/FoldableTextView$MoreClickSpan;    if-eqz v1, :cond_2    array-length v3, v1    if-lez v3, :cond_2    .line 189    aget-object v3, v1, v6    # getter for: Lcom/meizu/common/widget/FoldableTextView$MoreClickSpan;->mText:Ljava/lang/CharSequence;    invoke-static {v3}, Lcom/meizu/common/widget/FoldableTextView$MoreClickSpan;->access$000(Lcom/meizu/common/widget/FoldableTextView$MoreClickSpan;)Ljava/lang/CharSequence;    move-result-object v3    iput-object v3, p0, Lcom/meizu/common/widget/FoldableTextView;->mainText:Ljava/lang/CharSequence;    .line 193    .end local v1    # "spans":[Lcom/meizu/common/widget/FoldableTextView$MoreClickSpan;    :cond_2    iget-object v3, p0, Lcom/meizu/common/widget/FoldableTextView;->mainText:Ljava/lang/CharSequence;    invoke-direct {p0, v3}, Lcom/meizu/common/widget/FoldableTextView;->foldText(Ljava/lang/CharSequence;)Ljava/lang/CharSequence;    move-result-object v0    .line 194    .local v0, "dst":Ljava/lang/CharSequence;    invoke-static {v2, v0}, Landroid/text/TextUtils;->equals(Ljava/lang/CharSequence;Ljava/lang/CharSequence;)Z    move-result v3    if-nez v3, :cond_0    .line 196    iget-object v3, p0, Lcom/meizu/common/widget/FoldableTextView;->mListener:Lcom/meizu/common/widget/FoldableTextView$FoldingListener;    if-eqz v3, :cond_3    iget-object v3, p0, Lcom/meizu/common/widget/FoldableTextView;->mListener:Lcom/meizu/common/widget/FoldableTextView$FoldingListener;    const/4 v4, 0x1    invoke-interface {v3, p0, v4}, Lcom/meizu/common/widget/FoldableTextView$FoldingListener;->onFolding(Lcom/meizu/common/widget/FoldableTextView;Z)Z    move-result v3    if-eqz v3, :cond_0    .line 199    :cond_3    sget-object v3, Landroid/widget/TextView$BufferType;->SPANNABLE:Landroid/widget/TextView$BufferType;    invoke-virtual {p0, v0, v3}, Lcom/meizu/common/widget/FoldableTextView;->setText(Ljava/lang/CharSequence;Landroid/widget/TextView$BufferType;)V    .line 200    invoke-super {p0, p1, p2}, Landroid/widget/TextView;->onMeasure(II)V    goto :goto_0.end method.method public setClickToFold(Z)V    .locals 1    .param p1, "enabled"    # Z    .prologue    .line 133    if-eqz p1, :cond_0    .line 134    const/4 v0, 0x1    iput-boolean v0, p0, Lcom/meizu/common/widget/FoldableTextView;->mClickToFold:Z    .line 138    :goto_0    return-void    .line 136    :cond_0    const/4 v0, 0x0    iput-boolean v0, p0, Lcom/meizu/common/widget/FoldableTextView;->mClickToFold:Z    goto :goto_0.end method.method public setFoldStatus(Z)V    .locals 1    .param p1, "fold"    # Z    .prologue    .line 164    iget-boolean v0, p0, Lcom/meizu/common/widget/FoldableTextView;->mIsfolded:Z    if-eq v0, p1, :cond_0    .line 165    iput-boolean p1, p0, Lcom/meizu/common/widget/FoldableTextView;->mIsfolded:Z    .line 166    invoke-virtual {p0}, Lcom/meizu/common/widget/FoldableTextView;->requestLayout()V    .line 167    invoke-virtual {p0}, Lcom/meizu/common/widget/FoldableTextView;->invalidate()V    .line 169    :cond_0    return-void.end method.method public setFoldText(Ljava/lang/String;Ljava/lang/String;Z)V    .locals 0    .param p1, "strEllipse"    # Ljava/lang/String;    .param p2, "strUnfold"    # Ljava/lang/String;    .param p3, "alignViewEdge"    # Z    .prologue    .line 101    iput-boolean p3, p0, Lcom/meizu/common/widget/FoldableTextView;->mAlignViewEdge:Z    .line 102    if-eqz p1, :cond_0    .line 103    iput-object p1, p0, Lcom/meizu/common/widget/FoldableTextView;->mEllipseText:Ljava/lang/CharSequence;    .line 105    :cond_0    if-eqz p2, :cond_1    .line 106    iput-object p2, p0, Lcom/meizu/common/widget/FoldableTextView;->mUnfoldText:Ljava/lang/CharSequence;    .line 110    :cond_1    return-void.end method.method public setFolding(ILcom/meizu/common/widget/FoldableTextView$FoldingListener;)V    .locals 1    .param p1, "lineMax"    # I    .param p2, "l"    # Lcom/meizu/common/widget/FoldableTextView$FoldingListener;    .prologue    .line 120    iput p1, p0, Lcom/meizu/common/widget/FoldableTextView;->mFoldLineMax:I    .line 121    iput-object p2, p0, Lcom/meizu/common/widget/FoldableTextView;->mListener:Lcom/meizu/common/widget/FoldableTextView$FoldingListener;    .line 122    iget v0, p0, Lcom/meizu/common/widget/FoldableTextView;->mFoldLineMax:I    if-lez v0, :cond_0    .line 123    invoke-virtual {p0}, Lcom/meizu/common/widget/FoldableTextView;->requestLayout()V    .line 124    invoke-virtual {p0}, Lcom/meizu/common/widget/FoldableTextView;->invalidate()V    .line 126    :cond_0    return-void.end method.method public setLinkColor(I)V    .locals 0    .param p1, "color"    # I    .prologue    .line 146    iput p1, p0, Lcom/meizu/common/widget/FoldableTextView;->mLinkColor:I    .line 147    invoke-virtual {p0}, Lcom/meizu/common/widget/FoldableTextView;->invalidate()V    .line 148    return-void.end method.method public setText(Ljava/lang/CharSequence;Landroid/widget/TextView$BufferType;)V    .locals 0    .param p1, "text"    # Ljava/lang/CharSequence;    .param p2, "type"    # Landroid/widget/TextView$BufferType;    .prologue    .line 173    invoke-super {p0, p1, p2}, Landroid/widget/TextView;->setText(Ljava/lang/CharSequence;Landroid/widget/TextView$BufferType;)V    .line 174    invoke-virtual {p0}, Lcom/meizu/common/widget/FoldableTextView;->requestLayout()V    .line 175    return-void.end method

大致的java代码。为什么说大致,有的逻辑不是很好懂,有的地方按照我自己的逻辑写的,

正真的源码可能和我的还是有差别的。

public class FoldableTextView extends TextView implements View.OnClickListener {private static final String ELLIPSIS_TWO_DOTS = "‥";/** 是否边缘对齐 */private boolean mAlignViewEdge = false;/** 是否能折叠 */private boolean mClickToFold = true;private CharSequence mEllipseText;   //..private CharSequence mUnfoldText;  //更多/**折叠后显示的最多行数*/private int mFoldLineMax;           //显示的最多行数private boolean mIsClickSpan = false;/**是否是折叠状态*/private boolean mIsfolded = true;   private int mLinkColor = -1;private FoldingListener mListener;private CharSequence mainText;public FoldableTextView(Context paramContext) {this(paramContext, null);}public FoldableTextView(Context paramContext, AttributeSet paramAttributeSet) {this(paramContext, paramAttributeSet,R.style.Widget_MeizuCommon_FoldableTextView);}public FoldableTextView(Context context, AttributeSet paramAttributeSet,int paramInt) {super(context, paramAttributeSet, paramInt);TypedArray localTypedArray = context.obtainStyledAttributes(paramAttributeSet, R.styleable.FoldableTextView, paramInt, 0);mEllipseText = localTypedArray.getText(R.styleable.FoldableTextView_mzTextEllipse);mUnfoldText = localTypedArray.getText(R.styleable.FoldableTextView_mzTextUnfold);mFoldLineMax = localTypedArray.getInt(R.styleable.FoldableTextView_mzMaxFoldLine, 0);mAlignViewEdge = localTypedArray.getBoolean(R.styleable.FoldableTextView_mzUnfoldAlignViewEdge, false);mClickToFold = localTypedArray.getBoolean(R.styleable.FoldableTextView_mzClickToFold, false);mLinkColor = localTypedArray.getColor(R.styleable.FoldableTextView_mzLinkColor, -1);mIsfolded = localTypedArray.getBoolean(R.styleable.FoldableTextView_mzIsFold, true);localTypedArray.recycle();if (TextUtils.isEmpty(this.mUnfoldText)) {this.mUnfoldText = context.getString(R.string.more_item_label);}if (TextUtils.isEmpty(this.mEllipseText)) {this.mEllipseText = ELLIPSIS_TWO_DOTS;}setMovementMethod(LinkMovementMethod.getInstance());setOnClickListener(true);}SpannableStringBuilder sb ;private CharSequence foldText(CharSequence text) {if(sb!=null && sb.length()>0) return sb; sb = new SpannableStringBuilder(text);Layout layout = this.getLayout();   DynamicLayout tmpLayout = new DynamicLayout(sb, layout.getPaint(),layout.getWidth(), layout.getAlignment(), 1.0f, 0, false);if (tmpLayout.getLineCount() <= mFoldLineMax) return sb;//行数是按照0开始计数的?如果是则返回偏移值。偏移值是按1开始计数的,//如果想获取该返回值那里 的字符(或者字符串中的位置),记得-1int en = tmpLayout.getLineVisibleEnd(mFoldLineMax-1);MoreClickSpan span = new MoreClickSpan(sb);if (!TextUtils.isEmpty(mEllipseText)) {sb.replace(en, sb.length(), mEllipseText);}else {sb.delete(en, sb.length());}sb.append(" ");int addIndex = sb.length();sb.append(mUnfoldText);sb.setSpan(span, addIndex, sb.length(), Spanned.SPAN_POINT_MARK);if(!mAlignViewEdge) return sb;while (tmpLayout.getLineCount() <= mFoldLineMax) {sb.replace(addIndex, addIndex, " ");addIndex++ ;}sb.delete(addIndex-1, addIndex);return sb;}private void setOnClickListener(boolean paramBoolean) {if (paramBoolean) {setOnClickListener(this);return;}setOnClickListener(null);}public boolean getFoldStatus() {return mIsfolded;}@Overridepublic void onClick(View view) {if(mIsClickSpan||!mClickToFold){mIsClickSpan = false;return;}if (mIsfolded) {//已经折叠了,更改状态mIsfolded = false;setText(mainText, TextView.BufferType.NORMAL);if (mListener != null) mListener.onFolding(this, false);} else {mIsfolded = true;setText(foldText(mainText));if (mListener != null) mListener.onFolding(this, true);}}protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);if (!mIsfolded || mFoldLineMax <= 0)return;if(mainText == null || TextUtils.isEmpty(getText()))mainText = getText();if (mainText != null && (mainText instanceof Spanned)) {CharSequence dst = foldText(mainText);if (!TextUtils.equals(mainText, dst)|| (mListener != null && mListener.onFolding(this, true))) {setText(dst, TextView.BufferType.SPANNABLE);}}}public void setClickToFold(boolean clickToFold) {mClickToFold = clickToFold;}public void setFoldStatus(boolean foldStatus) {if (this.mIsfolded != foldStatus) {this.mIsfolded = foldStatus;requestLayout();invalidate();}}public void setFoldText(String ellipseText, String unfoldText,boolean isAlignViewEdge) {this.mAlignViewEdge = isAlignViewEdge;if (ellipseText != null) {mEllipseText = ellipseText;}if (unfoldText != null) {mUnfoldText = unfoldText;}}public void setFolding(int foldLineMax, FoldingListener listener) {this.mFoldLineMax = foldLineMax;this.mListener = listener;if (mFoldLineMax > 0) {requestLayout();invalidate();}}public void setLinkColor(int paramInt) {this.mLinkColor = paramInt;invalidate();}@Overridepublic void setText(CharSequence paramCharSequence,TextView.BufferType paramBufferType) {super.setText(paramCharSequence, paramBufferType);requestLayout();}public static abstract interface FoldingListener {public abstract boolean onFolding(FoldableTextView textView,boolean isfolded);}private class MoreClickSpan extends ClickableSpan {private final CharSequence mText;public MoreClickSpan(CharSequence text) {this.mText = text;}@Overridepublic void onClick(View view) {if ((mListener != null)&& (!mListener.onFolding(FoldableTextView.this, false))) {return;}//不是折叠状态mIsfolded  = false;setText(mText, TextView.BufferType.NORMAL);mIsClickSpan  = true;}@Overridepublic void updateDrawState(TextPaint textPaint) {if (mLinkColor == -1) {textPaint.setColor(textPaint.linkColor);return;}textPaint.setColor(mLinkColor);}}}


attrs.xml

  <declare-styleable name="FoldableTextView">        <attr name="mzTextEllipse" format="string" />        <attr name="mzTextUnfold" format="string" />        <attr name="mzMaxFoldLine" format="integer" />        <attr name="mzUnfoldAlignViewEdge" format="boolean" />        <attr name="mzClickToFold" format="boolean" />        <attr name="mzLinkColor" format="color" />        <attr name="mzIsFold" format="boolean" />    </declare-styleable>




参考:http://android.blog.51cto.com/268543/384809/

                   http://blog.csdn.net/yuanyuan_186/article/details/41358597

                  JVM指令上

  JVM指令下

                 JVM指令集


0 0
原创粉丝点击