遇到过这种场景吗?
什么样的场景需要从 smali 语言层面接入第三方 sdk 呢?
一般都是 java 语言接口,一目了然,搞个 smali 不是没事找事?
其实不然
场景不同,我还真就遇到这种常规操作
了 ———— 从 smali 接入 sdk
有一天
Leader 给你发一个 apk 文件
Leader:需要把我们的 sdk 接入到这个 apk 里面源码编辑器下载,但是没有 apk 的 Android 工程,能实现吗?
Programmer:应该可以,给我点时间研究下
Leade接口类型r:好,两天可以吧?我排期一下
Programmer:行
就这么简单:一个 apk,把我们的 sdk 接入到里面
不如写个 Demo 看看?
1、准备一个 sdk: gcsdk-1.0.0.jar
2、准备一个 apk: app-0.apk
【这个是需要你接入 sdk 的 apk】
3、创建一个空白 Android 项目,预备接入 sdk: 生成的 apk 备用 app-1.apk
我们简单实现一个 sdk,实际上接入的第三方 sdk 可能会更复杂一点
- gcsdk-1appearance.0.0 接入示例
// 初始化
GCSDK.getInstance().init(new InitCallback() {
@Override
public void initSuccess() {
System.out.println("gcsdk-初始化成功");
}
@Override
public void initFail(int code, String error) {
System.out.println("gcsdk-初始化失败:code = " + code + " error = " + error);
}
});
//登录
GCSDK.getInstance().login(new LoginCallback() {
@Override
public void onLoginSuccess() {
System.out.println("登录-成功");
}
@Override
public void inLoginFail(int code, String error) {
System.out.println("登录-失败:code = " + code + " error = " + error);
}
});
//广告
AdParams adParams = new AdParams();
GCSDK.getInstance().openAd(adParams, new AdCallback() {
@Override
public void onClick() {
System.out.println("广告-点击");
}
@Override
public void onClickSkip() {
System.out.println("广告-点击跳过");
}
@Override
public void onClose() {
System.out.println("广告-关闭");
}
@Override
public void onOpenFaild(int code, String error) {
System.out.println("广告-打开失败:code = " + code + " error = " + error);
}
@Override
public void onOpenSuccess() {
System.out.println("广告-打开成功");
}
@Override
public void onLoadBegin() {
System.out.println("广告-加载开始");
}
@Override
public void onLoadFaild(int code, String error) {
System.out.println("广告-加载失败:code = " + code + " error = " + error);
}
@Override
public void onLoadComplete() {
System.out.println("广告-加载完成");
}
@Override
public void onDownloadBegin() {
System.out.println("广告-下载开始");
}
@Override
public void onDownloadFail(int code, String error) {
System.out.println("广告-下载失败:code =" + code + " error = " + error);
}
@Override
public void onDownloadComplete() {
System.out.println("广告-下载完成");
}
});
//支付
PayParams payParams = new PayParams();
PayManager.getInstance().pay(payParams, new PayCallback() {
@Override
public void onPaySuccess() {
System.out.println("支付-成功");
}
@Override
public void onPayFail(int code, String error) {
System.out.println("支付-失败:code = " + code + " error = " + error);
}
});
- 创建一个空白的 Android 项目,开始接入 gcsdk接口卡,接入完成后appointment打包生成 apkAPP 留着备用,用于获取接入 sdk 的 smali 代码
以下是接入示例:
// App.java
package com.example.gcsdkdemo;
import android.app.Application;
import android.util.Log;
import com.primer.jsonlili.callback.InitCallback;
import com.primer.jsonlili.core.GCSDK;
public class App extends Application {
private final String TAG = "cunzhang";
//初始化回调
private InitCallback mInitCallback = new InitCallback() {
@Override
public void initSuccess() {
Log.d(TAG, "initSuccess: ");
}
@Override
public void initFail(int i, String s) {
Log.d(TAG, "initFail: ");
}
};
@Override
public void onCreate() {
super.onCreate();
//gcsdk 初始化
GCSDK.getInstance().init(mInitCallback);
}
}
//MainActivity.java
package com.example.gcsdkdemo;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import com.primer.jsonlili.callback.AdCallback;
import com.primer.jsonlili.callback.LoginCallback;
import com.primer.jsonlili.callback.PayCallback;
import com.primer.jsonlili.core.GCSDK;
import com.primer.jsonlili.params.AdParams;
import com.primer.jsonlili.params.PayParams;
public class MainActivity extends AppCompatActivity {
private final String TAG = "cunzhang";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void onPay(View view) {
Log.d(TAG, "onPay: ");
//支付接口
PayParams payParams = new PayParams();
GCSDK.getInstance().pay(payParams, new PayCallback() {
@Override
public void onPaySuccess() {
Log.d(TAG, "onPaySuccess: ");
}
@Override
public void onPayFail(int i, String s) {
Log.d(TAG, "onPayFail: ");
}
});
}
public void onLogin(View view) {
Log.d(TAG, "onLogin: ");
//登录接口
GCSDK.getInstance().login(new LoginCallback() {
@Override
public void onLoginSuccess() {
Log.d(TAG, "onLoginSuccess: ");
}
@Override
public void inLoginFail(int i, String s) {
Log.d(TAG, "inLoginFail: ");
}
});
}
public void onOpenAd(View view) {
Log.d(TAG, "onOpenAd: ");
//广告接口
AdParams adParams = new AdParams();
GCSDK.getInstance().openAd(adParams, new AdCallback() {
@Override
public void onClick() {
Log.d(TAG, "onClick: ");
}
@Override
public void onClickSkip() {
Log.d(TAG, "onClickSkip: ");
}
@Override
public void onClose() {
Log.d(TAG, "onClose: ");
}
@Override
public void onOpenFaild(int i, String s) {
Log.d(TAG, "onOpenFaild: ");
}
@Override
public void onOpenSuccess() {
Log.d(TAG, "onOpenSuccess: ");
}
@Override
public void onLoadBegin() {
Log.d(TAG, "onLoadBegin: ");
}
@Override
public void onLoadFaild(int i, String s) {
Log.d(TAG, "onLoadFaild: ");
}
@Override
public void onLoadComplete() {
Log.d(TAG, "onLoadComplete: ");
}
@Override
public void onDownloadBegin() {
Log.d(TAG, "onDownloadBegin: ");
}
@Override
public void onDownloadFail(int i, String s) {
Log.d(TAG, "onDownloadFail: ");
}
@Override
public void onDownloadComplete() {
Log.d(TAG, "onDownloadComplete: ");
}
});
}
}
接入完毕后,以此触发按钮点源码网站击事件,效果如下:
- Leader 的 apk:
也模拟创建一个 apk,比较简单,每一个 fragment 有一个按钮,我们的目的也很明确 为每个按钮的点击事件实现对应 sd初始化失败是怎么解决k 的接口调用
了解下项目中的 smali?
1、获得 smaliandroidstudio安装教程
java -jar apktool_2.6.0.jar [-r] d app-0.apk
java -jar apktool_2.6.0.jar [-r] d app-1.apk
Leader 的 apk:
模拟接入 sdk 的 apk:
2、简单了解项目的 smali 实APP现
本次使用 VSCode 查看 smali 代码,同时安装插件 smali、smali2java
模拟接入 sdk 的 apk
- App.java & App.smali
以下 smali 主要是列举与 sdk 相关,主要关注的是——sdk 接入相关代码生成的 s源码1688mali 具体有哪些、是如何结接口类型合使用的
package com.example.gcsdkdemo;
import android.app.Application;
import android.util.Log;
import com.primer.jsonlili.callback.InitCallback;
import com.primer.jsonlili.core.GCSDK;
public class App extends Application {
private final String TAG = "cunzhang";
//属性定义:.field private mInitCallback:Lcom/primer/jsonlili/callback/InitCallback;
//类的 <init> 方法中创建对象并赋值:
//new-instance v0, Lcom/example/gcsdkdemo/App$1;
//invoke-direct {v0, p0}, Lcom/example/gcsdkdemo/App$1;-><init>(Lcom/example/gcsdkdemo/App;)V
//iput-object v0, p0, Lcom/example/gcsdkdemo/App;->mInitCallback:Lcom/primer/jsonlili/callback/InitCallback;
private InitCallback mInitCallback = new InitCallback() {
@Override
public void initSuccess() {
Log.d(TAG, "initSuccess: ");
}
@Override
public void initFail(int i, String s) {
Log.d(TAG, "initFail: ");
}
};
@Override
public void onCreate() {
super.onCreate();
//初始化,v0 当前类 this 引用传入内部类中,为内部类初始化赋值
//invoke-static {}, Lcom/primer/jsonlili/core/GCSDK;->getInstance()Lcom/primer/jsonlili/core/GCSDK;
//move-result-object v0
//iget-object v1, p0, Lcom/example/gcsdkdemo/App;->mInitCallback:Lcom/primer/jsonlili/callback/InitCallback;
//invoke-virtual {v0, v1}, Lcom/primer/jsonlili/core/GCSDK;->init(Lcom/primer/jsonlili/callback/InitCallback;)V
GCSDK.getInstance().init(mInitCallback);
}
}
- InitCallback 内部类实现
.class Lcom/example/gcsdkdemo/App$1;
.super Ljava/lang/Object;
.source "App.java"
# interfaces
.implements Lcom/primer/jsonlili/callback/InitCallback;
# annotations
.annotation system Ldalvik/annotation/EnclosingClass;
value = Lcom/example/gcsdkdemo/App;
.end annotation
# 内部类
.annotation system Ldalvik/annotation/InnerClass;
accessFlags = 0x0
name = null
.end annotation
# 内部类持有外部类 this 引用
# instance fields
.field final synthetic this$0:Lcom/example/gcsdkdemo/App;
# direct methods
.method constructor <init>(Lcom/example/gcsdkdemo/App;)V
.locals 0
.param p1, "this$0" # Lcom/example/gcsdkdemo/App;
.line 13
iput-object p1, p0, Lcom/example/gcsdkdemo/App$1;->this$0:Lcom/example/gcsdkdemo/App;
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
return-void
.end method
# virtual methods
.method public initFail(ILjava/lang/String;)V
# 指定方法中可用的非参寄存器数量
.locals 2
.param p1, "i" # I
.param p2, "s" # Ljava/lang/String;
.line 21
const-string v0, "cunzhang"
const-string v1, "initFail: "
invoke-static {v0, v1}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
.line 22
return-void
.end method
.method public initSuccess()V
.locals 2
.line 16
const-string v0, "cunzhang"
const-string v1, "initSuccess: "
invoke-static {v0, v1}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
.line 17
return-void
.end method
- MainActivity.java $ Mai源码时代nActivity.smali
package com.example.gcsdkdemo;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import com.primer.jsonlili.callback.AdCallback;
import com.primer.jsonlili.callback.LoginCallback;
import com.primer.jsonlili.callback.PayCallback;
import com.primer.jsonlili.core.GCSDK;
import com.primer.jsonlili.params.AdParams;
import com.primer.jsonlili.params.PayParams;
public class MainActivity extends AppCompatActivity {
private final String TAG = "cunzhang";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void onPay(View view) {
Log.d(TAG, "onPay: ");
//创建 PayParams 对象并存储到 v0,
//new-instance v0, Lcom/primer/jsonlili/params/PayParams;
//invoke-direct {v0}, Lcom/primer/jsonlili/params/PayParams;-><init>()V
//.local v0, "payParams":Lcom/primer/jsonlili/params/PayParams;
//invoke-static {}, Lcom/primer/jsonlili/core/GCSDK;->getInstance()Lcom/primer/jsonlili/core/GCSDK;
//move-result-object v1
//new-instance v2, Lcom/example/gcsdkdemo/MainActivity$1;
//invoke-direct {v2, p0}, Lcom/example/gcsdkdemo/MainActivity$1;-><init>(Lcom/example/gcsdkdemo/MainActivity;)V
//invoke-virtual {v1, v0, v2}, Lcom/primer/jsonlili/core/GCSDK;->pay(Lcom/primer/jsonlili/params/PayParams;Lcom/primer/jsonlili/callback/PayCallback;)V
PayParams payParams = new PayParams();
GCSDK.getInstance().pay(payParams, new PayCallback() {
@Override
public void onPaySuccess() {
Log.d(TAG, "onPaySuccess: ");
}
@Override
public void onPayFail(int i, String s) {
Log.d(TAG, "onPayFail: ");
}
});
}
public void onLogin(View view) {
Log.d(TAG, "onLogin: ");
//调用 getInstance,把 getInstance 返回的对象存储到 v0,创建内部类 LoginCallback 对象,调用内部类初始化,调用登录方法
//invoke-static {}, Lcom/primer/jsonlili/core/GCSDK;->getInstance()Lcom/primer/jsonlili/core/GCSDK;
//move-result-object v0
//new-instance v1, Lcom/example/gcsdkdemo/MainActivity$2;
//invoke-direct {v1, p0}, Lcom/example/gcsdkdemo/MainActivity$2;-><init>(Lcom/example/gcsdkdemo/MainActivity;)V
//invoke-virtual {v0, v1}, Lcom/primer/jsonlili/core/GCSDK;->login(Lcom/primer/jsonlili/callback/LoginCallback;)V
GCSDK.getInstance().login(new LoginCallback() {
@Override
public void onLoginSuccess() {
Log.d(TAG, "onLoginSuccess: ");
}
@Override
public void inLoginFail(int i, String s) {
Log.d(TAG, "inLoginFail: ");
}
});
}
public void onOpenAd(View view) {
Log.d(TAG, "onOpenAd: ");
//new-instance v0, Lcom/primer/jsonlili/params/AdParams;
//invoke-direct {v0}, Lcom/primer/jsonlili/params/AdParams;-><init>()V
//.line 60
//.local v0, "adParams":Lcom/primer/jsonlili/params/AdParams;
//invoke-static {}, Lcom/primer/jsonlili/core/GCSDK;->getInstance()Lcom/primer/jsonlili/core/GCSDK;
//move-result-object v1
//new-instance v2, Lcom/example/gcsdkdemo/MainActivity$3;
//invoke-direct {v2, p0}, Lcom/example/gcsdkdemo/MainActivity$3;-><init>(Lcom/example/gcsdkdemo/MainActivity;)V
//invoke-virtual {v1, v0, v2}, Lcom/primer/jsonlili/core/GCSDK;->openAd(Lcom/primer/jsonlili/params/AdParams;Lcom/primer/jsonlili/callback/AdCallback;)V
AdParams adParams = new AdParams();
GCSDK.getInstance().openAd(adParams, new AdCallback() {
@Override
public void onClick() {
Log.d(TAG, "onClick: ");
}
@Override
public void onClickSkip() {
Log.d(TAG, "onClickSkip: ");
}
@Override
public void onClose() {
Log.d(TAG, "onClose: ");
}
@Override
public void onOpenFaild(int i, String s) {
Log.d(TAG, "onOpenFaild: ");
}
@Override
public void onOpenSuccess() {
Log.d(TAG, "onOpenSuccess: ");
}
@Override
public void onLoadBegin() {
Log.d(TAG, "onLoadBegin: ");
}
@Override
public void onLoadFaild(int i, String s) {
Log.d(TAG, "onLoadFaild: ");
}
@Override
public void onLoadComplete() {
Log.d(TAG, "onLoadComplete: ");
}
@Override
public void onDownloadBegin() {
Log.d(TAG, "onDownloadBegin: ");
}
@Override
public void onDownloadFail(int i, String s) {
Log.d(TAG, "onDownloadFail: ");
}
@Override
public void onDownloadComplete() {
Log.d(TAG, "onDownloadComplete: ");
}
});
}
}
- PayCallbaandroid平板电脑价格ck 内部类实现
.class Lcom/example/gcsdkdemo/MainActivity$1;
.super Ljava/lang/Object;
.source "MainActivity.java"
# interfaces
.implements Lcom/primer/jsonlili/callback/PayCallback;
# annotations
.annotation system Ldalvik/annotation/EnclosingMethod;
value = Lcom/example/gcsdkdemo/MainActivity;->onPay(Landroid/view/View;)V
.end annotation
.annotation system Ldalvik/annotation/InnerClass;
accessFlags = 0x0
name = null
.end annotation
# instance fields
.field final synthetic this$0:Lcom/example/gcsdkdemo/MainActivity;
# direct methods
.method constructor <init>(Lcom/example/gcsdkdemo/MainActivity;)V
.locals 0
.param p1, "this$0" # Lcom/example/gcsdkdemo/MainActivity;
.line 28
iput-object p1, p0, Lcom/example/gcsdkdemo/MainActivity$1;->this$0:Lcom/example/gcsdkdemo/MainActivity;
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
return-void
.end method
# virtual methods
.method public onPayFail(ILjava/lang/String;)V
.locals 2
.param p1, "i" # I
.param p2, "s" # Ljava/lang/String;
.line 36
const-string v0, "cunzhang"
const-string v1, "onPayFail: "
invoke-static {v0, v1}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
.line 37
return-void
.end method
.method public onPaySuccess()V
.locals 2
.line 31
const-string v0, "cunzhang"
const-string v1, "onPaySuccess: "
invoke-static {v0, v1}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
.line 32
return-void
.end method
- 内部类 LoginCallback 实现
.class Lcom/example/gcsdkdemo/MainActivity$2;
.super Ljava/lang/Object;
.source "MainActivity.java"
# interfaces
.implements Lcom/primer/jsonlili/callback/LoginCallback;
# annotations
.annotation system Ldalvik/annotation/EnclosingMethod;
value = Lcom/example/gcsdkdemo/MainActivity;->onLogin(Landroid/view/View;)V
.end annotation
.annotation system Ldalvik/annotation/InnerClass;
accessFlags = 0x0
name = null
.end annotation
# instance fields
.field final synthetic this$0:Lcom/example/gcsdkdemo/MainActivity;
# direct methods
.method constructor <init>(Lcom/example/gcsdkdemo/MainActivity;)V
.locals 0
.param p1, "this$0" # Lcom/example/gcsdkdemo/MainActivity;
.line 43
iput-object p1, p0, Lcom/example/gcsdkdemo/MainActivity$2;->this$0:Lcom/example/gcsdkdemo/MainActivity;
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
return-void
.end method
# virtual methods
.method public inLoginFail(ILjava/lang/String;)V
.locals 2
.param p1, "i" # I
.param p2, "s" # Ljava/lang/String;
.line 51
const-string v0, "cunzhang"
const-string v1, "inLoginFail: "
invoke-static {v0, v1}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
.line 52
return-void
.end method
.method public onLoginSuccess()V
.locals 2
.line 46
const-string v0, "cunzhang"
const-string v1, "onLoginSuccess: "
invoke-static {v0, v1}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
.line 47
return-void
.end method
- AdCallback 内部类实现
.class Lcom/example/gcsdkdemo/MainActivity$3;
.super Ljava/lang/Object;
.source "MainActivity.java"
# interfaces
.implements Lcom/primer/jsonlili/callback/AdCallback;
# annotations
.annotation system Ldalvik/annotation/EnclosingMethod;
value = Lcom/example/gcsdkdemo/MainActivity;->onOpenAd(Landroid/view/View;)V
.end annotation
.annotation system Ldalvik/annotation/InnerClass;
accessFlags = 0x0
name = null
.end annotation
# instance fields
.field final synthetic this$0:Lcom/example/gcsdkdemo/MainActivity;
# direct methods
.method constructor <init>(Lcom/example/gcsdkdemo/MainActivity;)V
.locals 0
.param p1, "this$0" # Lcom/example/gcsdkdemo/MainActivity;
.line 60
iput-object p1, p0, Lcom/example/gcsdkdemo/MainActivity$3;->this$0:Lcom/example/gcsdkdemo/MainActivity;
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
return-void
.end method
# virtual methods
.method public onClick()V
.locals 2
.line 63
const-string v0, "cunzhang"
const-string v1, "onClick: "
invoke-static {v0, v1}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
.line 64
return-void
.end method
.method public onClickSkip()V
.locals 2
.line 68
const-string v0, "cunzhang"
const-string v1, "onClickSkip: "
invoke-static {v0, v1}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
.line 69
return-void
.end method
.method public onClose()V
.locals 2
.line 73
const-string v0, "cunzhang"
const-string v1, "onClose: "
invoke-static {v0, v1}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
.line 74
return-void
.end method
.method public onDownloadBegin()V
.locals 2
.line 103
const-string v0, "cunzhang"
const-string v1, "onDownloadBegin: "
invoke-static {v0, v1}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
.line 104
return-void
.end method
.method public onDownloadComplete()V
.locals 2
.line 113
const-string v0, "cunzhang"
const-string v1, "onDownloadComplete: "
invoke-static {v0, v1}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
.line 114
return-void
.end method
.method public onDownloadFail(ILjava/lang/String;)V
.locals 2
.param p1, "i" # I
.param p2, "s" # Ljava/lang/String;
.line 108
const-string v0, "cunzhang"
const-string v1, "onDownloadFail: "
invoke-static {v0, v1}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
.line 109
return-void
.end method
.method public onLoadBegin()V
.locals 2
.line 88
const-string v0, "cunzhang"
const-string v1, "onLoadBegin: "
invoke-static {v0, v1}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
.line 89
return-void
.end method
.method public onLoadComplete()V
.locals 2
.line 98
const-string v0, "cunzhang"
const-string v1, "onLoadComplete: "
invoke-static {v0, v1}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
.line 99
return-void
.end method
.method public onLoadFaild(ILjava/lang/String;)V
.locals 2
.param p1, "i" # I
.param p2, "s" # Ljava/lang/String;
.line 93
const-string v0, "cunzhang"
const-string v1, "onLoadFaild: "
invoke-static {v0, v1}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
.line 94
return-void
.end method
.method public onOpenFaild(ILjava/lang/String;)V
.locals 2
.param p1, "i" # I
.param p2, "s" # Ljava/lang/String;
.line 78
const-string v0, "cunzhang"
const-string v1, "onOpenFaild: "
invoke-static {v0, v1}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
.line 79
return-void
.end method
.method public onOpenSuccess()V
.locals 2
.line 83
const-string v0, "cunzhang"
const-string v1, "onOpenSuccess: "
invoke-static {v0, v1}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
.line 84
return-void
.end method
“日久生情”,代码看多了自然掌握的 smali 知识的就更多吧
Leader 的 apk
假如我们已知代码插入点(调用点源码编程器)位置————对应按钮的点击事件;那么我们更应该的点是——找到对应按钮的点击事件所在位置、如何正确插入 smali 代初始化电脑的后果码
要不 smali 接入看看?
1、先把 sdk 相关的所有 smali 源码复制到预备接入 apk 反编译的工程目录适当位置处
这里我新建 smali_classes9
目录,gcsdk 比初始化是什么意思较简单,只接口测试用例设计有纯代码,没有资源、soappstore 文件等;如果有,也需要复制到工程的相应目录下,确保项目能够编译成功、运行期间能加载到代码,这是项目能够运行的前提。
下面就开始往预备接入的 apk 代码中合适位置插入 sdk smali 代码。
2、LeaderApp.java & LeaderApp.smali
.class public Lcom/example/leaderapp/ui/LeaderApp;
.super Landroid/app/Application;
.source "LeaderApp.java"
# instance fields
.field private final TAG:Ljava/lang/String;
# -----1、定义初始化回调字段
.field private mInitCallback:Lcom/primer/jsonlili/callback/InitCallback;
# direct methods
.method public constructor <init>()V
.locals 1
.line 6
invoke-direct {p0}, Landroid/app/Application;-><init>()V
.line 7
const-string v0, "leader"
iput-object v0, p0, Lcom/example/leaderapp/ui/LeaderApp;->TAG:Ljava/lang/String;
# -----2、初始化方法中创建内部类对象
new-instance v0, Lcom/example/leaderapp/ui/LeaderApp$1;
invoke-direct {v0, p0}, Lcom/example/leaderapp/ui/LeaderApp$1;-><init>(Lcom/example/leaderapp/ui/LeaderApp;)V
iput-object v0, p0, Lcom/example/leaderapp/ui/LeaderApp;->mInitCallback:Lcom/primer/jsonlili/callback/InitCallback;
return-void
.end method
# virtual methods
.method public onCreate()V
.locals 2
.line 11
invoke-super {p0}, Landroid/app/Application;->onCreate()V
.line 12
const-string v0, "leader"
const-string v1, "onCreate: "
invoke-static {v0, v1}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
# -----3、调用初始化方法
invoke-static {}, Lcom/primer/jsonlili/core/GCSDK;->getInstance()Lcom/primer/jsonlili/core/GCSDK;
move-result-object v0
iget-object v1, p0, Lcom/example/leaderapp/ui/LeaderApp;->mInitCallback:Lcom/primer/jsonlili/callback/InitCallback;
invoke-virtual {v0, v1}, Lcom/primer/jsonlili/core/GCSDK;->init(Lcom/primer/jsonlili/callback/InitCallback;)V
return-void
.end method
# -----4、创建 LeaderApp$1.smali,并更新路径、类等
插入完毕之后我们可以使用 VSCODE smali 插件代码转换查看是否插入初始化磁盘正确,可以做对比
代码转换,原始项目和插入后的代码看效果是一致的
手动签名、安装运行看日志,能看到 sdk 初始化正确,再次说明上述接入是无误的。
jarsigner -verbAPPose -keystore aa.keystore sign-app0.apk app-android平板电脑价格0.apk key0
Tips:
- 之前使用初始化电脑时出现问题
java -jar apktool.jar d ***.apk
反编译源码编辑器安装包,但在回编译时候可能回出现下面的错误,导致打包失败,日志中提到res/
目录,看日志像是资源问题。
W: invalid resource directory nam接口crc错误计数e: >/Users/jso源码nli/Desktop接口是什么/demo/0603/app-0/app-0/res navigati接口和抽象类的区别on brut.androlib.AndrolibExcep接口测试用例设计tion: brut.common.Br接口和抽象类的区别utException: could not exec (exit code = 1):
/Users/jsonli/Library/apktool/framework/1.apk, -S,
/Users/jsonli/Desktop/demo/0603/app-0/app-0/res, -M,
/Users/jsonli/Desktop/demo/0603/app-0/app-0/AndroidManifest.xml]
那么反编译时候不处理资源试试,apktool 加上 -r 参数java -jar apktool.jar -r d ***.apk
,接着打包正常。
- apktool 使用说明
-advance,–advanced prints advaapplence information.
-veandroid什么意思rsion,–version prints the接口类型 version then exits usage: apk源码编程器tool if|install-framework [options] <framewo初始化失败是怎么解决rk.apk&approachgt;
-p,–frame-pat源码精灵永久兑换码h
Storandroid下载安装es framework fil接口crc错误计数es into .-t,–tag Tag frameworks using . usage: apktool d[ecode] [options] <file_apk>
-f,–force Fapproveorce delete destinandroid是什么手机牌子ation directory.
-o,–output
The name of folder that gets written. Default is apk.android是什么系统out-p,–frame-path
Uses framework files located in .-r,–no-res Do not decode resources.【对资源不做处理】
-s,–no-src Do not decode sources.
-tandroid什么意思,–frame-tag Uses framework files tagged by .usage: apktool b[uild] [options] <app_path>
-f,–force-all Skip changes detection and buildappstore all files.
-o,–接口测试ou初始化失败是怎么解决tput
The n接口是什么ame of apk that gets初始化电脑的后果 written. Default is d源码精灵永久兑换码ist/name.apk-p,–frame-path
Uses framework files located in .
那继续完成剩下的接入吧 :)
3、HomeFandroid/harmonyosragment1源码1688.smali、HomeFandroid平板电脑价格rgment1.smali、HomeFrgment2.smali
HomeFragment$1.smali
: button 点击事件实现类,在此调用登录
HomeFragment$2.smali
: gcsdk 登录回调
.line
: 行号说明,可以去掉,不影响代码执行,主要作用android的drawable类是说明代码在原始 Java 文件中的具体位置
.class Lcom/example/leaderapp/ui/home/HomeFragment$1;
.super Ljava/lang/Object;
.source "HomeFragment.java"
# interfaces
.implements Landroid/view/View$OnClickListener;
# annotations
.annotation system Ldalvik/annotation/EnclosingMethod;
value = Lcom/example/leaderapp/ui/home/HomeFragment;->onCreateView(Landroid/view/LayoutInflater;Landroid/view/ViewGroup;Landroid/os/Bundle;)Landroid/view/View;
.end annotation
.annotation system Ldalvik/annotation/InnerClass;
accessFlags = 0x0
name = null
.end annotation
# instance fields
.field final synthetic this$0:Lcom/example/leaderapp/ui/home/HomeFragment;
# direct methods
.method constructor <init>(Lcom/example/leaderapp/ui/home/HomeFragment;)V
.locals 0
.param p1, "this$0" # Lcom/example/leaderapp/ui/home/HomeFragment;
.line 40
iput-object p1, p0, Lcom/example/leaderapp/ui/home/HomeFragment$1;->this$0:Lcom/example/leaderapp/ui/home/HomeFragment;
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
return-void
.end method
# virtual methods
.method public onClick(Landroid/view/View;)V
.locals 3
.param p1, "view" # Landroid/view/View;
.line 43
invoke-virtual {p1}, Landroid/view/View;->getContext()Landroid/content/Context;
move-result-object v0
const-string v1, "u767bu5f55"
const/4 v2, 0x0
invoke-static {v0, v1, v2}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;
move-result-object v0
invoke-virtual {v0}, Landroid/widget/Toast;->show()V
.line 44
const-string v0, "leader"
const-string v1, "onClick: login"
invoke-static {v0, v1}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
# -----1、调用登录接口,修改类路径、内部类(登录回调实现类)
invoke-static {}, Lcom/primer/jsonlili/core/GCSDK;->getInstance()Lcom/primer/jsonlili/core/GCSDK;
move-result-object v0
new-instance v1, Lcom/example/leaderapp/ui/home/HomeFragment$2;
# ----- 内部类持有外部类引用,这里的外部类是 button 的点击事件实现类,因此传入 HomeFragment$1,而不是 HomeFragment
invoke-direct {v1, p0}, Lcom/example/leaderapp/ui/home/HomeFragment$2;-><init>(Lcom/example/leaderapp/ui/home/HomeFragment$1;)V
invoke-virtual {v0, v1}, Lcom/primer/jsonlili/core/GCSDK;->login(Lcom/primer/jsonlili/callback/LoginCallback;)V
return-void
.end method
.class Lcom/example/leaderapp/ui/home/HomeFragment$2;
.super Ljava/lang/Object;
.source "HomeFragment.java"
# -----2、创建内部类文件,并把对应的登录回调代码复制过来
# -----3、修改类路径 .class、.source、
# interfaces
.implements Lcom/primer/jsonlili/callback/LoginCallback;
# annotations
.annotation system Ldalvik/annotation/EnclosingMethod;
value = Lcom/example/leaderapp/ui/home/HomeFragment;->onLogin(Landroid/view/View;)V
.end annotation
.annotation system Ldalvik/annotation/InnerClass;
accessFlags = 0x0
name = null
.end annotation
# 这里传入的外部类是 button 点击事件实现类,因此初始化函数和 this 类型应该是
# instance fields
.field final synthetic this$0:Lcom/example/leaderapp/ui/home/HomeFragment$1;
# direct methods
.method constructor <init>(Lcom/example/leaderapp/ui/home/HomeFragment$1;)V
.locals 0
.param p1, "this$0"
# 这里也是 HomeFragment$1
iput-object p1, p0, Lcom/example/leaderapp/ui/home/HomeFragment$2;->this$0:Lcom/example/leaderapp/ui/home/HomeFragment$1;
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
return-void
.end method
# virtual methods
.method public inLoginFail(ILjava/lang/String;)V
.locals 2
.param p1, "i" # I
.param p2, "s" # Ljava/lang/String;
.line 51
const-string v0, "cunzhang"
const-string v1, "inLoginFail: "
invoke-static {v0, v1}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
.line 52
return-void
.end method
.method public onLoginSuccess()V
.locals 2
.line 46
const-string v0, "cunzhang"
const-string v1, "onLoginSuccess: "
invoke-static {v0, v1}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
.line 47
return-void
.end method
4、Notific接口crc错误计数ationsFragment.smali、D源码时代ashboardAndroidFragmeappreciatent.smali
因为代码简单,且逻辑一致,剩下的支付和接口类型广告接口代码就不贴出来了,跟上述接入十分相似,没application有比较特别的地方。
检验结果与思考
结果:
- smali 代码android/harmonyos插入完毕、保存
- 使用 apktool 重新打包
- 使用签名工具重新签名
依此点击按钮,触发点击事件,运行结果如我所愿,一切正常。
思考:
A:为什么搞 smali 接入这么复杂
,这不是给自己找坑吗?源码编程器
B:有时候真的存在这种场景,也是无措之举…
A:既然你已有 apk,可以把它转换为 java 代码,在 java 代接口测试用例设计码上接入不更清晰、省事,免除遇到很接口是什么多未知的坑,咋不这么干?
Bapprove:好像初始化是什么意思…也 可 以?
A:我觉得可以,借助 Androidandroid平板电脑价格Fk 工初始化游戏启动器失败具可以直接从 apk 中反编译出 java 代码,当然————如果是加固、加密的 apk 可能就没那么容易了!!!
B:我觉得也是,在 java 代码上接入方便多了。
B:我是有点想不明白,我遇到的一家 CP 就是直接在 smali 上面接入的!难道说是技术过硬,哪里接入都一样?或者有什么特接口和抽象类的区别殊的场景初始化失败是怎么解决???
A:想不明白就不想了,有时间你可以试试我说的转 java 之后接入
B:好的,村长
A:如果接入的第三方 sdk 是一个 aAPPar,包含一些资源文件,接入会不初始化英文会遇到其他问题?
B:这不是没可能,实操过方知晓
A:那下次准备下
B:… …
smali 可能没有想象中的那么简单,
也可能就是这么简单,
之间的差距可能就是对 smali 的认识和理解深浅之别。