1. 程式人生 > >如何在任意安卓應用中新增彈窗功能?

如何在任意安卓應用中新增彈窗功能?

可以在沒有原始碼的情況下,直接反編譯已經打包的APK安裝包,通過修改SMALI程式碼實現新增和去除部分功能,並在應用的任何地方新增任意程式碼,增加任意任何您想實現的功能。通過這種方式,把該應用變為您自己的應用(通過安卓修改大師反編譯生成的新應用僅供個人學習反編譯知識,嚴禁用於商業用途)。

安卓修改大師提供海量的應用、遊戲和電子書作為修改模板,您只需要在安卓修改大師中找到想要修改的應用,點選該應用的安裝或者一鍵安裝按鈕,即可自動開啟相關的反編譯選項。

本教程通過對最近流行的最美手電筒應用進行反編譯並重新打包,實現在使用者按下關閉手電筒按鈕的時候,彈出一個提示彈窗,提示使用者“哈哈~你必須付錢才能關掉我,您確定現在就要付錢嗎?”,如果使用者選擇確定,將開啟設定的網頁,如果使用者選擇取消,將關閉應用。

好了,閒話少說,我來開始演示如何進行反編譯和新增自定義程式碼吧~~

第一步,在安卓修改大師頂部的搜尋框輸入“手電筒”並開始搜尋(見下圖),搜尋列表中出現很多匹配到“手電筒”關鍵字的應用,點選“最美手電筒”後面的一鍵安裝按鈕, 系統會自動彈出相關的反編譯選項選單,可以通過本選單將應用安裝到手機,或者檢視原始碼,也可以直接進行反編譯。點選選單中的“反編譯”按鈕,進入到該應用的反編譯介面。

由於我們要實現的是點選關閉按鈕後彈出一個提示視窗,因此我們需要先找到這個關閉按鈕的圖片資源,以便通過資源名稱找到相應的介面和呼叫方法(如果是文字按鈕,就更簡單了,直接在安卓修改大師的搜尋功能裡面直接搜尋按鈕文字即可)。最美手電筒的原始介面如下。

我們在安卓修改大師的左側點選高階模式,然後一層層展開目錄列表,在drawable相關的目錄裡面瀏覽圖片,找到和應用執行介面圖對應的圖片資源,如下圖所示,分別是關閉狀態和開啟狀態的圖片。我們是要針對關閉按鈕進行操作,所以關注一下關閉按鈕的圖片資源名稱是 off 

通過搜尋功能或者直接在高階模式中瀏覽layout目錄,開啟相應的介面佈局,我們仔細觀察就可以找到Home.xml是這個最美手電筒的主介面,這個xml裡面包含了上述的關閉按鈕的圖片資源名稱。

雙擊開啟Home.xml,我們可以清晰的看到這個按鈕的圖片資源名稱和點選後呼叫的方法名稱“switchTorch”,見下圖。這個呼叫方法名稱很重要,我們通過這個名稱作為入口查詢該方法所在的程式碼頁面。

點選安卓修改大師的左側搜尋/替換功能,開啟的介面中輸入“switchTorch”進行搜尋,將搜尋到包含該關鍵字的所有的程式碼,通過雙擊開啟每個程式碼頁面分析,很快就能找到該方法所在的頁面,如下圖選中的一行。

雙擊開啟該程式碼頁面,可以看到,已經自動定位到了該呼叫方法,後續將通過在該方法裡面新增程式碼,來實現彈出提示視窗的功能。

將該程式碼頁面拉到頂部,第一行定義了該類名的包含包名的全路徑,下圖紅框內的路徑極為重要,後面很多地方會用到,需要記錄下來。

.class public Lcom/nanshan/simpletorch/home/HomeActivity;”

其中,紅顏色部分是包路徑,藍色部分是呼叫的本類的類名。

下面,就開始最核心的程式碼移植的工作了。點選高階模式,目錄瀏覽中,按照上面獲得的包名,依次從smali展開,逐級點選開啟目錄,一直到能看到上面獲得那個類名的檔案。然後點選右下角的開啟所在目錄,將開啟包名對應的磁碟目錄。

現在來講解一下要實現的功能對應的程式碼。安卓應用的反編譯程式碼移植採用的是smali語言,並非Java語言,需要您有一定的Smali的基礎知識。當然,如果您現在還完全不懂smali語言,也沒有關係,按照下面的教程拷貝貼上就可以了。

由於要實現的是提示彈窗功能,該功能有兩個按鈕,每個按鈕對應獨立的功能。在Smali裡面,一般一個獨立的功能類對應一個獨立的檔案。本功能對應的程式碼片段有三個,一個在關閉按鈕點下的時候呼叫的程式碼,另外兩個分別對應的是確定和取消的程式碼。

上述功能對應的java程式碼為:

                AlertDialog dialog = new AlertDialog.Builder(this)

                                 .setTitle("提示")// 設定對話方塊的標題

                                 .setMessage("哈哈~你必須付錢才能關掉我,您確定現在就要付錢嗎?")//  設定對話方塊的內容

                                 //  設定對話方塊的按鈕

                                 .setNegativeButton("取消",  new DialogInterface.OnClickListener() {

                                         @Override

                                         public  void onClick(DialogInterface  dialog, int which) {

                                                 dialog.dismiss();

                                         }

                                 }).setPositiveButton("確定",  new DialogInterface.OnClickListener() {

                                         @Override

                                         public  void onClick(DialogInterface  dialog, int which) {

                                                 Uri  uri = Uri.parse("http://www.apkeditor.cn/pay/default.aspx");

                                                 Intent  intent = new Intent(Intent.ACTION_VIEW,  uri);

                                                 startActivity(intent);

                                                 dialog.dismiss();

                                         }

                                 }).create();

                dialog.show();

由於安卓反編譯後修改邏輯必須在Smali檔案裡面修改,因此需要將上述程式碼轉換成Smali程式碼。下面已經轉換為Smali程式碼,只需要複製貼上即可。後續會出詳細教程講解如何將Java程式碼生成Smali程式碼。

下面是取消按鈕對應的程式碼,請在上述包名對應的目錄裡面建立一個文字檔案,命名為 ApkEditorLoader$1.smali “,將下面的程式碼拷貝到裡面,並將程式碼中所有的 Lcom/txeasy/shoudiantong/ “替換為之前獲得的包路徑,將程式碼中所有的 MainActivity “替換為之前獲得的類名。後面兩份程式碼也相同操作。

.class Lcom/txeasy/shoudiantong/ApkEditorLoader$1;

.super Ljava/lang/Object;

.source  "MainActivity.java"

#  interfaces

.implements  Landroid/content/DialogInterface$OnClickListener;

#  annotations

.annotation  system Ldalvik/annotation/EnclosingMethod;

    value = Lcom/txeasy/shoudiantong/MainActivity;->onCreate(Landroid/os/Bundle;)V

.end  annotation

.annotation  system Ldalvik/annotation/InnerClass;

    accessFlags  = 0x0

    name = null

.end  annotation

#  instance fields

.field  final synthetic this$0:Lcom/txeasy/shoudiantong/MainActivity;

# direct  methods

.method  constructor <init>(Lcom/txeasy/shoudiantong/MainActivity;)V

    .locals 0

    .prologue

    iput-object  p1, p0, Lcom/txeasy/shoudiantong/ApkEditorLoader$1;->this$0:Lcom/txeasy/shoudiantong/MainActivity;

    invoke-direct {p0}, Ljava/lang/Object;-><init>()V

    return-void

.end  method

# virtual  methods

.method  public onClick(Landroid/content/DialogInterface;I)V

    .locals 0

    .param  p1, "dialog"     # Landroid/content/DialogInterface;

    .param  p2, "which"     # I

    .prologue

    invoke-interface {p1}, Landroid/content/DialogInterface;->dismiss()V

    return-void

.end  method

確定按鈕對應的程式碼,請在上述包名對應的目錄裡面建立一個文字檔案,命名為 ApkEditorLoader$2.smali “程式碼中的包名和類名按照前述方法進行替換。

.class Lcom/txeasy/shoudiantong/ApkEditorLoader$2;

.super Ljava/lang/Object;

.source  "MainActivity.java"

# interfaces

.implements Landroid/content/DialogInterface$OnClickListener;

# annotations

.annotation system Ldalvik/annotation/EnclosingMethod;

    value =  Lcom/txeasy/shoudiantong/MainActivity;->onCreate(Landroid/os/Bundle;)V

.end annotation

.annotation system Ldalvik/annotation/InnerClass;

    accessFlags  = 0x0

    name = null

.end annotation

# instance fields

.field final synthetic this$0:Lcom/txeasy/shoudiantong/MainActivity;

# direct methods

.method constructor <init>(Lcom/txeasy/shoudiantong/MainActivity;)V

    .locals 0

    .prologue

    iput-object  p1, p0, Lcom/txeasy/shoudiantong/ApkEditorLoader$2;->this$0:Lcom/txeasy/shoudiantong/MainActivity;

    invoke-direct {p0}, Ljava/lang/Object;-><init>()V

    return-void

.end method

# virtual methods

.method public onClick(Landroid/content/DialogInterface;I)V

    .locals 3

    .param  p1, "dialog"     # Landroid/content/DialogInterface;

    .param  p2, "which"     # I

    .prologue

    const-string  v2, "http://www.apkeditor.cn/pay/default.aspx?username=xiaoping"

    invoke-static {v2}, Landroid/net/Uri;->parse(Ljava/lang/String;)Landroid/net/Uri;

    move-result-object v1

    .local v1, "uri":Landroid/net/Uri;

    new-instance v0, Landroid/content/Intent;

    const-string  v2, "android.intent.action.VIEW"

    invoke-direct {v0, v2,  v1},  Landroid/content/Intent;-><init>(Ljava/lang/String;Landroid/net/Uri;)V

    .local v0,  "intent":Landroid/content/Intent;

    iget-object  v2, p0, Lcom/txeasy/shoudiantong/ApkEditorLoader$2;->this$0:Lcom/txeasy/shoudiantong/MainActivity;

    invoke-virtual {v2, v0}, Lcom/txeasy/shoudiantong/MainActivity;->startActivity(Landroid/content/Intent;)V

    invoke-interface {p1}, Landroid/content/DialogInterface;->dismiss()V

    return-void

.end  method

需要植入到取消按鈕對應的方法裡面的程式碼,程式碼中的包路徑和類名按照前述方法進行替換後植入。

    move-object/from16 v0, p0

    new-instance v1, Landroid/app/AlertDialog$Builder;

    invoke-direct {v1, v0},  Landroid/app/AlertDialog$Builder;-><init>(Landroid/content/Context;)V

    const-string  v2, "\u63d0\u793a"

    invoke-virtual {v1, v2},  Landroid/app/AlertDialog$Builder;->setTitle(Ljava/lang/CharSequence;)Landroid/app/AlertDialog$Builder;

    move-result-object v1

    const-string  v2, "\u60a8\u6b63\u5728\u8fd0\u884c\u7684\u7a0b\u5e8f\u662f\u7531\u201c\u5b89\u5353\u4fee\u6539\u5927\u5e08\u201d\u53cd\u7f16\u8bd1\u751f\u6210\uff0c\u672a\u4ed8\u8d39\u7528\u6237\u751f\u6210\u7684\u5e94\u7528\u4f1a\u5f39\u51fa\u672c\u63d0\u793a\u7a97\u53e3\uff0c\u60a8\u9700\u8981\u73b0\u5728\u5c31\u5347\u7ea7\u201c\u5b89\u5353\u4fee\u6539\u5927\u5e08\u201d\u7684VIP\u4f1a\u5458\u5417\uff1f"

    invoke-virtual {v1, v2},  Landroid/app/AlertDialog$Builder;->setMessage(Ljava/lang/CharSequence;)Landroid/app/AlertDialog$Builder;

    move-result-object v1

    const-string  v2, "\u53d6\u6d88"

    new-instance v3, Lcom/txeasy/shoudiantong/ApkEditorLoader$1;

    invoke-direct {v3, v0}, Lcom/txeasy/shoudiantong/ApkEditorLoader$1;-><init>(Lcom/txeasy/shoudiantong/MainActivity;)V

    invoke-virtual {v1, v2,  v3},  Landroid/app/AlertDialog$Builder;->setNegativeButton(Ljava/lang/CharSequence;Landroid/content/DialogInterface$OnClickListener;)Landroid/app/AlertDialog$Builder;

    move-result-object v1

    const-string  v2, "\u786e\u5b9a"

    new-instance v3, Lcom/txeasy/shoudiantong/ApkEditorLoader$2;

    invoke-direct {v3, v0}, Lcom/txeasy/shoudiantong/ApkEditorLoader$2;-><init>(Lcom/txeasy/shoudiantong/MainActivity;)V

    invoke-virtual {v1, v2,  v3},  Landroid/app/AlertDialog$Builder;->setPositiveButton(Ljava/lang/CharSequence;Landroid/content/DialogInterface$OnClickListener;)Landroid/app/AlertDialog$Builder;

    move-result-object v1

    invoke-virtual {v1},  Landroid/app/AlertDialog$Builder;->create()Landroid/app/AlertDialog;

    move-result-object v0

    .local v0,  "dialog":Landroid/app/AlertDialog;

    invoke-virtual {v0}, Landroid/app/AlertDialog;->show()V

上述程式碼的藍色部分是提示資訊,該資訊必須為Unicode格式,例如下面的一句話:

哈哈~你必須付錢才能關掉我,您確定現在就要付錢嗎?

對應的Unicode是(請自行百度“Unicode編碼轉換”,會找到一個轉換的網站,輸入中文會自動轉換為unicode,拷貝過來替換即可):

\u54c8\u54c8\uff5e\u4f60\u5fc5\u987b\u4ed8\u94b1\u624d\u80fd\u5173\u6389\u6211\uff0c\u60a8\u786e\u5b9a\u73b0\u5728\u5c31\u8981\u4ed8\u94b1\u5417\uff1f

替換包路徑和類名的方法,如下圖:

建立好的取消和確認按鈕對應的程式碼檔案如下所示:

需要插入程式碼的方法(該方法如何定位,前面已經講過),由於是插入到取消按鈕點選後,因此將我們的植入程式碼拷貝到off方法的呼叫後面。

插入後的樣子:

好了,到此為止已經基本大功告成了,我們點選安卓修改大師左側的打包/簽名功能,開始進行打包環節,打包後,系統會自動提示你是否需要安裝到手機上。

下面就是我們的最終成果,安裝到手機上並點選關閉手電筒按鈕出現的效果。

您可以用這種方法反編譯任何安卓應用哦。只要您願意,您可以在任何應用上面新增任何功能。後面我們會出教程教大家如何新增任意功能,包括如何進行VIP會員的破解等等。

安卓優化大師非常強大,有更多更好玩的方法來折騰任何應用。都來玩玩看吧~我相信你一定能夠玩出你的新花樣。後面我們會推出更多的例項教程,教您如何破解遊戲關卡,甚至在應用中新增自己的功能。