闲鱼图片与视频文件上传

闲鱼图片与视频文件上传

开启日志后,发现上传相关的代码所在类都以com.uploader.implement开头。反编译后发现一个比较关键的类com.uploader.implement.UploaderManager, trace其方法,发现图片、视频上传都会调用uploadAsync方法。

image-20240611131244389

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
//视频
UploaderManager->uploadAsync (argType: com.uploader.export.IUploaderTask): [object Object]
UploaderManager->uploadAsync (argType: com.uploader.export.ITaskListener): [object Object]
UploaderManager->uploadAsync (argType: android.os.Handler): Handler (android.os.Handler) {9061007}
UploaderManager->uploadAsync (argType: boolean): false
UploaderManager->uploadAsync (retType: boolean): true
java.lang.Exception
at com.uploader.implement.UploaderManager.uploadAsync(Native Method)
at com.uploader.implement.UploaderManager.uploadAsync(UploaderManager.java:1)
at com.taobao.idlefish.uploader.UploaderImageManager.uploadAsync(UploaderImageManager.java:20)
at com.taobao.fleamarket.push.plugin.processors.fluttermessage.FlutterUploadVideoProcessor.uploadVideo(FlutterUploadVideoProcessor.java:78)
at com.taobao.fleamarket.push.plugin.IdlefishIMMethodPlugin.onMethodCall(IdlefishIMMethodPlugin.java:582)
at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler.onMessage(MethodChannel.java:18)
at io.flutter.embedding.engine.dart.DartMessenger.invokeHandler(DartMessenger.java:19)
at io.flutter.embedding.engine.dart.DartMessenger.lambda$dispatchMessageToQueue$0(DartMessenger.java:18)
at io.flutter.embedding.engine.dart.DartMessenger.$r8$lambda$TsixYUB5E6FpKhMtCSQVHKE89gQ(DartMessenger.java:1)
at io.flutter.embedding.engine.dart.DartMessenger$$ExternalSyntheticLambda0.run(R8$$SyntheticClass:13)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:224)
at android.app.ActivityThread.main(ActivityThread.java:7584)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:539)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:950)

// 图片
UploaderManager->uploadAsync (argType: com.uploader.export.IUploaderTask): [object Object]
UploaderManager->uploadAsync (argType: com.uploader.export.ITaskListener): [object Object]
UploaderManager->uploadAsync (argType: android.os.Handler): Handler (android.os.Handler) {f6d0732}
UploaderManager->uploadAsync (argType: boolean): false
UploaderManager->uploadAsync (retType: boolean): true
java.lang.Exception
at com.uploader.implement.UploaderManager.uploadAsync(Native Method)
at com.uploader.implement.UploaderManager.uploadAsync(UploaderManager.java:1)
at com.taobao.mediaupload.imageupload.ImageUploadManager.uploadAsync(ImageUploadManager.java:20)
at com.taobao.mediaupload.MediaUploadPlugin.onMethodCall(MediaUploadPlugin.java:285)
at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler.onMessage(MethodChannel.java:18)
at io.flutter.embedding.engine.dart.DartMessenger.invokeHandler(DartMessenger.java:19)
at io.flutter.embedding.engine.dart.DartMessenger.lambda$dispatchMessageToQueue$0(DartMessenger.java:18)
at io.flutter.embedding.engine.dart.DartMessenger.$r8$lambda$TsixYUB5E6FpKhMtCSQVHKE89gQ(DartMessenger.java:1)
at io.flutter.embedding.engine.dart.DartMessenger$$ExternalSyntheticLambda0.run(R8$$SyntheticClass:13)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:224)
at android.app.ActivityThread.main(ActivityThread.java:7584)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:539)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:950)

图片上传的代码com.taobao.mediaupload.MediaUploadPlugin

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
package com.taobao.mediaupload;

public class MediaUploadPlugin extends BaseFlutterEventPlugin {
interface UploadProcessListener {
void onProcess(String arg1, int arg2);
}

static class UploadTask {
public IUploaderTask imageUploaderTask;
public String videoUploadTaskId;

private UploadTask() {
}

UploadTask(int v) {
}
}

public static final int $r8$clinit;
private static Handler mHandler;
private com.taobao.mediaupload.MediaUploadPlugin.1 mUploadProcessListener;
private Map mUploadTasks;

@Override // io.flutter.plugin.common.MethodChannel$MethodCallHandler
public final void onMethodCall(MethodCall methodCall0, Result methodChannel$Result0) {
IUploaderTask iUploaderTask1;
ImageUploadManager imageUploadManager2;
HashMap hashMap10;
IUploaderTask iUploaderTask0;
ImageUploadManager imageUploadManager0;
Long long0;
HashMap hashMap4;
MediaUploadPlugin mediaUploadPlugin0 = this;
MethodCall methodCall1 = methodCall0;
Result methodChannel$Result1 = methodChannel$Result0;
MediaUploadPlugin.printTLog("onMethodCall", f..ExternalSyntheticOutline0.m("methodName=", methodCall1.method), ((HashMap)methodCall1.arguments));
Class class0 = PTBS.class;
String s = methodCall1.method;
if(methodCall1.method.equals("uploadImage")) {
HashMap hashMap0 = (HashMap)methodCall1.arguments;
String path = (String)hashMap0.get("path");
boolean z = ((Boolean)hashMap0.get("delete")).booleanValue();
String bizeCode = (String)hashMap0.get("bizeCode");
String s3 = (String)hashMap0.get("privacySubBusiness");
String s4 = (String)hashMap0.get("privacyScene");
try {
if(TextUtils.isEmpty(path)) {
MediaUploadPlugin.printTLog("uploadImage", "uploadImage error, path is empty", null);
HashMap hashMap1 = new HashMap();
hashMap1.put("errCode", "-1");
hashMap1.put("errMsg", "path is empty");
methodChannel$Result1.success(hashMap1);
return;
}

if(!new File(path).exists()) {
MediaUploadPlugin.printTLog("uploadImage", "uploadImage error, file is not exists, path=" + path, null);
HashMap hashMap2 = new HashMap();
hashMap2.put("errCode", "-1");
hashMap2.put("errMsg", "file is not exists");
methodChannel$Result1.success(hashMap2);
return;
}

if(mediaUploadPlugin0.mUploadTasks.containsKey(path)) {
MediaUploadPlugin.printTLog("uploadImage", "uploadImage error, image is already uploading", null);
HashMap hashMap3 = new HashMap();
hashMap3.put("errCode", "-1");
hashMap3.put("errMsg", "image is already uploading");
methodChannel$Result1.success(hashMap3);
return;
}

UploadTask mediaUploadPlugin$UploadTask0 = new UploadTask(0);
mediaUploadPlugin$UploadTask0.imageUploaderTask = new MediaUploadPlugin.2(bizeCode, path);
mediaUploadPlugin0.mUploadTasks.put(path, mediaUploadPlugin$UploadTask0);
hashMap4 = new HashMap();
hashMap4.put("imagePath", path);
((PTBS)XModuleCenter.moduleForProtocol(class0)).commitEvent("UploadTracker_commit", hashMap4);
long0 = (long)System.currentTimeMillis();
imageUploadManager0 = ImageUploadManager.getInstance();
iUploaderTask0 = mediaUploadPlugin$UploadTask0.imageUploaderTask;
}
catch(Throwable throwable0) {
goto label_145;
}

MediaUploadPlugin mediaUploadPlugin1 = this;
String s5 = path;
ImageUploadManager imageUploadManager1 = imageUploadManager0;
String s6 = s3;
Long long1 = long0;
Result methodChannel$Result2 = methodChannel$Result0;
boolean z1 = z;
try {
new MediaUploadPlugin.3(mediaUploadPlugin1, s5, hashMap4, s6, s4, long1, methodChannel$Result2, ((boolean)(((int)z1))));
imageUploadManager1.uploadAsync(iUploaderTask0, null, MediaUploadPlugin.mHandler);
}
catch(Throwable throwable0) {
label_145:
String s7 = throwable0.getMessage();
MediaUploadPlugin.printTLog("uploadImage", f..ExternalSyntheticOutline0.m("catch Exception: ", s7), null);
((PTBS)XModuleCenter.moduleForProtocol(class0)).commitEvent("UploadTracker_exception", new MediaUploadPlugin.4(mediaUploadPlugin0, s7));
HashMap hashMap5 = new HashMap();
hashMap5.put("errCode", "-1");
hashMap5.put("errMsg", "异常失败");
methodChannel$Result0.success(hashMap5);
}

return;
}
// ...省略无关代码...
methodChannel$Result0.notImplemented();
}

@Override // com.taobao.idlefish.flutter.pluginbase.BaseFlutterPlugin
protected final String pluginName() {
return "media_upload_plugin";
}

private static void printTLog(String s, String s1, @Nullable HashMap hashMap0) {
StringBuilder stringBuilder0 = f..ExternalSyntheticOutline0.m(s1);
stringBuilder0.append((hashMap0 == null ? "" : ", args: " + hashMap0.toString()));
TLog.loge("mediaupload", s, stringBuilder0.toString());
}
}


onMethodCall是由flutter层调用java层的代码,参数比较简单,可以轻松构造。

最终上传图片、视频文件的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
Java.perform(function () {
console.log("Start hooking...");
var fastJSON = Java.use('com.alibaba.fastjson.JSON')
var Boolean = Java.use('java.lang.Boolean')
var HashMap = Java.use('java.util.HashMap')
var MethodCall = Java.use('io.flutter.plugin.common.MethodCall')
var ResultInterface = Java.use('io.flutter.plugin.common.MethodChannel$Result');


var MyResult = Java.registerClass({
name: 'com.example.MyClass',
implements: [ResultInterface],
methods: {
success: function (value) {
console.log('success...')
var json_str = fastJSON.toJSONString(value)
console.log(json_str)
return;
},
error: function (arg) {
console.log('error...')
},
notImplemented: function () {
console.log('notImplemented...')

}
}
});


/**
* 上传图片
* uploadImage
* {"bizeCode":"xy_chat","delete":false,"path":"/storage/emulated/0/Android/data/com.taobao.idlefish/cache/album_image_compress/-798177070.heic","privacyBusiness":"CLIENT","privacyScene":"用于私聊发图","privacySubBusiness":"私聊"}
*/

var hashMap = HashMap.$new()
hashMap.put('bizeCode', 'xy_chat')
hashMap.put('delete', Boolean.valueOf(false))
hashMap.put('path', '/storage/emulated/0/Download/qr.mp4')
hashMap.put('privacyBusiness', 'CLIENT')
hashMap.put('privacyScene', '用于私聊发图')
hashMap.put('privacySubBusiness', '私聊')

var methodCall = MethodCall.$new('uploadImage', hashMap)
console.log(methodCall)

var callback = MyResult.$new()
console.log(callback)


Java.choose("com.taobao.mediaupload.MediaUploadPlugin", {
onMatch: function (instance) {
console.log("Found MediaUploadPlugin instance: " + instance);
instance.onMethodCall(methodCall, callback)
// 必须返回stop,否则会遍历所有的实例
return "stop";
},
onComplete: function () {
console.log("Done");
},
onMatchOnce: true
});


// var MediaUploadPlugin = Java.use("com.taobao.mediaupload.MediaUploadPlugin");
// MediaUploadPlugin.onMethodCall.overload('io.flutter.plugin.common.MethodCall', 'io.flutter.plugin.common.MethodChannel$Result').implementation = function(methodCall, arg_1) {
// console.log("MediaUploadPlugin->onMethodCall (argType: io.flutter.plugin.common.MethodCall): " + methodCall);
// var method = methodCall.method.value
// var field = MethodCall.class.getDeclaredField('arguments')
// var value = field.get(methodCall);
// console.log(method)
// var json_str = fastJSON.toJSONString(value)
// console.log(json_str)

// console.log("MediaUploadPlugin->onMethodCall (argType: io.flutter.plugin.common.MethodChannel$Result): " + arg_1);
// this.onMethodCall(methodCall, arg_1);

// }





// var IdlefishIMMethodPlugin = Java.use("com.taobao.fleamarket.push.plugin.IdlefishIMMethodPlugin");
// IdlefishIMMethodPlugin.onMethodCall.overload('io.flutter.plugin.common.MethodCall', 'io.flutter.plugin.common.MethodChannel$Result').implementation = function(methodCall, arg_1) {
// console.log("IdlefishIMMethodPlugin->onMethodCall (argType: io.flutter.plugin.common.MethodCall): " + methodCall);
// console.log("IdlefishIMMethodPlugin->onMethodCall (argType: io.flutter.plugin.common.MethodChannel$Result): " + arg_1);

// var method = methodCall.method.value
// var field = MethodCall.class.getDeclaredField('arguments')
// var value = field.get(methodCall);
// console.log(method)
// var json_str = fastJSON.toJSONString(value)
// console.log(json_str)
// this.onMethodCall(methodCall, arg_1);
// }


/**
* 上传视频
* uploadVideo
* {"bizCode":"xianyu_imvod_private","path":"/storage/emulated/0/Android/data/com.taobao.idlefish/cache/media_video/1718082127425.mp4"}
*/

var hashMap = HashMap.$new()
hashMap.put('bizeCode', 'xianyu_imvod_private')
hashMap.put('path', '/storage/emulated/0/Download/qr.mp4')
var methodCall = MethodCall.$new('uploadVideo', hashMap)
var callback = MyResult.$new()

Java.choose("com.taobao.fleamarket.push.plugin.IdlefishIMMethodPlugin", {
onMatch: function (instance) {
console.log("Found IdlefishIMMethodPlugin instance: " + instance);
instance.onMethodCall(methodCall, callback)
// 必须返回stop,否则会遍历所有的实例
return "stop";
},
onComplete: function () {
console.log("Done");
},
onMatchOnce: true
});

});