Skip to content

Instantly share code, notes, and snippets.

@xloger
Created July 27, 2016 06:52
Show Gist options
  • Save xloger/975bfa54bdf5043cb955558b82a3ef49 to your computer and use it in GitHub Desktop.
Save xloger/975bfa54bdf5043cb955558b82a3ef49 to your computer and use it in GitHub Desktop.
package com.xloger.exlink.app;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import com.xloger.exlink.app.entity.App;
import com.xloger.exlink.app.entity.Rule;
import com.xloger.exlink.app.util.AppUtil;
import com.xloger.exlink.app.util.MyLog;
import com.xloger.exlink.app.util.StreamUtil;
import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import static de.robv.android.xposed.XposedHelpers.findAndHookMethod;
/**
* Created by xloger on 1月2日.
* Author:xloger
* Email:[email protected]
* 卧槽这代码复杂度简直了......你们想看的话自求多福吧Orz,当初我写的什么鬼啊......
*/
public class HookMain implements IXposedHookLoadPackage {
private int index;
private static List<App> appList=null;
private final static String EX_DAT ="ExDat";
@Override
public void handleLoadPackage(LoadPackageParam lpparam) throws Throwable {
if (appList == null||appList.size()==0) {
appList= AppUtil.getAppList();
}
if (appList == null) {
return;
}
for (int i = 0; i < appList.size(); i++) {
App app = appList.get(i);
if(lpparam.packageName.equals(app.getPackageName())&& app.isUse()){
index=i;
MyLog.log("进入"+ app.getAppName()+"("+ app.getPackageName()+")");
findAndHookMethod(Activity.class, "startActivity", Intent.class, Bundle.class, xc_methodHook);
findAndHookMethod(Activity.class, "startActivityForResult", Intent.class, int.class, Bundle.class,xc_methodHook);
break;
}
}
}
private XC_MethodHook xc_methodHook=new XC_MethodHook(){
@Override
protected void beforeHookedMethod(XC_MethodHook.MethodHookParam param) throws Throwable {
App app = appList.get(index);
String exUrl =null;
//如果该应用正处于“匹配模式”,则执行sendToExLink方法
if (app.isTest()){
MyLog.log("进入匹配模式!");
sendToExLink(param);
return;
}
//判断该Activity是否已经处于规则之中
String activityName = param.thisObject.getClass().getName();
Set<Rule> ruleSet = app.getRules();
List<Rule> ruleList=new ArrayList<Rule>();
for (Rule tempRule : ruleSet) {
if (activityName.equals(tempRule.getActivityName())){
ruleList.add(tempRule);
}
}
if(ruleList.size()==0) {
return;
}
MyLog.log("Started activity: " + activityName);
//分析获取的Intent
Intent intent = (Intent)param.args[0];
MyLog.log("Intent: " + intent.toString());
if (StreamUtil.isContain(ruleList, EX_DAT)){
MyLog.log("诶?这里应该没错吧?");
exUrl=intent.getData().toString();
}else {
Bundle extras=intent.getExtras();
if (!StreamUtil.isContainUrl(extras.toString())){
MyLog.log("Extras不对,换一个");
if (param.args.length>2){
extras=(Bundle)param.args[2];
if (!StreamUtil.isContainUrl(extras.toString())){
MyLog.log("还是不对,不处理了...");
return;
}
}else {
return;
}
}
MyLog.log(" - With extras: " + extras.toString());
int trueUrl=0;
for (Rule rule : ruleList) {
String tempUrl=extras.getString(rule.getExtrasKey());
if (!"".equals(tempUrl)){
exUrl=tempUrl;
trueUrl++;
}
}
if (trueUrl>1){
MyLog.log("好像遇到多个链接的我无法处理的情况了_(:з)∠)_");
}
}
//intent.toUri(0);这个还没测试有没有效果
MyLog.log("然后就跪了...");
if (exUrl == null||"".equals(exUrl)) {
MyLog.log(new RuntimeException("无法获取url"));
return;
}
//Url规范化
if (!exUrl.startsWith("http")){
MyLog.log("Url不符合规范,正在二次分析");
MyLog.log("当前externalUrl:"+exUrl);
exUrl=StreamUtil.clearUrl(exUrl);
MyLog.log("处理后externalUrl:"+exUrl);
if (exUrl == null) {
MyLog.log(new RuntimeException("无法解析url"));
return;
}
}
Uri uri = Uri.parse(exUrl);
MyLog.log("uri:"+uri);
//检查白名单
Set<String> whiteUrl = app.getWhiteUrl();
if (whiteUrl != null) {
for (String s : whiteUrl) {
if (s.equals(uri.getHost())){
MyLog.log("处于白名单之中,跳过");
return;
}else if (StreamUtil.isSecondLevelDomain(s,uri.getHost())){
MyLog.log("为"+s+"的二级域名,跳过");
return;
}
}
}
if (appList.get(index).getPackageName().equals("com.tencent.mm")){
MyLog.log("进入匹配微信模式");
compatibleWeChat(param,uri);
return;
}
//发送干净的Intent
Intent exIntent = new Intent();
exIntent.setAction(Intent.ACTION_VIEW);
exIntent.setData(uri);
((Activity)param.thisObject).startActivity(exIntent);
param.setResult(null);
}
/**
* 匹配模式 <br/>
* 判断哪个值包含了Url,并发送到Exlink
* @param param 传入的参数
*/
private void sendToExLink(XC_MethodHook.MethodHookParam param) {
Intent intent = (Intent)param.args[0];
MyLog.log("Intent: " + intent.toString());
Uri data = intent.getData();
if (data!=null){
if (StreamUtil.isContain(data.toString())){
openExlink(param, EX_DAT);
return;
}
}
Bundle extras = intent.getExtras();
if (extras==null){
MyLog.log("没有Extras,采用第二套方案");
if (param.args.length>2){
extras= (Bundle) param.args[2];
if (extras != null) {
MyLog.log("第二套:"+extras.toString());
}else {
MyLog.log("第三套方案失败,跳过");
return;
}
}else {
MyLog.log("第三套方案失败,跳过");
return;
}
}else {
MyLog.log(" - With extras: " + extras.toString());
}
Set<String> keySet = extras.keySet();
for (String key : keySet) {
Object o = extras.get(key);
if (o == null) {
continue;
}
String value=o.toString();
if (StreamUtil.isContain(value)){
openExlink(param,key);
}
}
}
private void openExlink(XC_MethodHook.MethodHookParam param,String key){
MyLog.log("成功匹配!");
Uri uri = Uri.parse("exlink://test");
String activityName = param.thisObject.getClass().getName();
Intent sendToExLinkIntent=new Intent();
sendToExLinkIntent.setAction(Intent.ACTION_VIEW);
sendToExLinkIntent.setData(uri);
sendToExLinkIntent.putExtra("activityName",activityName);
sendToExLinkIntent.putExtra("extrasKey",key);
sendToExLinkIntent.putExtra("position",index);
((Activity)param.thisObject).startActivity(sendToExLinkIntent);
param.setResult(null);
}
/**
* 兼容微信 <br/>
* 对微信进行特殊处理
* @param param 传入的参数
* @param uri 需要被打开的链接
*/
private void compatibleWeChat(XC_MethodHook.MethodHookParam param,Uri uri){
boolean isOpenWithOut1=false;
boolean isOpenWithOut2=false;
boolean isOpenWithOut3=false;
Intent intent = (Intent)param.args[0];
String judge1 = intent.getStringExtra("preChatName");
String judge2 = intent.getStringExtra("prePublishId");
String judge3 = intent.getStringExtra("preUsername");
MyLog.log("judge1:"+judge1+"judge2:"+judge2+"judge3:"+judge3);
if (judge1==null&&judge2==null&&judge3==null){
isOpenWithOut1=true;
}
String judge4 = intent.getStringExtra("version_name");
String judge5 = intent.getStringExtra("KAppId");
String judge6 = intent.getStringExtra("srcDisplayname");
MyLog.log("judge4:"+judge4+"judge5:"+judge5+"judge6:"+judge6);
if (judge4!=null&&judge5!=null&&judge6==null){
isOpenWithOut2=true;
}
String judge7 = intent.getStringExtra("srcUsername");
String judge8 = intent.getStringExtra("message_index");
String judge9 = intent.getStringExtra("message_id");
MyLog.log("judge7:"+judge7+"judge8:"+judge8+"judge9:"+judge9);
if (judge7==null&&judge8==null&&judge9==null){
isOpenWithOut3=true;
}
if (isOpenWithOut1||isOpenWithOut2||isOpenWithOut3){
MyLog.log("判断可以用外置浏览器打开");
Intent exIntent = new Intent();
exIntent.setAction(Intent.ACTION_VIEW);
exIntent.setData(uri);
((Activity)param.thisObject).startActivity(exIntent);
param.setResult(null);
}else {
MyLog.log("判断需要用内置浏览器打开");
}
}
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment