提交 ae77cb97 编写于 作者: J jackjintai

modify:

1、新增日志导出功能
上级 91589446
......@@ -38,7 +38,6 @@ import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.didichuxing.doraemondemo.util.FrescoUtil;
import com.didichuxing.doraemonkit.DoraemonKit;
import com.didichuxing.doraemonkit.aop.MethodCostUtil;
import com.didichuxing.doraemonkit.kit.largepicture.glide.LargeBitmapGlideTransformation;
import com.didichuxing.doraemonkit.kit.largepicture.picasso.LargeBitmapPicassoTransformation;
import com.didichuxing.doraemonkit.kit.methodtrace.MethodCost;
......@@ -311,9 +310,7 @@ public class MainDebugActivity extends AppCompatActivity implements View.OnClick
break;
case R.id.btn_jump:
startActivity(new Intent(this, SecondActivity.class));
break;
case R.id.btn_jump_leak:
......
......@@ -33,7 +33,10 @@ public final class DokitCommClassAdapter extends ClassVisitor {
private DokitExtension dokitExtension;
/**
* @param cv 传进来的是 ClassWriter
*
* @param cv cv
* @param appExtension appExtension
* @param dokitExtension dokitExtension
*/
public DokitCommClassAdapter(final ClassVisitor cv, AppExtension appExtension, DokitExtension dokitExtension) {
super(Opcodes.ASM7, cv);
......
......@@ -38,8 +38,12 @@ public final class DokitSlowMethodClassAdapter extends ClassVisitor {
*/
private int thresholdTime = 500;
/**
* @param cv 传进来的是 ClassWriter
*
* @param cv cv 传进来的是 ClassWriter
* @param appExtension appExtension
* @param dokitExtension dokitExtension
*/
public DokitSlowMethodClassAdapter(final ClassVisitor cv, AppExtension appExtension, DokitExtension dokitExtension) {
super(Opcodes.ASM7, cv);
......@@ -108,7 +112,6 @@ public final class DokitSlowMethodClassAdapter extends ClassVisitor {
/**
* access值得计算方式为Opcodes.ACC_PUBLIC & Opcodes.ACC_STATIC
* <p>
* Visits a method of the class. This method <i>must</i> return a new {@link MethodVisitor}
* instance (or {@literal null}) each time it is called, i.e., it should not return a previously
......
......@@ -26,8 +26,12 @@ public final class DokitUrlConnectionClassAdapter extends ClassVisitor {
private DokitExtension dokitExtension;
/**
* @param cv 传进来的是 ClassWriter
*
* @param cv cv 传进来的是 ClassWriter
* @param appExtension appExtension
* @param dokitExtension dokitExtension
*/
public DokitUrlConnectionClassAdapter(final ClassVisitor cv, AppExtension appExtension, DokitExtension dokitExtension) {
super(Opcodes.ASM7, cv);
......
......@@ -41,6 +41,7 @@ public final class SlowMethodAdapter extends AdviceAdapter {
super(Opcodes.ASM7, methodVisitor, access, methodName, descriptor);
this.className = className;
this.thresholdTime = thresholdTime;
//access值得计算方式为 Opcodes.ACC_PUBLIC & Opcodes.ACC_STATIC
this.isStaticMethod = (access & Opcodes.ACC_STATIC) != 0;
}
......
......@@ -21,7 +21,7 @@ public final class UrlConnectionMethodAdapter extends LocalVariablesSorter imple
* @param owner 调用对象
* @param name 函数名
* @param desc 函数签名
* @param isInterface
* @param isInterface 是否是接口
*/
@Override
public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean isInterface) {
......
......@@ -27,10 +27,15 @@ public class PlatformHttpHook {
if (IS_INSTALL) {
return;
}
OkHttpRpc.OkHttpRpcInterceptor rpcMockInterceptor = new OkHttpRpc.OkHttpRpcInterceptor((new RpcMockInterceptor()));
OkHttpRpc.OkHttpRpcInterceptor rpcMonitorInterceptor = new OkHttpRpc.OkHttpRpcInterceptor((new RpcMonitorInterceptor()));
globalInterceptors.add(rpcMockInterceptor);
globalInterceptors.add(rpcMonitorInterceptor);
IS_INSTALL = true;
try {
//可能存在用户没有引入滴滴内部网络库的情况
OkHttpRpc.OkHttpRpcInterceptor rpcMockInterceptor = new OkHttpRpc.OkHttpRpcInterceptor((new RpcMockInterceptor()));
OkHttpRpc.OkHttpRpcInterceptor rpcMonitorInterceptor = new OkHttpRpc.OkHttpRpcInterceptor((new RpcMonitorInterceptor()));
globalInterceptors.add(rpcMockInterceptor);
globalInterceptors.add(rpcMonitorInterceptor);
IS_INSTALL = true;
} catch (Exception e) {
e.printStackTrace();
}
}
}
......@@ -16,10 +16,9 @@
android:layout_width="match_parent"
android:layout_height="89dp"
android:layout_alignParentTop="true"
app:dkIcon="@drawable/dk_close_icon"
app:dkTitle="@string/dk_console_log_title"
android:background="@color/foreground_wtf"
/>
app:dkIcon="@drawable/dk_close_icon"
app:dkTitle="@string/dk_console_log_title" />
<View
android:id="@+id/view_divider"
......@@ -98,6 +97,11 @@
style="@style/DK.RadioButton.Left"
android:text="清空日志" />
<Button
android:id="@+id/btn_export"
style="@style/DK.RadioButton.middle"
android:text="导出" />
<Button
android:id="@+id/btn_top"
style="@style/DK.RadioButton.middle"
......
......@@ -45,10 +45,16 @@ public class OkHttpHook {
if (IS_INSTALL) {
return;
}
globalInterceptors.add(new MockInterceptor());
globalInterceptors.add(new LargePictureInterceptor());
globalInterceptors.add(new DoraemonInterceptor());
globalNetworkInterceptors.add(new DoraemonWeakNetworkInterceptor());
IS_INSTALL = true;
try {
//可能存在用户没有引入okhttp的情况
globalInterceptors.add(new MockInterceptor());
globalInterceptors.add(new LargePictureInterceptor());
globalInterceptors.add(new DoraemonInterceptor());
globalNetworkInterceptors.add(new DoraemonWeakNetworkInterceptor());
IS_INSTALL = true;
} catch (Exception e) {
e.printStackTrace();
}
}
}
......@@ -2,9 +2,12 @@ package com.didichuxing.doraemonkit.kit.gpsmock;
import android.content.Context;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.IBinder;
import com.blankj.utilcode.util.ReflectUtils;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
......@@ -67,7 +70,14 @@ public class WifiHooker extends BaseServiceHooker {
if (!GpsMockManager.getInstance().isMocking()) {
return method.invoke(originService, args);
}
return null;
try {
return Class.forName("android.net.wifi.WifiInfo").newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return new Object();
}
}
}
\ No newline at end of file
package com.didichuxing.doraemonkit.kit.loginfo;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import com.didichuxing.doraemonkit.R;
import com.didichuxing.doraemonkit.ui.dialog.DialogListener;
import com.didichuxing.doraemonkit.ui.dialog.DialogProvider;
import com.didichuxing.doraemonkit.ui.setting.SettingItem;
import com.didichuxing.doraemonkit.ui.setting.SettingItemAdapter;
import java.io.File;
/**
* Created by wanglikun on 2019/4/16
*/
public class LogExportDialog extends DialogProvider<Object> {
private RecyclerView mChooseList;
private SettingItemAdapter mAdapter;
public LogExportDialog(Object data, DialogListener listener) {
super(data, listener);
}
@Override
public int getLayoutId() {
return R.layout.dk_dialog_file_explorer_choose;
}
@Override
protected void findViews(View view) {
mChooseList = view.findViewById(R.id.choose_list);
mAdapter = new SettingItemAdapter(getContext());
mChooseList.setAdapter(mAdapter);
mChooseList.setLayoutManager(new LinearLayoutManager(getContext()));
}
@Override
protected void bindData(final Object file) {
mAdapter.append(new SettingItem(R.string.dk_save));
mAdapter.append(new SettingItem(R.string.dk_share));
mAdapter.setOnSettingItemClickListener(new SettingItemAdapter.OnSettingItemClickListener() {
@Override
public void onSettingItemClick(View view, SettingItem data) {
if (data.desc == R.string.dk_save) {
if (onButtonClickListener != null) {
onButtonClickListener.onSaveClick(LogExportDialog.this);
}
} else if (data.desc == R.string.dk_share) {
if (onButtonClickListener != null) {
onButtonClickListener.onShareClick(LogExportDialog.this);
}
}
}
});
}
private OnButtonClickListener onButtonClickListener;
public void setOnButtonClickListener(OnButtonClickListener onButtonClickListener) {
this.onButtonClickListener = onButtonClickListener;
}
public interface OnButtonClickListener {
/**
* @param dialog dialog
*/
void onSaveClick(LogExportDialog dialog);
/**
* @param dialog dialog
*/
void onShareClick(LogExportDialog dialog);
}
}
\ No newline at end of file
package com.didichuxing.doraemonkit.kit.loginfo;
import android.app.ProgressDialog;
import android.content.Context;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.text.Editable;
......@@ -13,17 +17,34 @@ import android.view.WindowManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.ProgressBar;
import android.widget.RadioGroup;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.blankj.utilcode.util.AppUtils;
import com.blankj.utilcode.util.CollectionUtils;
import com.blankj.utilcode.util.FileIOUtils;
import com.blankj.utilcode.util.FileUtils;
import com.blankj.utilcode.util.PathUtils;
import com.blankj.utilcode.util.ThreadUtils;
import com.blankj.utilcode.util.TimeUtils;
import com.blankj.utilcode.util.ToastUtils;
import com.didichuxing.doraemonkit.DoraemonKit;
import com.didichuxing.doraemonkit.R;
import com.didichuxing.doraemonkit.ui.UniversalActivity;
import com.didichuxing.doraemonkit.ui.base.AbsDokitView;
import com.didichuxing.doraemonkit.ui.base.DokitViewLayoutParams;
import com.didichuxing.doraemonkit.ui.dialog.DialogProvider;
import com.didichuxing.doraemonkit.ui.dialog.UniversalDialogFragment;
import com.didichuxing.doraemonkit.ui.fileexplorer.FileExplorerChooseDialog;
import com.didichuxing.doraemonkit.ui.loginfo.LogItemAdapter;
import com.didichuxing.doraemonkit.ui.widget.titlebar.TitleBar;
import com.didichuxing.doraemonkit.util.FileUtil;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
/**
......@@ -147,13 +168,14 @@ public class LogInfoDokitView extends AbsDokitView implements LogInfoManager.OnL
Button mBtnTop = findViewById(R.id.btn_top);
Button mBtnBottom = findViewById(R.id.btn_bottom);
Button mBtnClean = findViewById(R.id.btn_clean);
Button mBtnExport = findViewById(R.id.btn_export);
mBtnTop.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mLogItemAdapter == null || mLogItemAdapter.getItemCount() == 0) {
return;
}
mLogRv.smoothScrollToPosition(0);
mLogRv.scrollToPosition(0);
}
});
mBtnBottom.setOnClickListener(new View.OnClickListener() {
......@@ -162,7 +184,36 @@ public class LogInfoDokitView extends AbsDokitView implements LogInfoManager.OnL
if (mLogItemAdapter == null || mLogItemAdapter.getItemCount() == 0) {
return;
}
mLogRv.smoothScrollToPosition(mLogItemAdapter.getItemCount() - 1);
mLogRv.scrollToPosition(mLogItemAdapter.getItemCount() - 1);
}
});
mBtnExport.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mLogItemAdapter == null || mLogItemAdapter.getItemCount() == 0) {
ToastUtils.showShort("暂无日志信息可以导出");
return;
}
LogExportDialog logExportDialog = new LogExportDialog(new Object(), null);
logExportDialog.setOnButtonClickListener(new LogExportDialog.OnButtonClickListener() {
@Override
public void onSaveClick(LogExportDialog dialog) {
export2File(100);
dialog.dismiss();
}
@Override
public void onShareClick(LogExportDialog dialog) {
export2File(101);
dialog.dismiss();
}
});
showDialog(logExportDialog);
}
});
......@@ -179,6 +230,73 @@ public class LogInfoDokitView extends AbsDokitView implements LogInfoManager.OnL
}
private void showDialog(DialogProvider provider) {
if (getActivity() == null || !(getActivity() instanceof FragmentActivity)) {
return;
}
UniversalDialogFragment dialog = new UniversalDialogFragment();
provider.setHost(dialog);
dialog.setProvider(provider);
provider.show(((FragmentActivity) getActivity()).getSupportFragmentManager());
}
/**
* 将日志信息保存到文件
*
* @param operateType 100 保存到本地 101 保存到本地并分享
*/
private void export2File(final int operateType) {
ToastUtils.showShort("日志保存中,请稍后...");
final String logPath = PathUtils.getInternalAppFilesPath() + File.separator + AppUtils.getAppName() + "_" + TimeUtils.getNowString(new SimpleDateFormat("yyyy-MM-dd-HH:mm:ss")) + ".log";
final File logFile = new File(logPath);
ThreadUtils.executeByCpu(new ThreadUtils.Task<Boolean>() {
@Override
public Boolean doInBackground() throws Throwable {
try {
List<LogLine> logLines = new ArrayList<>(mLogItemAdapter.getTrueValues());
for (LogLine logLine : logLines) {
String strLog = logLine.getProcessId() + " " + " " + logLine.getTimestamp() + " " + logLine.getTag() + " " + logLine.getLogLevelText() + " " + logLine.getLogOutput() + "\n";
FileIOUtils.writeFileFromString(logFile, strLog, true);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
@Override
public void onSuccess(Boolean result) {
if (result) {
ToastUtils.showShort("文件保存在:" + logPath);
//分享
if (operateType == 101) {
FileUtil.systemShare(DoraemonKit.APPLICATION, logFile);
}
}
}
@Override
public void onCancel() {
if (logFile.exists()) {
FileUtils.delete(logFile);
}
ToastUtils.showShort("日志保存失败");
}
@Override
public void onFail(Throwable t) {
if (logFile.exists()) {
FileUtils.delete(logFile);
}
ToastUtils.showShort("日志保存失败");
}
});
}
@Override
public void initDokitViewLayoutParams(DokitViewLayoutParams params) {
params.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
......
......@@ -51,7 +51,8 @@ public class LogLine {
&& originalLine.length() >= TIMESTAMP_LENGTH) {
String timestamp = originalLine.substring(0, TIMESTAMP_LENGTH - 1);
logLine.setTimestamp(timestamp);
startIdx = TIMESTAMP_LENGTH; // cut off timestamp
// cut off timestamp
startIdx = TIMESTAMP_LENGTH;
}
Matcher matcher = logPattern.matcher(originalLine);
......
......@@ -183,6 +183,9 @@ class NormalDokitViewManager implements DokitViewManagerInterface {
*/
@Override
public void onActivityResume(Activity activity) {
if (mActivityDokitViews == null) {
return;
}
Map<String, AbsDokitView> existDokitViews = mActivityDokitViews.get(activity);
//先清除页面上启动模式为DokitIntent.MODE_ONCE 的dokitView
if (existDokitViews != null) {
......@@ -312,7 +315,9 @@ class NormalDokitViewManager implements DokitViewManagerInterface {
dokitView.performCreate(mContext);
//在全局dokitviews中保存该类型的
if (dokitIntent.mode == DokitIntent.MODE_SINGLE_INSTANCE) {
mGlobalSingleDokitViews.put(dokitView.getTag(), createGlobalSingleDokitViewInfo(dokitView));
if (mGlobalSingleDokitViews != null) {
mGlobalSingleDokitViews.put(dokitView.getTag(), createGlobalSingleDokitViewInfo(dokitView));
}
}
//得到activity window中的根布局
final FrameLayout mDecorView = (FrameLayout) dokitIntent.activity.getWindow().getDecorView();
......@@ -458,7 +463,7 @@ class NormalDokitViewManager implements DokitViewManagerInterface {
}
//同步移除全局指定类型的dokitView
if (mGlobalSingleDokitViews.containsKey(tag)) {
if (mGlobalSingleDokitViews != null && mGlobalSingleDokitViews.containsKey(tag)) {
mGlobalSingleDokitViews.remove(tag);
}
......@@ -491,7 +496,7 @@ class NormalDokitViewManager implements DokitViewManagerInterface {
//移除map中的数据
dokitViews.remove(tag);
if (mGlobalSingleDokitViews.containsKey(tag)) {
if (mGlobalSingleDokitViews != null && mGlobalSingleDokitViews.containsKey(tag)) {
mGlobalSingleDokitViews.remove(tag);
}
}
......@@ -524,7 +529,10 @@ class NormalDokitViewManager implements DokitViewManagerInterface {
//移除map中的数据
dokitViews.clear();
}
mGlobalSingleDokitViews.clear();
if (mGlobalSingleDokitViews != null) {
mGlobalSingleDokitViews.clear();
}
}
/**
......
......@@ -12,11 +12,11 @@ import android.widget.Filter;
import android.widget.Filterable;
import android.widget.TextView;
import com.blankj.utilcode.util.ToastUtils;
import com.didichuxing.doraemonkit.R;
import com.didichuxing.doraemonkit.kit.loginfo.LogLine;
import com.didichuxing.doraemonkit.kit.loginfo.util.SearchCriteria;
import com.didichuxing.doraemonkit.kit.loginfo.util.TagColorUtil;
import com.didichuxing.doraemonkit.ui.toast.AppToast;
import com.didichuxing.doraemonkit.ui.widget.recyclerview.AbsRecyclerAdapter;
import com.didichuxing.doraemonkit.ui.widget.recyclerview.AbsViewBinder;
......@@ -140,7 +140,7 @@ public class LogItemAdapter extends AbsRecyclerAdapter<AbsViewBinder<LogLine>, L
public boolean onLongClick(View v) {
ClipData clipData = ClipData.newPlainText("Label", data.getOriginalLine());
mClipboard.setPrimaryClip(clipData);
new AppToast(getContext()).show("copy success");
ToastUtils.showShort("copy success");
return true;
}
});
......@@ -160,8 +160,6 @@ public class LogItemAdapter extends AbsRecyclerAdapter<AbsViewBinder<LogLine>, L
mTag.setText(item.getTag());
String text = item.getLogOutput();
mLogText.setText(text);
if (item.isExpanded() && item.getProcessId() != -1) {
mLogText.setSingleLine(false);
mTime.setVisibility(View.VISIBLE);
......
......@@ -41,7 +41,7 @@ public class DoraemonStatisticsUtil {
try {
jsonObject.put("appId", appId);
jsonObject.put("appName", appName);
jsonObject.put("version", "" + BuildConfig.VERSION_NAME);
jsonObject.put("version", "" + BuildConfig.DOKIT_VERSION);
jsonObject.put("type", type);
jsonObject.put("from", from);
} catch (JSONException e) {
......
......@@ -47,6 +47,7 @@ public class FileUtil {
}
Intent intent = new Intent(Intent.ACTION_SEND);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Uri uri;
try {
uri = FileProvider.getUriForFile(context, context.getPackageName() + ".debugfileprovider", file);
......@@ -57,7 +58,7 @@ public class FileUtil {
intent.setDataAndType(uri, "*/*");
}
context.startActivity(intent);
} catch (IllegalArgumentException e) {
} catch (Exception e) {
LogHelper.e(TAG,
"The selected file can't be shared: " + file.toString());
}
......
......@@ -97,6 +97,11 @@
style="@style/DK.RadioButton.Left"
android:text="清空日志" />
<Button
android:id="@+id/btn_export"
style="@style/DK.RadioButton.middle"
android:text="导出" />
<Button
android:id="@+id/btn_top"
style="@style/DK.RadioButton.middle"
......
......@@ -69,6 +69,6 @@
android:paddingLeft="2dp"
android:paddingRight="2dp"
android:textSize="12sp"/>
/>
</RelativeLayout>
\ No newline at end of file
......@@ -240,6 +240,7 @@
<string name="dk_app_data_clean">Confirm that you want to delete local data</string>
<string name="dk_hint">Hint</string>
<string name="dk_share">share</string>
<string name="dk_save">save</string>
<string name="dk_platform_monitor_data_button">start test</string>
<string name="dk_platform_monitor_data_button_stop">stop test</string>
......
......@@ -239,6 +239,7 @@
<string name="dk_app_data_clean">确认要删除本地数据</string>
<string name="dk_hint">提示</string>
<string name="dk_share">分享</string>
<string name="dk_save">保存</string>
<string name="dk_platform_monitor_data_button">开始测试</string>
<string name="dk_platform_monitor_data_button_stop">结束测试</string>
......
......@@ -238,6 +238,7 @@
<string name="dk_hint">提示</string>
<string name="dk_share">分享</string>
<string name="dk_save">保存</string>
<string name="dk_platform_monitor_data_button">開始測試</string>
<string name="dk_platform_monitor_data_button_stop">結束測試</string>
<string name="dk_success">成功</string>
......
......@@ -250,6 +250,7 @@
<string name="dk_app_data_clean">确认要删除本地数据</string>
<string name="dk_hint">提示</string>
<string name="dk_share">分享</string>
<string name="dk_save">保存</string>
<string name="dk_platform_monitor_data_button">开始测试</string>
<string name="dk_platform_monitor_data_button_stop">结束测试</string>
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册