Перейти к содержимому

Как модифицировать приложение андроид

  • автор:

Модификация Android приложения от новичка и для новичков

Добрый день!
Хочу поделиться с вами историей как я модифицировал одно из системных приложений Adroid’а, точнее его модификации LeWa OS. С Андроидом я познакомился недавно, всего месяц назад, и постараюсь тут описать весь ход своих мыслей, что несомненно будет полезно всем тем кто хочет улучшить Андроид, но не знает с чего начать. Пост постараюсь сделать подробным, а потому длинным.

Для начало немного истории.

Как только я получил свой первый китайфон, решил попробовать разные прошивки и в результате остановился на Lewa. Но глаза постоянно мозолил один ее недочет — список контактов, а точнее быстрая навигация на английском.

Информации о данной проблеме немного, поэтому начал копать сам.

Набор инструментов
  • установить Java
  • APKTOOLS для распаковки *.apk
  • Прочитать данный пост
  • Получить объект исследования. Если вы пользуетесь Lewa то надо из архива с прошивкой или прямо с телефона нужно вытянуть /system/app/PIM.apk и все apk из папки /system/framework/ обычно это framework-res.apk, lewa-res.apk и
    mediatek-res.apk. Если вы хотите просто потренироваться то могу дать свои
Приступим

Итак, первое что нам надо это разобрать наше приложение, для этого все apk надо скопировать в папку с apktools. Все apk которые лежали в /system/framework/ надо выделить, подцепить мышью и перенести на apktool-if.cmd тем самым открыв их с помощью этого bat’ника. PIM.apk таким же образом надо открыть с помощью apktool-d.cmd. В результате получаем папку с распакованным приложением.

Изучаем код

Первое что нам необходимо понять — что и где править. Так как мой список контактов изобилует русскими именами, а в быстротой навигации одни английские буквы резонно предположить, что буквы просто жестко забиты где то в коде, а не генерируются динамически исходя из того какие имена у вас в контактах. Обычно такие данные хранятся в папке res, а точнее в res\values\arrays.xml но в нашем случае там ничего похожего нет.
Думаем дальше — раз нет там, значит есть где то в коде. Весь код находится в папе smali, по сути там не исходный код а так называемый Байт-код, и его там много. Так где же искать? Я поступил так, в папке res\layout\ хранятся все «окошки» нашего приложения, то что нам надо находится где-то в списке контактов, поэтому я наобум открыл contact_list_content.xml и начал изучать.

contact_list_content.xml

Там меня заинтересовала строчка

Что это за индексер такой?? Смотрим

alphabet_fast_indexer.xml

Тут ключевые стороки

Что это за элемент который прижимается к правой части экрана (android:layout_gravity=«right»), не то ли что мы ищем?
com.lewa.PIM.widget.AlphabetFastIndexer это ссылка на код PIM\smali\com\lewa\PIM\widget\AlphabetFastIndexer.smali, но изучать его неудобно, и тут на сцену выходит связка dex2jar-0.0.9.7 jd-gui-0.3.3.windows которые мы скачали из поста на форуме и так же научились ими пользоваться. Превращаем classes.dex в classes_dex2jar.jar и открываем через jd-gui.exe

AlphabetFastIndexer.smali Декомпилированный

package com.lewa.PIM.widget; import android.content.Context; import android.content.res.Resources; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Typeface; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import java.util.ArrayList; public class AlphabetFastIndexer extends View < public static String[] b = < "★", "#", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z" >; private int choose = 0; private int mChooseColor; private boolean mHasFav = true; private ArrayList mLetters = new ArrayList(); private int mPaddingBottom; private int mTextsize; OnTouchingLetterChangedListener onTouchingLetterChangedListener; private Paint paint = new Paint(); private boolean showBkg = false; public AlphabetFastIndexer(Context paramContext) < super(paramContext); init(paramContext); setHasFavorite(false); >public AlphabetFastIndexer(Context paramContext, AttributeSet paramAttributeSet) < super(paramContext, paramAttributeSet); init(paramContext); setHasFavorite(false); >public AlphabetFastIndexer(Context paramContext, AttributeSet paramAttributeSet, int paramInt) < super(paramContext, paramAttributeSet, paramInt); init(paramContext); setHasFavorite(false); >private void init(Context paramContext) < this.mChooseColor = paramContext.getResources().getColor(17170450); this.mTextsize = paramContext.getResources().getDimensionPixelSize(2131361937); this.mPaddingBottom = paramContext.getResources().getDimensionPixelSize(2131361938); >public boolean dispatchTouchEvent(MotionEvent paramMotionEvent) < int i = paramMotionEvent.getAction(); int j = (int)(paramMotionEvent.getY() / getHeight() * this.mLetters.size()); switch (i) < default: return true; case 0: this.showBkg = true; case 2: drawThumb(j); return true; case 1: >this.showBkg = false; invalidate(); return true; > public void drawThumb(int paramInt) < OnTouchingLetterChangedListener localOnTouchingLetterChangedListener = this.onTouchingLetterChangedListener; if ((this.choose != paramInt) && (localOnTouchingLetterChangedListener != null) && (paramInt >= 0) && (paramInt < this.mLetters.size())) < if (localOnTouchingLetterChangedListener != null) localOnTouchingLetterChangedListener.onTouchingLetterChanged((String)this.mLetters.get(paramInt)); this.choose = paramInt; invalidate(); >> public void drawThumb(String paramString) < if ((paramString != null) && (!paramString.equals(this.mLetters.get(this.choose)))) < int i = this.mLetters.indexOf(paramString); if (i == -1) i = 0; if (this.choose != i) < this.choose = i; invalidate(); >> > protected void onDraw(Canvas paramCanvas) < super.onDraw(paramCanvas); if (this.showBkg) paramCanvas.drawColor(Color.parseColor("#4C000000")); while (true) < int i = getHeight(); int j = getWidth(); int k = this.mLetters.size(); int m = i / k; for (int n = 0; n < k; n++) < this.paint.setColor(-1); this.paint.setTypeface(Typeface.DEFAULT_BOLD); this.paint.setAntiAlias(true); this.paint.setTextSize(this.mTextsize); if (n == this.choose) < this.paint.setColor(this.mChooseColor); this.paint.setFakeBoldText(true); >String str = (String)this.mLetters.get(n); paramCanvas.drawText(str, j / 2 - this.paint.measureText(str) / 2.0F, m + m * n, this.paint); this.paint.reset(); > paramCanvas.drawColor(Color.parseColor("#26000000")); > > protected void onMeasure(int paramInt1, int paramInt2) < if (this.mHasFav) paramInt2 -= this.mPaddingBottom; setMeasuredDimension(paramInt1, paramInt2); >public boolean onTouchEvent(MotionEvent paramMotionEvent) < return super.onTouchEvent(paramMotionEvent); >public void setHasFavorite(boolean paramBoolean) < int k; if (this.mHasFav != paramBoolean) < this.mHasFav = paramBoolean; this.mLetters.clear(); String[] arrayOfString = b; int i = arrayOfString.length; int j = 0; if (j < i) < String str = arrayOfString[j]; if ((!paramBoolean) && (str.equals("★"))); while (true) < j++; break; this.mLetters.add(str); >> if (this.choose != 0) < if (!paramBoolean) break label117; k = 1 + this.choose; this.choose = k; >if (this.choose >= 0) break label128; this.choose = 0; > while (true) < requestLayout(); return; label117: k = -1 + this.choose; break; label128: if (this.choose >= this.mLetters.size()) this.choose = (-1 + this.mLetters.size()); > > public void setOnTouchingLetterChangedListener(OnTouchingLetterChangedListener paramOnTouchingLetterChangedListener) < this.onTouchingLetterChangedListener = paramOnTouchingLetterChangedListener; >public static abstract interface OnTouchingLetterChangedListener < public abstract void onTouchingLetterChanged(String paramString); >> 

Вот же оно- public static String[] b = < "★", "#", «A», «B», «C», «D», «E», «F», «G», «H», «I», «J», «K», «L», «M», «N», «O», «P», «Q», «R», «S», «T», «U», «V», «W», «X», «Y», «Z» >;. Но править прямо тут нельзя, декомпилированный код примерный, и врядли соберется обратно без ошибок, тем более у нас нет остальных частей программы. Так что правим байт код в PIM\smali\com\lewa\PIM\widget\AlphabetFastIndexer.smali

AlphabetFastIndexer.smali

.class public Lcom/lewa/PIM/widget/AlphabetFastIndexer; .super Landroid/view/View; .source "AlphabetFastIndexer.java" # annotations .annotation system Ldalvik/annotation/MemberClasses; value = < Lcom/lewa/PIM/widget/AlphabetFastIndexer$OnTouchingLetterChangedListener; >.end annotation # static fields .field public static b:[Ljava/lang/String; # instance fields .field private choose:I .field private mChooseColor:I .field private mHasFav:Z .field private mLetters:Ljava/util/ArrayList; .annotation system Ldalvik/annotation/Signature; value = < "Ljava/util/ArrayList", ";" > .end annotation .end field .field private mPaddingBottom:I .field private mTextsize:I .field onTouchingLetterChangedListener:Lcom/lewa/PIM/widget/AlphabetFastIndexer$OnTouchingLetterChangedListener; .field private paint:Landroid/graphics/Paint; .field private showBkg:Z # direct methods .method static constructor ()V .locals 3 .prologue .line 19 const/16 v0, 0x1c new-array v0, v0, [Ljava/lang/String; const/4 v1, 0x0 const-string v2, "\u2605" aput-object v2, v0, v1 const/4 v1, 0x1 const-string v2, "#" aput-object v2, v0, v1 const/4 v1, 0x2 const-string v2, "A" aput-object v2, v0, v1 const/4 v1, 0x3 const-string v2, "B" aput-object v2, v0, v1 const/4 v1, 0x4 const-string v2, "C" aput-object v2, v0, v1 const/4 v1, 0x5 const-string v2, "D" aput-object v2, v0, v1 const/4 v1, 0x6 const-string v2, "E" aput-object v2, v0, v1 const/4 v1, 0x7 const-string v2, "F" aput-object v2, v0, v1 const/16 v1, 0x8 const-string v2, "G" aput-object v2, v0, v1 const/16 v1, 0x9 const-string v2, "H" aput-object v2, v0, v1 const/16 v1, 0xa const-string v2, "I" aput-object v2, v0, v1 const/16 v1, 0xb const-string v2, "J" aput-object v2, v0, v1 const/16 v1, 0xc const-string v2, "K" aput-object v2, v0, v1 const/16 v1, 0xd const-string v2, "L" aput-object v2, v0, v1 const/16 v1, 0xe const-string v2, "M" aput-object v2, v0, v1 const/16 v1, 0xf const-string v2, "N" aput-object v2, v0, v1 const/16 v1, 0x10 const-string v2, "O" aput-object v2, v0, v1 const/16 v1, 0x11 const-string v2, "P" aput-object v2, v0, v1 const/16 v1, 0x12 const-string v2, "Q" aput-object v2, v0, v1 const/16 v1, 0x13 const-string v2, "R" aput-object v2, v0, v1 const/16 v1, 0x14 const-string v2, "S" aput-object v2, v0, v1 const/16 v1, 0x15 const-string v2, "T" aput-object v2, v0, v1 const/16 v1, 0x16 const-string v2, "U" aput-object v2, v0, v1 const/16 v1, 0x17 const-string v2, "V" aput-object v2, v0, v1 const/16 v1, 0x18 const-string v2, "W" aput-object v2, v0, v1 const/16 v1, 0x19 const-string v2, "X" aput-object v2, v0, v1 const/16 v1, 0x1a const-string v2, "Y" aput-object v2, v0, v1 const/16 v1, 0x1b const-string v2, "Z" aput-object v2, v0, v1 sput-object v0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->b:[Ljava/lang/String; return-void .end method .method public constructor (Landroid/content/Context;)V .locals 2 .parameter "context" .prologue const/4 v1, 0x0 .line 44 invoke-direct , Landroid/view/View;->(Landroid/content/Context;)V .line 22 iput v1, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->choose:I .line 23 new-instance v0, Landroid/graphics/Paint; invoke-direct , Landroid/graphics/Paint;->()V iput-object v0, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->paint:Landroid/graphics/Paint; .line 27 const/4 v0, 0x1 iput-boolean v0, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->mHasFav:Z .line 29 new-instance v0, Ljava/util/ArrayList; invoke-direct , Ljava/util/ArrayList;->()V iput-object v0, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->mLetters:Ljava/util/ArrayList; .line 112 iput-boolean v1, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->showBkg:Z .line 45 invoke-direct , Lcom/lewa/PIM/widget/AlphabetFastIndexer;->init(Landroid/content/Context;)V .line 46 invoke-virtual , Lcom/lewa/PIM/widget/AlphabetFastIndexer;->setHasFavorite(Z)V .line 47 return-void .end method .method public constructor (Landroid/content/Context;Landroid/util/AttributeSet;)V .locals 2 .parameter "context" .parameter "attrs" .prologue const/4 v1, 0x0 .line 38 invoke-direct , Landroid/view/View;->(Landroid/content/Context;Landroid/util/AttributeSet;)V .line 22 iput v1, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->choose:I .line 23 new-instance v0, Landroid/graphics/Paint; invoke-direct , Landroid/graphics/Paint;->()V iput-object v0, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->paint:Landroid/graphics/Paint; .line 27 const/4 v0, 0x1 iput-boolean v0, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->mHasFav:Z .line 29 new-instance v0, Ljava/util/ArrayList; invoke-direct , Ljava/util/ArrayList;->()V iput-object v0, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->mLetters:Ljava/util/ArrayList; .line 112 iput-boolean v1, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->showBkg:Z .line 39 invoke-direct , Lcom/lewa/PIM/widget/AlphabetFastIndexer;->init(Landroid/content/Context;)V .line 40 invoke-virtual , Lcom/lewa/PIM/widget/AlphabetFastIndexer;->setHasFavorite(Z)V .line 41 return-void .end method .method public constructor (Landroid/content/Context;Landroid/util/AttributeSet;I)V .locals 2 .parameter "context" .parameter "attrs" .parameter "defStyle" .prologue const/4 v1, 0x0 .line 32 invoke-direct , Landroid/view/View;->(Landroid/content/Context;Landroid/util/AttributeSet;I)V .line 22 iput v1, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->choose:I .line 23 new-instance v0, Landroid/graphics/Paint; invoke-direct , Landroid/graphics/Paint;->()V iput-object v0, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->paint:Landroid/graphics/Paint; .line 27 const/4 v0, 0x1 iput-boolean v0, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->mHasFav:Z .line 29 new-instance v0, Ljava/util/ArrayList; invoke-direct , Ljava/util/ArrayList;->()V iput-object v0, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->mLetters:Ljava/util/ArrayList; .line 112 iput-boolean v1, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->showBkg:Z .line 33 invoke-direct , Lcom/lewa/PIM/widget/AlphabetFastIndexer;->init(Landroid/content/Context;)V .line 34 invoke-virtual , Lcom/lewa/PIM/widget/AlphabetFastIndexer;->setHasFavorite(Z)V .line 35 return-void .end method .method private init(Landroid/content/Context;)V .locals 2 .parameter "context" .prologue .line 50 invoke-virtual , Landroid/content/Context;->getResources()Landroid/content/res/Resources; move-result-object v0 const v1, 0x1060012 invoke-virtual , Landroid/content/res/Resources;->getColor(I)I move-result v0 iput v0, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->mChooseColor:I .line 51 invoke-virtual , Landroid/content/Context;->getResources()Landroid/content/res/Resources; move-result-object v0 const v1, 0x7f0a0091 invoke-virtual , Landroid/content/res/Resources;->getDimensionPixelSize(I)I move-result v0 iput v0, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->mTextsize:I .line 52 invoke-virtual , Landroid/content/Context;->getResources()Landroid/content/res/Resources; move-result-object v0 const v1, 0x7f0a0092 invoke-virtual , Landroid/content/res/Resources;->getDimensionPixelSize(I)I move-result v0 iput v0, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->mPaddingBottom:I .line 53 return-void .end method # virtual methods .method public dispatchTouchEvent(Landroid/view/MotionEvent;)Z .locals 6 .parameter "event" .prologue const/4 v5, 0x1 .line 116 invoke-virtual , Landroid/view/MotionEvent;->getAction()I move-result v0 .line 117 .local v0, action:I invoke-virtual , Landroid/view/MotionEvent;->getY()F move-result v2 .line 118 .local v2, y:F invoke-virtual , Lcom/lewa/PIM/widget/AlphabetFastIndexer;->getHeight()I move-result v3 int-to-float v3, v3 div-float v3, v2, v3 iget-object v4, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->mLetters:Ljava/util/ArrayList; invoke-virtual , Ljava/util/ArrayList;->size()I move-result v4 int-to-float v4, v4 mul-float/2addr v3, v4 float-to-int v1, v3 .line 120 .local v1, c:I packed-switch v0, :pswitch_data_0 .line 143 :goto_0 return v5 .line 122 :pswitch_0 iput-boolean v5, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->showBkg:Z .line 135 :pswitch_1 invoke-virtual , Lcom/lewa/PIM/widget/AlphabetFastIndexer;->drawThumb(I)V goto :goto_0 .line 138 :pswitch_2 const/4 v3, 0x0 iput-boolean v3, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->showBkg:Z .line 140 invoke-virtual , Lcom/lewa/PIM/widget/AlphabetFastIndexer;->invalidate()V goto :goto_0 .line 120 :pswitch_data_0 .packed-switch 0x0 :pswitch_0 :pswitch_2 :pswitch_1 .end packed-switch .end method .method public drawThumb(I)V .locals 2 .parameter "position" .prologue .line 152 iget-object v0, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->onTouchingLetterChangedListener:Lcom/lewa/PIM/widget/AlphabetFastIndexer$OnTouchingLetterChangedListener; .line 153 .local v0, listener:Lcom/lewa/PIM/widget/AlphabetFastIndexer$OnTouchingLetterChangedListener; iget v1, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->choose:I if-eq v1, p1, :cond_1 if-eqz v0, :cond_1 .line 154 if-ltz p1, :cond_1 iget-object v1, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->mLetters:Ljava/util/ArrayList; invoke-virtual , Ljava/util/ArrayList;->size()I move-result v1 if-ge p1, v1, :cond_1 .line 155 if-eqz v0, :cond_0 .line 156 iget-object v1, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->mLetters:Ljava/util/ArrayList; invoke-virtual , Ljava/util/ArrayList;->get(I)Ljava/lang/Object; move-result-object v1 check-cast v1, Ljava/lang/String; invoke-interface , Lcom/lewa/PIM/widget/AlphabetFastIndexer$OnTouchingLetterChangedListener;->onTouchingLetterChanged(Ljava/lang/String;)V .line 158 :cond_0 iput p1, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->choose:I .line 159 invoke-virtual , Lcom/lewa/PIM/widget/AlphabetFastIndexer;->invalidate()V .line 162 :cond_1 return-void .end method .method public drawThumb(Ljava/lang/String;)V .locals 3 .parameter "letter" .prologue .line 165 if-eqz p1, :cond_1 iget-object v1, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->mLetters:Ljava/util/ArrayList; iget v2, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->choose:I invoke-virtual , Ljava/util/ArrayList;->get(I)Ljava/lang/Object; move-result-object v1 invoke-virtual , Ljava/lang/String;->equals(Ljava/lang/Object;)Z move-result v1 if-nez v1, :cond_1 .line 166 iget-object v1, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->mLetters:Ljava/util/ArrayList; invoke-virtual , Ljava/util/ArrayList;->indexOf(Ljava/lang/Object;)I move-result v0 .line 167 .local v0, i:I const/4 v1, -0x1 if-ne v0, v1, :cond_0 const/4 v0, 0x0 .line 168 :cond_0 iget v1, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->choose:I if-eq v1, v0, :cond_1 .line 169 iput v0, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->choose:I .line 170 invoke-virtual , Lcom/lewa/PIM/widget/AlphabetFastIndexer;->invalidate()V .line 173 .end local v0 #i:I :cond_1 return-void .end method .method protected onDraw(Landroid/graphics/Canvas;)V .locals 12 .parameter "canvas" .prologue const/4 v11, 0x1 .line 83 invoke-super , Landroid/view/View;->onDraw(Landroid/graphics/Canvas;)V .line 84 iget-boolean v8, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->showBkg:Z if-eqz v8, :cond_1 .line 85 const-string v8, "#4C000000" invoke-static , Landroid/graphics/Color;->parseColor(Ljava/lang/String;)I move-result v8 invoke-virtual , Landroid/graphics/Canvas;->drawColor(I)V .line 90 :goto_0 invoke-virtual , Lcom/lewa/PIM/widget/AlphabetFastIndexer;->getHeight()I move-result v0 .line 91 .local v0, height:I invoke-virtual , Lcom/lewa/PIM/widget/AlphabetFastIndexer;->getWidth()I move-result v5 .line 92 .local v5, width:I iget-object v8, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->mLetters:Ljava/util/ArrayList; invoke-virtual , Ljava/util/ArrayList;->size()I move-result v4 .line 93 .local v4, size:I div-int v3, v0, v4 .line 94 .local v3, singleHeight:I const/4 v1, 0x0 .local v1, i:I :goto_1 if-ge v1, v4, :cond_2 .line 95 iget-object v8, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->paint:Landroid/graphics/Paint; const/4 v9, -0x1 invoke-virtual , Landroid/graphics/Paint;->setColor(I)V .line 96 iget-object v8, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->paint:Landroid/graphics/Paint; sget-object v9, Landroid/graphics/Typeface;->DEFAULT_BOLD:Landroid/graphics/Typeface; invoke-virtual , Landroid/graphics/Paint;->setTypeface(Landroid/graphics/Typeface;)Landroid/graphics/Typeface; .line 97 iget-object v8, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->paint:Landroid/graphics/Paint; invoke-virtual , Landroid/graphics/Paint;->setAntiAlias(Z)V .line 98 iget-object v8, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->paint:Landroid/graphics/Paint; iget v9, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->mTextsize:I int-to-float v9, v9 invoke-virtual , Landroid/graphics/Paint;->setTextSize(F)V .line 99 iget v8, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->choose:I if-ne v1, v8, :cond_0 .line 100 iget-object v8, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->paint:Landroid/graphics/Paint; iget v9, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->mChooseColor:I invoke-virtual , Landroid/graphics/Paint;->setColor(I)V .line 101 iget-object v8, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->paint:Landroid/graphics/Paint; invoke-virtual , Landroid/graphics/Paint;->setFakeBoldText(Z)V .line 103 :cond_0 iget-object v8, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->mLetters:Ljava/util/ArrayList; invoke-virtual , Ljava/util/ArrayList;->get(I)Ljava/lang/Object; move-result-object v2 check-cast v2, Ljava/lang/String; .line 104 .local v2, letterStr:Ljava/lang/String; div-int/lit8 v8, v5, 0x2 int-to-float v8, v8 iget-object v9, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->paint:Landroid/graphics/Paint; invoke-virtual , Landroid/graphics/Paint;->measureText(Ljava/lang/String;)F move-result v9 const/high16 v10, 0x4000 div-float/2addr v9, v10 sub-float v6, v8, v9 .line 105 .local v6, xPos:F mul-int v8, v3, v1 add-int/2addr v8, v3 int-to-float v7, v8 .line 106 .local v7, yPos:F iget-object v8, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->paint:Landroid/graphics/Paint; invoke-virtual , Landroid/graphics/Canvas;->drawText(Ljava/lang/String;FFLandroid/graphics/Paint;)V .line 107 iget-object v8, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->paint:Landroid/graphics/Paint; invoke-virtual , Landroid/graphics/Paint;->reset()V .line 94 add-int/lit8 v1, v1, 0x1 goto :goto_1 .line 87 .end local v0 #height:I .end local v1 #i:I .end local v2 #letterStr:Ljava/lang/String; .end local v3 #singleHeight:I .end local v4 #size:I .end local v5 #width:I .end local v6 #xPos:F .end local v7 #yPos:F :cond_1 const-string v8, "#26000000" invoke-static , Landroid/graphics/Color;->parseColor(Ljava/lang/String;)I move-result v8 invoke-virtual , Landroid/graphics/Canvas;->drawColor(I)V goto :goto_0 .line 110 .restart local v0 #height:I .restart local v1 #i:I .restart local v3 #singleHeight:I .restart local v4 #size:I .restart local v5 #width:I :cond_2 return-void .end method .method protected onMeasure(II)V .locals 1 .parameter "widthMeasureSpec" .parameter "heightMeasureSpec" .prologue .line 77 iget-boolean v0, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->mHasFav:Z if-eqz v0, :cond_0 iget v0, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->mPaddingBottom:I sub-int/2addr p2, v0 .end local p2 :cond_0 invoke-virtual , Lcom/lewa/PIM/widget/AlphabetFastIndexer;->setMeasuredDimension(II)V .line 78 return-void .end method .method public onTouchEvent(Landroid/view/MotionEvent;)Z .locals 1 .parameter "event" .prologue .line 148 invoke-super , Landroid/view/View;->onTouchEvent(Landroid/view/MotionEvent;)Z move-result v0 return v0 .end method .method public setHasFavorite(Z)V .locals 6 .parameter "hasFav" .prologue .line 56 iget-boolean v4, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->mHasFav:Z if-eq v4, p1, :cond_4 .line 57 iput-boolean p1, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->mHasFav:Z .line 58 iget-object v4, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->mLetters:Ljava/util/ArrayList; invoke-virtual , Ljava/util/ArrayList;->clear()V .line 59 sget-object v0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->b:[Ljava/lang/String; .local v0, arr$:[Ljava/lang/String; array-length v2, v0 .local v2, len$:I const/4 v1, 0x0 .local v1, i$:I :goto_0 if-ge v1, v2, :cond_1 aget-object v3, v0, v1 .line 60 .local v3, letter:Ljava/lang/String; if-nez p1, :cond_0 const-string v4, "\u2605" invoke-virtual , Ljava/lang/String;->equals(Ljava/lang/Object;)Z move-result v4 if-eqz v4, :cond_0 .line 59 :goto_1 add-int/lit8 v1, v1, 0x1 goto :goto_0 .line 62 :cond_0 iget-object v4, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->mLetters:Ljava/util/ArrayList; invoke-virtual , Ljava/util/ArrayList;->add(Ljava/lang/Object;)Z goto :goto_1 .line 64 .end local v3 #letter:Ljava/lang/String; :cond_1 iget v4, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->choose:I if-eqz v4, :cond_2 if-eqz p1, :cond_5 iget v4, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->choose:I add-int/lit8 v4, v4, 0x1 :goto_2 iput v4, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->choose:I .line 65 :cond_2 iget v4, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->choose:I if-gez v4, :cond_6 const/4 v4, 0x0 iput v4, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->choose:I .line 68 :cond_3 :goto_3 invoke-virtual , Lcom/lewa/PIM/widget/AlphabetFastIndexer;->requestLayout()V .line 70 .end local v0 #arr$:[Ljava/lang/String; .end local v1 #i$:I .end local v2 #len$:I :cond_4 return-void .line 64 .restart local v0 #arr$:[Ljava/lang/String; .restart local v1 #i$:I .restart local v2 #len$:I :cond_5 iget v4, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->choose:I add-int/lit8 v4, v4, -0x1 goto :goto_2 .line 66 :cond_6 iget v4, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->choose:I iget-object v5, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->mLetters:Ljava/util/ArrayList; invoke-virtual , Ljava/util/ArrayList;->size()I move-result v5 if-lt v4, v5, :cond_3 iget-object v4, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->mLetters:Ljava/util/ArrayList; invoke-virtual , Ljava/util/ArrayList;->size()I move-result v4 add-int/lit8 v4, v4, -0x1 iput v4, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->choose:I goto :goto_3 .end method .method public setOnTouchingLetterChangedListener(Lcom/lewa/PIM/widget/AlphabetFastIndexer$OnTouchingLetterChangedListener;)V .locals 0 .parameter "onTouchingLetterChangedListener" .prologue .line 181 iput-object p1, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->onTouchingLetterChangedListener:Lcom/lewa/PIM/widget/AlphabetFastIndexer$OnTouchingLetterChangedListener; .line 182 return-void .end method 

Тут нас интересует следующий участок
AlphabetFastIndexer.smali

const/16 v0, 0x1c new-array v0, v0, [Ljava/lang/String; const/4 v1, 0x0 const-string v2, "\u2605" aput-object v2, v0, v1 const/4 v1, 0x1 const-string v2, "#" aput-object v2, v0, v1 const/4 v1, 0x2 const-string v2, "A" aput-object v2, v0, v1 const/4 v1, 0x3 const-string v2, "B" aput-object v2, v0, v1 const/4 v1, 0x4 const-string v2, "C" aput-object v2, v0, v1 const/4 v1, 0x5 const-string v2, "D" aput-object v2, v0, v1 const/4 v1, 0x6 const-string v2, "E" aput-object v2, v0, v1 const/4 v1, 0x7 const-string v2, "F" aput-object v2, v0, v1 const/16 v1, 0x8 const-string v2, "G" aput-object v2, v0, v1 const/16 v1, 0x9 const-string v2, "H" aput-object v2, v0, v1 const/16 v1, 0xa const-string v2, "I" aput-object v2, v0, v1 const/16 v1, 0xb const-string v2, "J" aput-object v2, v0, v1 const/16 v1, 0xc const-string v2, "K" aput-object v2, v0, v1 const/16 v1, 0xd const-string v2, "L" aput-object v2, v0, v1 const/16 v1, 0xe const-string v2, "M" aput-object v2, v0, v1 const/16 v1, 0xf const-string v2, "N" aput-object v2, v0, v1 const/16 v1, 0x10 const-string v2, "O" aput-object v2, v0, v1 const/16 v1, 0x11 const-string v2, "P" aput-object v2, v0, v1 const/16 v1, 0x12 const-string v2, "Q" aput-object v2, v0, v1 const/16 v1, 0x13 const-string v2, "R" aput-object v2, v0, v1 const/16 v1, 0x14 const-string v2, "S" aput-object v2, v0, v1 const/16 v1, 0x15 const-string v2, "T" aput-object v2, v0, v1 const/16 v1, 0x16 const-string v2, "U" aput-object v2, v0, v1 const/16 v1, 0x17 const-string v2, "V" aput-object v2, v0, v1 const/16 v1, 0x18 const-string v2, "W" aput-object v2, v0, v1 const/16 v1, 0x19 const-string v2, "X" aput-object v2, v0, v1 const/16 v1, 0x1a const-string v2, "Y" aput-object v2, v0, v1 const/16 v1, 0x1b const-string v2, "Z" aput-object v2, v0, v1 

Тут и так все понятно, меняем буквы на русские, и так как русских букв больше придется добавить несколько строк типа

 const/16 v1, 0x1b const-string v2, "" aput-object v2, v0, v1 

const/16 v1, 0x1b это порядковый номер буквы он тоже будет с каждой новой буквой расти. Так же в начале вы могли заметить стоку

const/16 v0, 0x1c 

Это размер всего массива, так как мы добавили несколько букв ее нам тоже надо поменять. Я добавил 3 буквы по этому в моем случае ее надо поменять на

const/16 v0, 0x1f 

В итоге у меня получился следующий код:
AlphabetFastIndexer.smali Исправленный

const/16 v0, 0x1f new-array v0, v0, [Ljava/lang/String; const/4 v1, 0x0 const-string v2, "\u2605" aput-object v2, v0, v1 const/4 v1, 0x1 const-string v2, "#" aput-object v2, v0, v1 const/4 v1, 0x2 const-string v2, "\u0410" aput-object v2, v0, v1 const/4 v1, 0x3 const-string v2, "\u0411" aput-object v2, v0, v1 const/4 v1, 0x4 const-string v2, "\u0412" aput-object v2, v0, v1 const/4 v1, 0x5 const-string v2, "\u0413" aput-object v2, v0, v1 const/4 v1, 0x6 const-string v2, "\u0414" aput-object v2, v0, v1 const/4 v1, 0x7 const-string v2, "\u0415" aput-object v2, v0, v1 const/16 v1, 0x8 const-string v2, "\u0416" aput-object v2, v0, v1 const/16 v1, 0x9 const-string v2, "\u0417" aput-object v2, v0, v1 const/16 v1, 0xa const-string v2, "\u0418" aput-object v2, v0, v1 const/16 v1, 0xb const-string v2, "\u041a" aput-object v2, v0, v1 const/16 v1, 0xc const-string v2, "\u041b" aput-object v2, v0, v1 const/16 v1, 0xd const-string v2, "\u041c" aput-object v2, v0, v1 const/16 v1, 0xe const-string v2, "\u041d" aput-object v2, v0, v1 const/16 v1, 0xf const-string v2, "\u041e" aput-object v2, v0, v1 const/16 v1, 0x10 const-string v2, "\u041f" aput-object v2, v0, v1 const/16 v1, 0x11 const-string v2, "\u0420" aput-object v2, v0, v1 const/16 v1, 0x12 const-string v2, "\u0421" aput-object v2, v0, v1 const/16 v1, 0x13 const-string v2, "\u0422" aput-object v2, v0, v1 const/16 v1, 0x14 const-string v2, "\u0423" aput-object v2, v0, v1 const/16 v1, 0x15 const-string v2, "\u0424" aput-object v2, v0, v1 const/16 v1, 0x16 const-string v2, "\u0425" aput-object v2, v0, v1 const/16 v1, 0x17 const-string v2, "\u0426" aput-object v2, v0, v1 const/16 v1, 0x18 const-string v2, "\u0427" aput-object v2, v0, v1 const/16 v1, 0x19 const-string v2, "\u0428" aput-object v2, v0, v1 const/16 v1, 0x1a const-string v2, "\u0429" aput-object v2, v0, v1 const/16 v1, 0x1b const-string v2, "\u042b" aput-object v2, v0, v1 const/16 v1, 0x1c const-string v2, "\u042d" aput-object v2, v0, v1 const/16 v1, 0x1d const-string v2, "\u042e" aput-object v2, v0, v1 const/16 v1, 0x1e const-string v2, "\u042f" aput-object v2, v0, v1 

«\u042f» — это «юникоды» наших букв, так надежней)

После этого можно попробовать собрать риложение перетянув папку PIM на apktool-b.cmd, через некоторое время появится PIM\dist\PIM.apk

Теперь можно заменить им PIM.apk своего телефона, как это сделать выходит за рамки данной статьи. Могу лишь скзать что можно прошится моим патчем, предварительно заменив в нем PIM.apk на свой.

PROFIT?

Не совсем… Да, буквы русские но поиск то не работает!
Изучаем дальше декомпилированный AlphabetFastIndexer.smali
тут больше ничего интересного кроме

public static abstract interface OnTouchingLetterChangedListener

Хотя по идее он к нашей проблеме не относится я все же решил посмотреть что это такое. public static abstract говорит о том, что этот интерфейс реализован где то в другом файле. Ищем поиском и находим пару файлов где встречается OnTouchingLetterChangedListener:
PIM\smali\com\lewa\PIM\contacts\list\ContactEntryListFragment.smali
PIM\smali\com\lewa\PIM\mms\choiceContacts\MmsChoicePhoneNumbersContacts.smali

Они достаточно длинные поэтому приведу только то что нас интересует

ContactEntryListFragment.smali

Runnable FirstLettersRunnable = new Runnable() < public void run() < ContactEntryListFragment.this.marrFirstCharacters.clear(); ContactEntryListFragment.this.marrFirstLetters.clear(); Cursor localCursor = ContactEntryListFragment.this.mAdapter.getCursor(0); CharArrayBuffer localCharArrayBuffer1; CharArrayBuffer localCharArrayBuffer2; if ((localCursor != null) && (!localCursor.isClosed()) && (localCursor.getCount() >0)) < localCursor.moveToFirst(); boolean bool = ContactEntryListFragment.this.mAdapter instanceof ContactEntryListAdapter; int i = 0; int j = 0; if (bool) j = ContactEntryListFragment.this.mAdapter.getStarredCount(); do < localCharArrayBuffer1 = new CharArrayBuffer(128); localCharArrayBuffer2 = new CharArrayBuffer(128); if ((i >= j) || (localCursor.getInt(12) != 1)) break; localCharArrayBuffer1.data[0] = '★'; int k = 9733; i++; ContactEntryListFragment.this.marrFirstLetters.add(String.valueOf(k)); ContactEntryListFragment.this.marrFirstCharacters.add(String.copyValueOf(localCharArrayBuffer1.data, 0, 1)); > while (localCursor.moveToNext()); if (ContactEntryListFragment.this.mAdapter != null) ContactEntryListFragment.this.mAdapter.notifyDataSetChanged(); > ContactEntryListFragment.access$302(ContactEntryListFragment.this, true); return; localCursor.copyStringToBuffer(1, localCharArrayBuffer1); if ((localCharArrayBuffer1.data[0] >= 'a') && (localCharArrayBuffer1.data[0] while (true) < localCursor.copyStringToBuffer(10, localCharArrayBuffer2); int m = Character.toUpperCase(localCharArrayBuffer2.data[0]); if ((m >= 65) && (m 'Z'))) localCharArrayBuffer1.data[0] = '#'; > > >; 

Как и откуда вызывается это функция я не понял но факт — она собирает первые буквы контактов и все что не относится к английским буквам приравневает к # И поэтому у нас ничего не работает… конкретно эта функция находится в «подфайле» PIM\smali\com\lewa\PIM\contacts\list\ContactEntryListFragment$3.smali

Там нужно найти участок

.method public run()V .locals 13 .prologue .local p0, this:Lcom/lewa/PIM/contacts/list/ContactEntryListFragment$3;,"Lcom/lewa/PIM/contacts/list/ContactEntryListFragment.3;" const/16 v12, 0x5a const/16 v11, 0x41 

0x41 и 0x5a это буквы ‘A’ и ‘Z’ их надо поменять на русские:

.method public run()V .locals 13 .prologue .local p0, this:Lcom/lewa/PIM/contacts/list/ContactEntryListFragment$3;,"Lcom/lewa/PIM/contacts/list/ContactEntryListFragment.3;" const/16 v12, 0x42f const/16 v11, 0x410 

После чего найти

 aget-char v6, v6, v8 const/16 v7, 0x61 if-lt v6, v7, :cond_6 iget-object v6, v3, Landroid/database/CharArrayBuffer;->data:[C aget-char v6, v6, v8 const/16 v7, 0x7a if-gt v6, v7, :cond_6 

0x61 — ‘a’
0x7a — ‘z’
Меняем

 aget-char v6, v6, v8 const/16 v7, 0x430 if-lt v6, v7, :cond_6 iget-object v6, v3, Landroid/database/CharArrayBuffer;->data:[C aget-char v6, v6, v8 const/16 v7, 0x44f if-gt v6, v7, :cond_6 

В файле MmsChoicePhoneNumbersContacts.smali примерно такая же история

ContactEntryListFragment.smali

 protected void onQueryComplete(int paramInt, Object paramObject, Cursor paramCursor) < switch (paramInt) < default: return; case 0: >MmsChoicePhoneNumbersContacts.this.mAdapter.changeCursor(paramCursor); if (paramCursor.getCount() > 0) < MmsChoicePhoneNumbersContacts.this.marrFirstCharacters.clear(); MmsChoicePhoneNumbersContacts.this.marrFirstLetters.clear(); paramCursor.moveToPosition(-1); if (paramCursor.moveToNext()) < CharArrayBuffer localCharArrayBuffer1 = new CharArrayBuffer(128); paramCursor.copyStringToBuffer(4, localCharArrayBuffer1); if ((localCharArrayBuffer1.data[0] >= 'a') && (localCharArrayBuffer1.data[0] while (true) < CharArrayBuffer localCharArrayBuffer2 = new CharArrayBuffer(128); paramCursor.copyStringToBuffer(11, localCharArrayBuffer2); char c = Character.toUpperCase(localCharArrayBuffer2.data[0]); if ((c < 'A') || (c >'Z')) c = '#'; MmsChoicePhoneNumbersContacts.this.marrFirstLetters.add(String.valueOf(c)); MmsChoicePhoneNumbersContacts.this.marrFirstCharacters.add(String.copyValueOf(localCharArrayBuffer1.data, 0, 1)); break; if ((localCharArrayBuffer1.data[0] < '€') && ((localCharArrayBuffer1.data[0] < 'A') || (localCharArrayBuffer1.data[0] >'Z'))) localCharArrayBuffer1.data[0] = '#'; > > MmsChoicePhoneNumbersContacts.access$502(MmsChoicePhoneNumbersContacts.this, true); paramCursor.moveToFirst(); MmsChoicePhoneNumbersContacts.this.mEmptyTextView.setVisibility(8); return; > MmsChoicePhoneNumbersContacts.this.mEmptyTextView.setVisibility(0); > 
# virtual methods .method protected onQueryComplete(ILjava/lang/Object;Landroid/database/Cursor;)V .locals 10 .parameter "token" .parameter "cookie" .parameter "cursor" .prologue const/16 v9, 0x5a const/16 v8, 0x41 
# virtual methods .method protected onQueryComplete(ILjava/lang/Object;Landroid/database/Cursor;)V .locals 10 .parameter "token" .parameter "cookie" .parameter "cursor" .prologue const/16 v9, 0x42f const/16 v8, 0x410 

и соответсвенно

 aget-char v3, v3, v5 const/16 v4, 0x61 if-lt v3, v4, :cond_3 iget-object v3, v1, Landroid/database/CharArrayBuffer;->data:[C aget-char v3, v3, v5 const/16 v4, 0x7a if-gt v3, v4, :cond_3 
 aget-char v3, v3, v5 const/16 v4, 0x430 if-lt v3, v4, :cond_3 iget-object v3, v1, Landroid/database/CharArrayBuffer;->data:[C aget-char v3, v3, v5 const/16 v4, 0x44f if-gt v3, v4, :cond_3 

Собираем это дело обратно и запихиваем а телефон. Вот теперь работает!

Спасибо всем за внимание!

P.S. Надеюсь мой ход мыслей кому то поможет. В идеале бы найти как строятся группы в списке контактов и привинтить это дело сюда. Тогда бы в этом списке были толко те буквы, которые дейсвительно присутствуют в контактах, при том что на нескольких языках одновременно, но это мне пока не по зубам.

  • android
  • разработка под android

Простой способ модификации Android приложения

Бывает после релиза приложения его исходники куда-то деваются. Правда ведь, такое постоянно случается? И ничего не остается кроме как декомпилировать его и подправить несколько сотен строк кода и все это нужно сделать максимально быстро.

Вот и у меня появилась задача модифицировать приложение имея всего лишь его apk. И те, кто занимался декомпиляцией приложений знают насколько тяжело его потом скомпилировать.

Декомпиляция
  • ApkTool для декомпиляции ресурсов.
  • Dex2Jar для преобразования dex в jar.
  • JD-GUI для получения исходников из jar.
  • еще рекомендую JAD, некоторые места лучше декомпилирует чем JD-GUI.

Если попробовать собрать приложение после декомпиляции, то скорее всего оно не скомпилируется из-за ошибок, особо тяжело декомпилируются циклы и условия. Некоторые ошибки легко исправляются, но опять же разобраться во множестве условных переходов будет не просто, а когда их количество более ста или даже несколько тысяч, то такой способ восстановить приложение теряет эффективность, быстрее написать все заново.

На этом можно было и закончить эксперименты с декомпиляцией, но лень двигатель прогресса и родился новый способ.

Переопределение классов

Итак, jar это библиотека, так почему бы просто не подключить ее к новому проекту? Кидаем ее в папку libs, наследуемся от главной активити и компилируем. Все работает, главное чтоб не совпадали имена классов, поэтому названия пакетов должно отличаться иначе как минимум совпадут сгенерированные BuildConfig и R.

Таким способом можно отнаследоваться от Activity, Service, BroadcastReceiver и, возможно, некоторых других классов объявляемых в манифесте, так же в манифесте нужно будет указать новые имена классов, иначе они не будут использоваться.

Теперь можно переопределить виртуальные функции, но и только, тем более ключевое слово final не позволит это сделать и отнаследоваться тоже, поэтому идем дальше.

Замена классов

Разархивировав jar библиотеку получим class файлы, это скомпилированные классы, заметим, что при сборке проекта в папке bin/classes лежат те же class файлы, а что если подсунуть туда файлы из библиотеки…

Не все так просто, для начала нужно скомпилировать проект. Чтобы использовать классы исходного приложения нужно его как-то присоединить к проекту, но при этом не экспортировать. Делается это просто: из папки libs Эклипс сам экспортирует библиотеки, поэтому перемещаем jar библиотеку в папку lib и подключаем к проекту, в Эклипсе это Project->Preferences->Java Build Path->Libraries->Add Jars… далее во вкладке Order and Export нужно убедиться, что не установлен чекбокс, потому что экспортировать библиотеку нам не нужно, все будет в class файлах.

Теперь берем какой-нибудь класс из декомпилированных исходников приложения, исправляем в нем ошибки компиляции, добавляем, например, показ диалога, чтоб убедиться, что используется именно новый класс. Далее очищаем проект, в Эклипсе это Project->Clean, копируем class файлы в папку bin/classes, собираем проект и все работает!

При следующих сборках проекта нет необходимости его очищать, так что использовать такой способ достаточно удобно. Для облегчения исправления ошибок после декомпиляции я использовал исходники полученные из JD-GUI и JAD, обычно этого было достаточно.

Но вот пришло время собрать релизную версию, а для нее, конечно же, используется обфускатор и выдаст он сотни ошибок на совпадения имен классов и неразрешенные ссылки. Вот теперь пора убрать из скомпилированных class файлов классы, которые были заменены, после этого ошибок не должно быть. Еще одна неприятная особенность сборки релиза — нужно каждый раз очищать проект и копировать class файлы, а то они куда-то пропадают.

Заключение

Таким способом декомпилируются только модифицируемые файлы, что избавляет от исправления ошибок во всех исходниках и улучшает надежность, так как всего часть кода подвергнется процессу декомпиляции — исправления — компиляции.

С большой вероятностью не получится скрыть все следы от оригинального приложения, названия необфусцированных классов таких как Activity и Service, а так же названия их пакетов сохранятся и будут доступны после декомпиляции модифицированного приложения, но для пиратских версий это не проблема, из-за чего стоит защищать приложение, способы защиты аналогичны другим способам защиты от изменения кода.

Обновление классов в jar — идея замены классов пришла из этой возможности для jar библиотеки.

  • Java
  • Разработка под Android

Как модифицировать приложение андроид

В стоке в приложении регистрируешься и оно синхронизируется со своим сервером через верификацию по смс. И просит оплату. В идеале, нужно сделать чтобы приложение работало автономно, без соединения со своим сервером.

У меня уже есть мод на это приложение, но в старой версии. Оно продолжает соединяться со своим сервером, но не просит оплату.

Я прикреплю мод старой версии 2.14.6
И новое апк, которое надо модифицировать версия 2.16.3

Огромная просьба сделать мод по аналогии с версией 2.14.6 или вообще выпилить онлайн из этого приложения.

Как модифицировать приложение андроид

К сожалению, на данный момент, подобными программами не изменить 99% онлайн приложений.

Мы предлагаем вам 12 основных приложений для модифицирования игр и программ, на своём Android устройстве.

  1. CreeHack (КриХак)
    Программа позволяет производить покупки с помощью фейковой карты. Работает на очень малом количестве приложений.
  2. APK Editor Pro
    Полное модифицирование apk файлов на Android.

Инструкции по работе с программами, вы сможете найти в соответствующих им статьях.

A: Я не смог(ла) модифицировать игру, что делать?
B: Некоторые приложения возможно модифицировать только с помощью ручных способов.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *