├── app
├── .gitignore
├── src
│ ├── main
│ │ ├── assets
│ │ │ └── xposed_init
│ │ ├── res
│ │ │ ├── values
│ │ │ │ ├── dimens.xml
│ │ │ │ ├── colors.xml
│ │ │ │ ├── strings.xml
│ │ │ │ └── styles.xml
│ │ │ ├── mipmap-hdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-mdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-anydpi-v26
│ │ │ │ ├── ic_launcher.xml
│ │ │ │ └── ic_launcher_round.xml
│ │ │ ├── xml
│ │ │ │ └── c.xml
│ │ │ ├── layout
│ │ │ │ ├── activity_main.xml
│ │ │ │ ├── activity_start.xml
│ │ │ │ └── activity_add.xml
│ │ │ ├── drawable-v24
│ │ │ │ └── ic_launcher_foreground.xml
│ │ │ └── drawable
│ │ │ │ └── ic_launcher_background.xml
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── example
│ │ │ │ └── admin
│ │ │ │ └── wxaddfrienddemo
│ │ │ │ ├── MyBroadcastReceiver.java
│ │ │ │ ├── StartActivity.java
│ │ │ │ ├── SpiltTest.java
│ │ │ │ ├── MyService.java
│ │ │ │ ├── Module.java
│ │ │ │ ├── AddUtils.java
│ │ │ │ ├── MainActivity.java
│ │ │ │ └── AddActivity.java
│ │ └── AndroidManifest.xml
│ ├── test
│ │ └── java
│ │ │ └── com
│ │ │ └── example
│ │ │ └── admin
│ │ │ └── wxaddfrienddemo
│ │ │ └── ExampleUnitTest.java
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── example
│ │ └── admin
│ │ └── wxaddfrienddemo
│ │ └── ExampleInstrumentedTest.java
├── release
│ ├── app-release.apk
│ ├── wxaddfriend.apk
│ └── output.json
├── jar
│ └── XposedBridgeApi-54.jar
├── proguard-rules.pro
└── build.gradle
├── settings.gradle
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── .gitignore
├── .idea
├── modules.xml
├── runConfigurations.xml
├── gradle.xml
└── misc.xml
├── gradle.properties
├── gradlew.bat
├── README.md
└── gradlew
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------
/app/src/main/assets/xposed_init:
--------------------------------------------------------------------------------
1 | com.example.admin.wxaddfrienddemo.Module
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 | 16dp
3 |
4 |
--------------------------------------------------------------------------------
/app/release/app-release.apk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/carrys17/WxAddFriendDemo/HEAD/app/release/app-release.apk
--------------------------------------------------------------------------------
/app/release/wxaddfriend.apk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/carrys17/WxAddFriendDemo/HEAD/app/release/wxaddfriend.apk
--------------------------------------------------------------------------------
/app/jar/XposedBridgeApi-54.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/carrys17/WxAddFriendDemo/HEAD/app/jar/XposedBridgeApi-54.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/carrys17/WxAddFriendDemo/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/carrys17/WxAddFriendDemo/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/carrys17/WxAddFriendDemo/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/carrys17/WxAddFriendDemo/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/carrys17/WxAddFriendDemo/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/carrys17/WxAddFriendDemo/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/carrys17/WxAddFriendDemo/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/carrys17/WxAddFriendDemo/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/carrys17/WxAddFriendDemo/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/carrys17/WxAddFriendDemo/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/carrys17/WxAddFriendDemo/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/workspace.xml
5 | /.idea/libraries
6 | .DS_Store
7 | /build
8 | /captures
9 | .externalNativeBuild
10 |
--------------------------------------------------------------------------------
/app/release/output.json:
--------------------------------------------------------------------------------
1 | [{"outputType":{"type":"APK"},"apkInfo":{"type":"MAIN","splits":[],"versionCode":1},"path":"app-release.apk","properties":{"packageId":"com.example.admin.wxaddfrienddemo","split":"","minSdkVersion":"15"}}]
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Tue Nov 07 09:33:50 CST 2017
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | WxAddFriendDemo
3 | 添加好友助手
4 | 自动加人,需要对方的v1或者wxid
5 | StartActivity
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/c.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/test/java/com/example/admin/wxaddfrienddemo/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.example.admin.wxaddfrienddemo;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | org.gradle.jvmargs=-Xmx1536m
13 |
14 | # When configured, Gradle will run in incubating parallel mode.
15 | # This option should only be used with decoupled projects. More details, visit
16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
17 | # org.gradle.parallel=true
18 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/example/admin/wxaddfrienddemo/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.example.admin.wxaddfrienddemo;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumented test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.example.admin.wxaddfrienddemo", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/admin/wxaddfrienddemo/MyBroadcastReceiver.java:
--------------------------------------------------------------------------------
1 | package com.example.admin.wxaddfrienddemo;
2 |
3 | import android.content.BroadcastReceiver;
4 | import android.content.Context;
5 | import android.content.Intent;
6 | import android.os.Bundle;
7 | import android.util.Log;
8 |
9 | /**
10 | * Created by admin on 2017/12/5.
11 | */
12 |
13 | public class MyBroadcastReceiver extends BroadcastReceiver {
14 |
15 | Context mContext;
16 |
17 | public MyBroadcastReceiver(Context context){
18 | mContext = context;
19 | }
20 |
21 | @Override
22 | public void onReceive(Context context, Intent intent) {
23 | Log.i("xyz","进入onReceive");
24 | Bundle bundle = intent.getExtras();
25 | String wxid = bundle.getString("wxid");
26 | int scene = bundle.getInt("scene");
27 | String tuiWxid = bundle.getString("tuiWxid");
28 | String tuiNickName = bundle.getString("tuiNickName");
29 | AddUtils.addFriendByWxid(mContext,wxid,scene,tuiWxid,tuiNickName);
30 |
31 | }
32 |
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 26
5 | defaultConfig {
6 | applicationId "com.example.admin.wxaddfrienddemo"
7 | minSdkVersion 15
8 | targetSdkVersion 26
9 | versionCode 1
10 | versionName "1.0"
11 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
12 | }
13 | buildTypes {
14 | release {
15 | minifyEnabled false
16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
17 | }
18 | }
19 | }
20 |
21 | dependencies {
22 | implementation fileTree(include: ['*.jar'], dir: 'libs')
23 | implementation 'com.android.support:appcompat-v7:26.1.0'
24 | implementation 'com.android.support.constraint:constraint-layout:1.0.2'
25 | implementation 'com.android.support:design:26.1.0'
26 | testImplementation 'junit:junit:4.12'
27 | androidTestImplementation 'com.android.support.test:runner:1.0.1'
28 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
29 | provided files('jar/XposedBridgeApi-54.jar')
30 | }
31 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/admin/wxaddfrienddemo/StartActivity.java:
--------------------------------------------------------------------------------
1 | package com.example.admin.wxaddfrienddemo;
2 |
3 | import android.content.Intent;
4 | import android.os.Bundle;
5 | import android.support.design.widget.FloatingActionButton;
6 | import android.support.design.widget.Snackbar;
7 | import android.support.v7.app.AppCompatActivity;
8 | import android.support.v7.widget.Toolbar;
9 | import android.view.View;
10 | import android.widget.Button;
11 |
12 | public class StartActivity extends AppCompatActivity {
13 |
14 | @Override
15 | protected void onCreate(Bundle savedInstanceState) {
16 | super.onCreate(savedInstanceState);
17 | setContentView(R.layout.activity_start);
18 |
19 | // 间接
20 | findViewById(R.id.slow).setOnClickListener(new View.OnClickListener() {
21 | @Override
22 | public void onClick(View v) {
23 | Intent intent = new Intent(StartActivity.this,AddActivity.class);
24 | intent.putExtra("mode",1);
25 | startActivity(intent);
26 | }
27 | });
28 |
29 | // 直接
30 | findViewById(R.id.quick).setOnClickListener(new View.OnClickListener() {
31 | @Override
32 | public void onClick(View v) {
33 | Intent intent = new Intent(StartActivity.this,AddActivity.class);
34 | intent.putExtra("mode",2);
35 | startActivity(intent);
36 | }
37 | });
38 |
39 |
40 | }
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/admin/wxaddfrienddemo/SpiltTest.java:
--------------------------------------------------------------------------------
1 | package com.example.admin.wxaddfrienddemo;
2 |
3 | import android.os.SystemClock;
4 |
5 | import java.util.Random;
6 |
7 | import javax.net.ssl.SSLContext;
8 |
9 | /**
10 | * Created by admin on 2017/11/16.
11 | */
12 |
13 | // 可忽略
14 | public class SpiltTest {
15 |
16 | public static void main(String []args){
17 | String s = "wxid_lnt4ahvg2esr22";
18 | System.out.println("初始值:"+s);
19 | String [] ss = s.split("_");
20 | String res = "";
21 | for (String s1:ss){
22 | res +=s1;
23 | }
24 | System.out.println("结果为:"+res);
25 |
26 |
27 | String s1 = "qsss2312";
28 | System.out.println("初始值:"+s1);
29 | String s2 = s1.substring(0,4);
30 | if (s2.equals("wxid")){
31 | String s3 = s1.substring(4);
32 | s1 = s2 + "_"+s3;
33 | System.out.println("结果为: "+s);
34 | }
35 |
36 | Double random = Math.random();
37 | System.out.println("random = "+random.toString());
38 | String str = random.toString().substring(2,11);
39 | System.out.println("生成的数字为: "+str);
40 |
41 |
42 | String s11 = "wxidlnt4ahvg2esr22";
43 | System.out.println("初始值:"+s11);
44 | String s22 = s1.toUpperCase();
45 | System.out.println("转为大写:"+s22);
46 |
47 | double ran = Math.random();
48 | long lon = (long) (1500 + ran *1000);
49 | System.out.println("RANDOM :"+lon);
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/admin/wxaddfrienddemo/MyService.java:
--------------------------------------------------------------------------------
1 | package com.example.admin.wxaddfrienddemo;
2 |
3 | import android.accessibilityservice.AccessibilityService;
4 | import android.content.Context;
5 | import android.os.Build;
6 | import android.support.annotation.RequiresApi;
7 | import android.util.Log;
8 | import android.view.accessibility.AccessibilityEvent;
9 |
10 | /**
11 | * Created by admin on 2017/11/8.
12 | */
13 |
14 | public class MyService extends AccessibilityService {
15 |
16 | private static Context sInstance = null;
17 |
18 | public static Context getContext(){
19 | return sInstance;
20 | }
21 |
22 |
23 | public static int cnt = 0;
24 | public static Object gs_lockObj=new Object();
25 |
26 | @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
27 | @Override
28 | public void onAccessibilityEvent(AccessibilityEvent event) {
29 | int type = event.getEventType();
30 | // 界面是否跳转,利用全局变量
31 | if (type == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED){
32 |
33 | synchronized (gs_lockObj){
34 | cnt ++;
35 | }
36 | }
37 |
38 | }
39 |
40 | @Override
41 | protected void onServiceConnected() {
42 | super.onServiceConnected();
43 | // 获取到this必须在这个方法里面
44 | if (sInstance == null){
45 | sInstance = this;
46 | }
47 | Log.i("xyz","服务开启");
48 |
49 | }
50 |
51 | @Override
52 | public void onInterrupt() {
53 | Log.i("xyz","服务中断");
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_start.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
20 |
21 |
32 |
33 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
12 |
13 |
19 |
22 |
25 |
26 |
27 |
28 |
34 |
35 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
39 |
40 |
41 |
42 |
43 |
46 |
47 |
48 |
49 |
52 |
55 |
58 |
59 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/admin/wxaddfrienddemo/Module.java:
--------------------------------------------------------------------------------
1 | package com.example.admin.wxaddfrienddemo;
2 |
3 | import android.app.AndroidAppHelper;
4 | import android.content.BroadcastReceiver;
5 | import android.content.ContentResolver;
6 | import android.content.Context;
7 | import android.content.IntentFilter;
8 | import android.database.Cursor;
9 | import android.net.Uri;
10 | import android.os.Bundle;
11 | import android.os.SystemClock;
12 | import android.util.Log;
13 |
14 | import de.robv.android.xposed.IXposedHookLoadPackage;
15 | import de.robv.android.xposed.XC_MethodHook;
16 | import de.robv.android.xposed.XposedBridge;
17 | import de.robv.android.xposed.XposedHelpers;
18 | import de.robv.android.xposed.callbacks.XC_LoadPackage;
19 |
20 | import static de.robv.android.xposed.XposedHelpers.findAndHookMethod;
21 | import static de.robv.android.xposed.XposedHelpers.findClass;
22 |
23 |
24 | /**
25 | * Created by admin on 2017/12/5.
26 | */
27 |
28 | public class Module implements IXposedHookLoadPackage {
29 |
30 |
31 | public static Context applicationContext = null;
32 |
33 | public static Context getApplicationContext() {
34 | return applicationContext;
35 | }
36 |
37 | // ContentResolver resolver;
38 | // Uri uri = Uri.parse("content://com.example.admin.wxaddfrienddemo.provider");
39 |
40 | MyBroadcastReceiver receiver = null;
41 |
42 |
43 | @Override
44 | public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
45 |
46 | if (loadPackageParam.packageName.equals("com.tencent.mm")){
47 | Log.i("xyz","进来handleLoadPackage方法");
48 |
49 | // 获取到当前进程的上下文
50 | try{
51 | Class> launcherUI = XposedHelpers.findClass("com.tencent.mm.ui.LauncherUI", loadPackageParam.classLoader);
52 | XposedHelpers.findAndHookMethod(launcherUI, "onResume", new XC_MethodHook() {
53 | // Class> ContextClass = findClass("android.content.ContextWrapper",loadPackageParam.classLoader);
54 | // findAndHookMethod(ContextClass, "getApplicationContext", new XC_MethodHook() {
55 | @Override
56 | protected void afterHookedMethod(MethodHookParam param) throws Throwable {
57 | super.afterHookedMethod(param);
58 | applicationContext = (Context) param.thisObject;
59 | // Log.i("xyz","Module得到上下文");
60 | XposedBridge.log("Module得到上下文");
61 |
62 |
63 | if (receiver == null){
64 | IntentFilter filter = new IntentFilter("com.example.admin.wxaddfrienddemo.broadcast");
65 | receiver = new MyBroadcastReceiver(applicationContext);
66 | AndroidAppHelper.currentApplication().getApplicationContext().registerReceiver(receiver,filter);
67 | Log.i("xyz","Xposed注册广播");
68 | }
69 |
70 | }
71 | });
72 | }catch (Throwable throwable){
73 | XposedBridge.log("Module获取上下文失败 "+throwable);
74 | Log.i("xyz","Module获取上下文失败");
75 | }
76 |
77 | }
78 |
79 | }
80 |
81 |
82 | }
83 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # WxAddFriendDemo
2 |
3 |
4 | 1.0
5 |
6 | 寻找添加好友时传入的参数的情况,分析得到每个参数的意义和必要性,最后得出结论。
7 |
8 |
9 | 然后不同的方式有不同的bundle参数,总的来说分为三种
10 |
11 |
12 | 一、搜索方式
13 |
14 | 1、通过搜索微信号的方式
15 |
16 | 2、通过搜索手机号的方式
17 |
18 | 二、群的方式
19 |
20 | 1、直接在聊天界面中点击别人的头像的方式
21 |
22 |
23 |
24 | 2、点击右上角的群信息再点击具体的人添加
25 |
26 |
27 | 三、手机通讯录,也就是在微信中点击添加手机通讯录的方式
28 |
29 |
30 | 一、搜索的方式
31 |
32 | 搜索微信号的形式
33 |
34 | I/set ( 2625): intent = Intent { cmp=com.tencent.mm/.plugin.profile.ui.ContactInfoUI (has extras) }
35 | I/set ( 2625): bundle = Bundle[{Contact_NeedShowChangeRemarkButton=false, Contact_QuanPin=wxidqgpqsx2ozvlp22, Contact_PyInitial=WXIDQGPQSX2OZVLP22, Contact_RegionCode=, Contact_BrandList=, Contact_KSnsBgId=0, add_more_friend_search_scene=2, Contact_KWeiboNick=null, Contact_KSnsBgUrl=null, Contact_KSnsIFlag=0, Contact_KWeibo_flag=0, Contact_Signature=null, Contact_BIZ_KF_WORKER_ID=null, Contact_VUser_Info=null, Contact_KHideExpose=true, Contact_Nick=慧雯, Contact_User=v1_2c36ea4042bb6e382de53f1966494a8fc1bb9ebac4ae1eb02b1b346233b27b3dc98d9b4466a947552462be8d5c0111b8@stranger, Contact_VUser_Info_Flag=0, Contact_Sex=0, Contact_Alias=sdq13540497060, Contact_Scene=3, Contact_KWeibo=null, Contact_NeedShowChangeSnsPreButton=false}]
36 |
37 | 搜索手机号的形式
38 |
39 | I/set ( 2625): intent = Intent { cmp=com.tencent.mm/.plugin.profile.ui.ContactInfoUI (has extras) }
40 | I/set ( 2625): bundle = Bundle[{Contact_NeedShowChangeRemarkButton=false, Contact_QuanPin=wxidpkspt5ckkejk12, Contact_PyInitial=WXIDPKSPT5CKKEJK12, Contact_RegionCode=, Contact_BrandList=, Contact_KSnsBgId=0, add_more_friend_search_scene=2, Contact_Search_Mobile=18814143558, Contact_KWeiboNick=null, Contact_KSnsBgUrl=null, Contact_KSnsIFlag=0, Contact_KWeibo_flag=0, Contact_Signature=null, Contact_BIZ_KF_WORKER_ID=null, Contact_VUser_Info=null, Contact_KHideExpose=true, Contact_Nick=趁你我还年轻, Contact_User=v1_6f37fdf0632e975154dcb187f1408fe15feee4047fe4d313de611496f1074ddcb64016d8947ab158ab6e9af86a134daf@stranger, Contact_VUser_Info_Flag=0, Contact_Sex=0, Contact_Alias=FJX613558, Contact_Scene=15, Contact_KWeibo=null, Contact_NeedShowChangeSnsPreButton=false}]
41 |
42 | 二、群里非好友时
43 |
44 | 直接在聊天界面点击头像
45 |
46 | I/set ( 2625): intent = Intent { cmp=com.tencent.mm/.plugin.profile.ui.ContactInfoUI (has extras) }
47 | I/set ( 2625): bundle = Bundle[{Contact_NeedShowChangeRemarkButton=false, room_name=636235605@chatroom, Is_RoomOwner=false, Contact_RoomNickname=吃瓜的鸿, Contact_User=wxid_n24mdcaqj37s22, Contact_Scene=14, Contact_NeedShowChangeSnsPreButton=false}]
48 |
49 |
50 | 先点击右上角显示群信息,再点击头像
51 | I/set ( 2625): intent = Intent { cmp=com.tencent.mm/.plugin.profile.ui.ContactInfoUI (has extras) }
52 | I/set ( 2625): bundle = Bundle[{Contact_NeedShowChangeRemarkButton=false, Contact_Mobile_MD5=, Contact_ChatRoomId=636235605@chatroom, room_name=636235605@chatroom, Is_RoomOwner=false, Contact_RoomNickname=蔡建, Contact_RoomMember=true, Contact_Nick=林, Contact_User=wxid_lnt4ahvg2esr22, Contact_Scene=14, Contact_RemarkName=, Contact_NeedShowChangeSnsPreButton=false}]
53 |
54 | 三、通讯录方式
55 | I/set ( 2625): intent = Intent { cmp=com.tencent.mm/.plugin.profile.ui.ContactInfoUI (has extras) }
56 | I/set ( 2625): bundle = Bundle[{Contact_NeedShowChangeRemarkButton=false, Contact_Mobile_MD5=270bae1b55a890759987f9047b81c027, Contact_RegionCode=CN_Guangdong_Dongguan, Contact_ShowUserName=false, Contact_Signature= boeey, Contact_Nick=桌球, Contact_User=v1_f2beaa1797ef0252d0421242b04ab14613f59c18c49bab2e395fc26badaf517a@stranger, Contact_Sex=1, Contact_Alias=, Contact_Scene=13, Contact_NeedShowChangeSnsPreButton=false}]
57 |
58 |
59 | 2.0
60 |
61 | 通过前面总结的规律,实现自动添加好友的效果。
62 |
63 | 在ui布局中,要求可以选择一个txt文本。里面有要添加的微信id的值。每行一个,实现自动遍历该文本中的微信id,添加相应的好友。
64 |
65 | 界面可以选择用户想要的添加场景,每次添加的时间间隔,用户想要填入的验证信息,当前添加的人数。
66 |
67 | 具体逻辑看代码,注释很清楚了。
68 |
69 | 3.0
70 |
71 | 新增两种三种添加场景,分别为搜索QQ号,名片,二维码的方式,它们的场景号为12,17,30.
72 |
73 | 名片的添加会有新的字段v2值,看起来像是用于反垃圾的票据,而且添加到同一个人3次会报出加人频繁了,还有就是如果对方设置了不能通过名片获取到他的信息,也是无法添加的。
74 |
75 | 二维码的也有v2值,其他没啥限制。
76 |
77 | 看更新的ManiActivity.class
78 |
79 |
80 | 修改添加人的逻辑实现
81 |
82 | 遇到的问题:
83 |
84 | 首先就是更改查找的方式,之前是通过id的方式,这种每次微信一更新就会改变id,所以要用一种通用的方式来实现。通过查找页面中的文本来获取控件。
85 | 递归查找当前页面是否有输入框/返回键,要设置一个临时变量,不然递归返回的是个参数,所以每次都为null,而且记得找到就return ,而不是刚开始改进的那种break的方式。
86 |
87 | 然后就是线程通过问题了,因为要在activity中获取到辅助功能类的服务,而且在界面变化时执行相应的操作,这就需要在activity和service之间共享变量了。每次获取前睡眠一段时间,直到获取到最新的值为止。有一个需要注意的地方就是Android的activity和service都是在主线程的,所以在activity中开启子线程执行操作,这样睡眠时让出cpu给主线程执行,实现同步。
88 |
89 | 最后就是吐司的问题了,因为前面提到,activity中的操作都是在子线程执行的,所以在吐司时就是在子线程,然后这里的子线程的吐司有很大的几率被微信自己的覆盖了,所以吐司时通过handler来实现在主线程操作,这样吐司才能正常显示。
90 |
91 | 其他的就是一些小问题了,现在的代码在本地测试是没问题的,但是如果cpu占用高的情况下,就会出现一些奇怪的问题,所以还需要再次改进。
92 |
93 | 4.0
94 |
95 | 添加时自动跳转界面的调整。
96 |
97 | 之前的如果cpu占用高或者网速不好的话,可能获取不到控件,所以现在是利用 do while的方式来不断的获取,当然也有一个超时限制,然后在每个操作之间的间隔调高,增加稳定性,加快删除原本的验证信息的速率。这样的稳定性就非常好了。
98 | 然后还有考虑到特殊情况的处理,比如对方设置了某种场景你不能添加到他的时候,此时就应该点击确定后再点击返回到主界面。
99 |
100 |
101 | 今天最后的版本就是在ui界面中添加了一个可以设置添加时bundle参数填入的多少选择,有三种情况,后面的两种有三种场景可用,第一种情况没有限制。
102 |
103 | 每次操作间的时间间隔也来了个随机生成的,在1500到2000毫秒之间。
104 |
105 | 5.0
106 |
107 | 新增直接跳转到验证界面填入验证信息加人,而不是到用户界面再点击添加的方式。这种需要注意的就是通过intent的方式来跳转的,不是之前的adb的方式。所以需要用到微信的context,需要hook来拿到,然后又是进程间通信的问题。这里不能用之前的SharedPrefrences结合ContentProvider的方式来通信,因为如果是这种方式的话,会在hook中做跳转界面的操作。但是hook又是一个不断的过程,所以会卡顿到微信的打开。换一个思路,采用BroadcastReceiver的方式,通过在activity发送广播,在xposed中注册广播,然后将获取到的微信Context传给广播接收者,在onReceiver() 中去执行界面的跳转操作。
108 |
109 | 6.0
110 |
111 | 直接添加方式时新增推荐人wxid和昵称参数
112 |
113 | 修改界面的提示信息
114 |
115 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_add.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
17 |
18 |
27 |
28 |
29 |
39 |
40 |
41 |
51 |
52 |
60 |
61 |
69 |
70 |
81 |
82 |
91 |
92 |
102 |
103 |
115 |
116 |
127 |
128 |
139 |
140 |
151 |
152 |
153 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/admin/wxaddfrienddemo/AddUtils.java:
--------------------------------------------------------------------------------
1 | package com.example.admin.wxaddfrienddemo;
2 |
3 | import android.accessibilityservice.AccessibilityService;
4 | import android.content.ContentValues;
5 | import android.content.Context;
6 | import android.content.Intent;
7 | import android.util.Log;
8 | import android.widget.Toast;
9 |
10 | import java.io.IOException;
11 |
12 | /**
13 | * Created by admin on 2017/11/8.
14 | */
15 |
16 | public class AddUtils {
17 | /**
18 | * 通过v1或者是wxid 加人
19 | * @param v1 对方的v1值
20 | * @param scene 场景方式
21 | * @param bundleScene bundle参数方式
22 | */
23 | public static void addFriend(String v1,int scene,int bundleScene){
24 |
25 | // 计算出py的值
26 | String py = "";
27 | String [] ss = v1.split("_");
28 | for (String s1:ss){
29 | py +=s1;
30 | }
31 | // 将py转化为大写
32 | String upper = py.toUpperCase();
33 |
34 | if (bundleScene == 1){// 只有contact user和场景
35 | String s = "adb shell am start -n com.tencent.mm/com.tencent.mm.plugin.profile.ui.ContactInfoUI "+
36 | "--es Contact_User \""+v1+"\" "+
37 | "--ei Contact_Scene "+ scene +" "+
38 | "";
39 | try {
40 | Runtime.getRuntime().exec(s);
41 | } catch (IOException e) {
42 | e.printStackTrace();
43 | }
44 | }else if (bundleScene == 2 ){ // bundle类型为2,所有参数除了brand
45 |
46 | if(scene == 15){ // 通过手机号搜索
47 | //I/set ( 1193): bundle = Bundle[{Contact_NeedShowChangeRemarkButton=false, Contact_QuanPin=wxidlnt4ahvg2esr22,
48 | // Contact_PyInitial=WXIDLNT4AHVG2ESR22, Contact_RegionCode=CN_Guangdong_Guangzhou, Contact_BrandList=,
49 | // Contact_KSnsBgId=0, add_more_friend_search_scene=2, Contact_Search_Mobile=18814143556, Contact_KWeiboNick=null, Contact_KSnsBgUrl=null,
50 | // Contact_KSnsIFlag=0, Contact_KWeibo_flag=0, Contact_Signature=多的是,你不知道的事, Contact_BIZ_KF_WORKER_ID=null, Contact_VUser_Info=null,
51 | // Contact_KHideExpose=true, Contact_Nick=林, Contact_User=wxid_lnt4ahvg2esr22, Contact_VUser_Info_Flag=0, Contact_Sex=1,
52 | // Contact_Alias=q961513094, Contact_Scene=15, Contact_KWeibo=null,
53 | // AntispamTicket=v2_e574085f9339eb7cdac3e14cac25a4bcbb1f186311910df6c32be54b4ebe4c5b3caafa2fcee01e96195b5e1c39f1dd8f@stranger,
54 | // Contact_NeedShowChangeSnsPreButton=false}]
55 | String s = "adb shell am start -n com.tencent.mm/com.tencent.mm.plugin.profile.ui.ContactInfoUI "+
56 | "--ez Contact_NeedShowChangeRemarkButton false "+
57 | "--es Contact_QuanPin \""+py+"\" "+
58 | "--es Contact_PyInitial \""+upper+"\" "+
59 | "--ei Contact_KSnsBgId 0 "+
60 | "--ei add_more_friend_search_scene 2 " +
61 | "--es Contact_KWeiboNick \"null\" "+
62 | "--es Contact_KSnsBgUrl \"null\" "+
63 | "--ei Contact_KSnsIFlag 0 "+
64 | "--ei Contact_KWeibo_flag 0 "+
65 | "--es Contact_Signature \"null\" "+
66 | "--es Contact_BIZ_KF_WORKER_ID \"null\" "+
67 | "--es Contact_VUser_Info \"null\" "+
68 | "--ez Contact_KHideExpose true "+
69 | "--es Contact_User \""+v1+"\" "+
70 | "--ei Contact_VUser_Info_Flag 0 "+
71 | "--ei Contact_Scene "+ scene +" "+
72 | "--es Contact_KWeibo \"null\" "+
73 | "--ez Contact_NeedShowChangeSnsPreButton false "+
74 | "";
75 | try {
76 | Runtime.getRuntime().exec(s);
77 | } catch (IOException e) {
78 | e.printStackTrace();
79 | }
80 | }else if (scene == 14){ // 通过群好友
81 | // I/set ( 1107): bundle = Bundle[{Contact_NeedShowChangeRemarkButton=false, Contact_ChatRoomId=636235605@chatroom,
82 | // room_name=636235605@chatroom, Is_RoomOwner=false, Contact_RoomNickname=蔡建, Contact_User=wxid_lnt4ahvg2esr22, Contact_Scene=14,
83 | // Contact_NeedShowChangeSnsPreButton=false}]
84 | String s = "adb shell am start -n com.tencent.mm/com.tencent.mm.plugin.profile.ui.ContactInfoUI "+
85 | "--ez Contact_NeedShowChangeRemarkButton false "+
86 | // "--es Contact_ChatRoomId \"636235605@chatroom\" "+
87 | // "--es room_name \"636235605@chatroom\" "+
88 | "--ez Is_RoomOwner false "+
89 | // "--es Contact_RoomNickname \"蔡建\" "+
90 | "--es Contact_User \""+v1+"\" "+
91 | "--ei Contact_Scene "+ scene +" "+
92 | "--ez Contact_NeedShowChangeSnsPreButton false "+
93 | "";
94 | try {
95 | Runtime.getRuntime().exec(s);
96 | } catch (IOException e) {
97 | e.printStackTrace();
98 | }
99 | }else if (scene == 30) {// 通过扫一扫
100 | //I/set ( 1517): bundle = Bundle[{Contact_NeedShowChangeRemarkButton=false, Contact_QuanPin=wxidqxve6fsx4ery12,
101 | // Contact_PyInitial=WXIDQXVE6FSX4ERY12, Contact_RegionCode=CN_Guangdong_Guangzhou,
102 | // Contact_BrandList=, Contact_KSnsBgId=0, Contact_IsLBSFriend=true,
103 | // Contact_KWeiboNick=null, Contact_KSnsBgUrl=null, Contact_KSnsIFlag=0, Contact_KWeibo_flag=0,
104 | // Contact_Signature=宅若久时天然呆, 呆到深处自然萌, Contact_BIZ_KF_WORKER_ID=null, Contact_VUser_Info=null,
105 | // Contact_KHideExpose=true, Contact_Nick=雯雯,
106 | // Contact_User=v1_4b6ece89d367aed49ce765008cd11b297b3c3836bbc71c70ad71dc3e5da1b2359ee868dfe958ef76121ce676f53ab246@stranger,
107 | // Contact_VUser_Info_Flag=0, Contact_Sex=2, Contact_Alias=aa15596417033, Contact_Scene=30, Contact_KWeibo=null,
108 | // AntispamTicket=v2_973dea324a20f5da3d5de134c8c725d768ffb73ba1ec057d61c89f3140fb128e211dd1239af7f458ef7d20df144fcc76@stranger,
109 | // Contact_NeedShowChangeSnsPreButton=false}]
110 | String s = "adb shell am start -n com.tencent.mm/com.tencent.mm.plugin.profile.ui.ContactInfoUI "+
111 | "--ez Contact_NeedShowChangeRemarkButton false "+
112 | "--es Contact_QuanPin \""+py+"\" "+
113 | "--es Contact_PyInitial \""+upper+"\" "+
114 | "--ei Contact_KSnsBgId 0 "+
115 | "--ez Contact_IsLBSFriend true "+
116 | "--es Contact_KWeiboNick \"null\" "+
117 | "--es Contact_KSnsBgUrl \"null\" "+
118 | "--ei Contact_KSnsIFlag 0 "+
119 | "--ei Contact_KWeibo_flag 0 "+
120 | "--es Contact_Signature \"null\" "+
121 | "--es Contact_BIZ_KF_WORKER_ID \"null\" "+
122 | "--es Contact_VUser_Info \"null\" "+
123 | "--ez Contact_KHideExpose true "+
124 | "--es Contact_User \""+v1+"\" "+
125 | "--ei Contact_VUser_Info_Flag 0 "+
126 | "--ei Contact_Scene "+ scene +" "+
127 | "--es Contact_KWeibo \"null\" "+
128 | "--ez Contact_NeedShowChangeSnsPreButton false "+
129 | "";
130 | try {
131 | Runtime.getRuntime().exec(s);
132 | } catch (IOException e) {
133 | e.printStackTrace();
134 | }
135 | }
136 |
137 |
138 | }else if (bundleScene == 3){ // bundle类型为3的时候
139 |
140 | if(scene == 15){ // 通过手机号搜索
141 | //I/set ( 1193): bundle = Bundle[{Contact_NeedShowChangeRemarkButton=false, Contact_QuanPin=wxidlnt4ahvg2esr22,
142 | // Contact_PyInitial=WXIDLNT4AHVG2ESR22, Contact_RegionCode=CN_Guangdong_Guangzhou, Contact_BrandList=,
143 | // Contact_KSnsBgId=0, add_more_friend_search_scene=2, Contact_Search_Mobile=18814143556, Contact_KWeiboNick=null, Contact_KSnsBgUrl=null,
144 | // Contact_KSnsIFlag=0, Contact_KWeibo_flag=0, Contact_Signature=多的是,你不知道的事, Contact_BIZ_KF_WORKER_ID=null, Contact_VUser_Info=null,
145 | // Contact_KHideExpose=true, Contact_Nick=林, Contact_User=wxid_lnt4ahvg2esr22, Contact_VUser_Info_Flag=0, Contact_Sex=1,
146 | // Contact_Alias=q961513094, Contact_Scene=15, Contact_KWeibo=null,
147 | // AntispamTicket=v2_e574085f9339eb7cdac3e14cac25a4bcbb1f186311910df6c32be54b4ebe4c5b3caafa2fcee01e96195b5e1c39f1dd8f@stranger,
148 | // Contact_NeedShowChangeSnsPreButton=false}]
149 | String s = "adb shell am start -n com.tencent.mm/com.tencent.mm.plugin.profile.ui.ContactInfoUI "+
150 | "--ez Contact_NeedShowChangeRemarkButton false "+
151 | "--es Contact_QuanPin \""+py+"\" "+
152 | "--es Contact_PyInitial \""+upper+"\" "+
153 | "--es Contact_BrandList \"\" "+
154 | "--ei Contact_KSnsBgId 0 "+
155 | "--ei add_more_friend_search_scene 2 " +
156 | "--es Contact_KWeiboNick \"null\" "+
157 | "--es Contact_KSnsBgUrl \"null\" "+
158 | "--ei Contact_KSnsIFlag 0 "+
159 | "--ei Contact_KWeibo_flag 0 "+
160 | "--es Contact_Signature \"null\" "+
161 | "--es Contact_BIZ_KF_WORKER_ID \"null\" "+
162 | "--es Contact_VUser_Info \"null\" "+
163 | "--ez Contact_KHideExpose true "+
164 | "--es Contact_User \""+v1+"\" "+
165 | "--ei Contact_VUser_Info_Flag 0 "+
166 | "--ei Contact_Scene "+ scene +" "+
167 | "--es Contact_KWeibo \"null\" "+
168 | "--ez Contact_NeedShowChangeSnsPreButton false "+
169 | "";
170 | try {
171 | Runtime.getRuntime().exec(s);
172 | } catch (IOException e) {
173 | e.printStackTrace();
174 | }
175 | }else if (scene == 14){ // 通过群好友
176 | // I/set ( 1107): bundle = Bundle[{Contact_NeedShowChangeRemarkButton=false, Contact_ChatRoomId=636235605@chatroom,
177 | // room_name=636235605@chatroom, Is_RoomOwner=false, Contact_RoomNickname=蔡建, Contact_User=wxid_lnt4ahvg2esr22, Contact_Scene=14,
178 | // Contact_NeedShowChangeSnsPreButton=false}]
179 | String s = "adb shell am start -n com.tencent.mm/com.tencent.mm.plugin.profile.ui.ContactInfoUI "+
180 | "--ez Contact_NeedShowChangeRemarkButton false "+
181 | // "--es Contact_ChatRoomId \"636235605@chatroom\" "+
182 | // "--es room_name \"636235605@chatroom\" "+
183 | "--ez Is_RoomOwner false "+
184 | // "--es Contact_RoomNickname \"蔡建\" "+
185 | "--es Contact_User \""+v1+"\" "+
186 | "--ei Contact_Scene "+ scene +" "+
187 | "--ez Contact_NeedShowChangeSnsPreButton false "+
188 | "";
189 | try {
190 | Runtime.getRuntime().exec(s);
191 | } catch (IOException e) {
192 | e.printStackTrace();
193 | }
194 | }else if (scene == 30) {// 通过扫一扫
195 | //I/set ( 1517): bundle = Bundle[{Contact_NeedShowChangeRemarkButton=false, Contact_QuanPin=wxidqxve6fsx4ery12,
196 | // Contact_PyInitial=WXIDQXVE6FSX4ERY12, Contact_RegionCode=CN_Guangdong_Guangzhou,
197 | // Contact_BrandList=, Contact_KSnsBgId=0, Contact_IsLBSFriend=true,
198 | // Contact_KWeiboNick=null, Contact_KSnsBgUrl=null, Contact_KSnsIFlag=0, Contact_KWeibo_flag=0,
199 | // Contact_Signature=宅若久时天然呆, 呆到深处自然萌, Contact_BIZ_KF_WORKER_ID=null, Contact_VUser_Info=null,
200 | // Contact_KHideExpose=true, Contact_Nick=雯雯,
201 | // Contact_User=v1_4b6ece89d367aed49ce765008cd11b297b3c3836bbc71c70ad71dc3e5da1b2359ee868dfe958ef76121ce676f53ab246@stranger,
202 | // Contact_VUser_Info_Flag=0, Contact_Sex=2, Contact_Alias=aa15596417033, Contact_Scene=30, Contact_KWeibo=null,
203 | // AntispamTicket=v2_973dea324a20f5da3d5de134c8c725d768ffb73ba1ec057d61c89f3140fb128e211dd1239af7f458ef7d20df144fcc76@stranger,
204 | // Contact_NeedShowChangeSnsPreButton=false}]
205 | String s = "adb shell am start -n com.tencent.mm/com.tencent.mm.plugin.profile.ui.ContactInfoUI "+
206 | "--ez Contact_NeedShowChangeRemarkButton false "+
207 | "--es Contact_QuanPin \""+py+"\" "+
208 | "--es Contact_PyInitial \""+upper+"\" "+
209 | "--es Contact_BrandList \"\" "+
210 | "--ei Contact_KSnsBgId 0 "+
211 | "--ez Contact_IsLBSFriend true "+
212 | "--es Contact_KWeiboNick \"null\" "+
213 | "--es Contact_KSnsBgUrl \"null\" "+
214 | "--ei Contact_KSnsIFlag 0 "+
215 | "--ei Contact_KWeibo_flag 0 "+
216 | "--es Contact_Signature \"null\" "+
217 | "--es Contact_BIZ_KF_WORKER_ID \"null\" "+
218 | "--es Contact_VUser_Info \"null\" "+
219 | "--ez Contact_KHideExpose true "+
220 | "--es Contact_User \""+v1+"\" "+
221 | "--ei Contact_VUser_Info_Flag 0 "+
222 | "--ei Contact_Scene "+ scene +" "+
223 | "--es Contact_KWeibo \"null\" "+
224 | "--ez Contact_NeedShowChangeSnsPreButton false "+
225 | "";
226 | try {
227 | Runtime.getRuntime().exec(s);
228 | } catch (IOException e) {
229 | e.printStackTrace();
230 | }
231 | }
232 | }
233 |
234 | }
235 |
236 |
237 |
238 |
239 | public static void addFriendByWxid(Context context,String wxid,int scene,String tuiWxid,String tuiNickName){
240 |
241 | Log.i("xyz","进入addFriendByWxid context = "+context +" wxid "+wxid+" scene "+scene);
242 |
243 | Intent params = new Intent();
244 | params.setClassName(context, "com.tencent.mm.plugin.profile.ui.SayHiWithSnsPermissionUI");
245 | params.putExtra("sayhi_with_sns_perm_send_verify", true);
246 | params.putExtra("room_name", "null");
247 | params.putExtra("source_from_user_name", tuiWxid);
248 | params.putExtra("sayhi_with_sns_perm_add_remark", true);
249 | params.putExtra("source_from_nick_name", tuiNickName);
250 | params.putExtra("Contact_Nick", "");
251 | params.putExtra("Contact_User", wxid);
252 | params.putExtra("Contact_Scene", scene);
253 | params.putExtra("Contact_RemarkName", "");
254 | params.putExtra("sayhi_with_sns_perm_set_label", false);
255 | context.startActivity(params);
256 | }
257 |
258 |
259 | // 自动生成9位数的字符串
260 | static String getRandom(){
261 | Double random = Math.random();
262 | String str = random.toString().substring(2,11);
263 | return str;
264 | }
265 |
266 | }
267 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/admin/wxaddfrienddemo/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.example.admin.wxaddfrienddemo;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.content.ComponentName;
5 | import android.content.ContentUris;
6 | import android.content.Context;
7 | import android.content.Intent;
8 | import android.content.pm.PackageInfo;
9 | import android.content.pm.PackageManager;
10 | import android.database.Cursor;
11 | import android.net.Uri;
12 | import android.os.Build;
13 | import android.os.Environment;
14 | import android.provider.DocumentsContract;
15 | import android.provider.MediaStore;
16 | import android.support.v7.app.AppCompatActivity;
17 | import android.os.Bundle;
18 | import android.text.TextPaint;
19 | import android.text.TextUtils;
20 | import android.util.Log;
21 | import android.view.View;
22 | import android.widget.Button;
23 | import android.widget.EditText;
24 | import android.widget.TextView;
25 | import android.widget.Toast;
26 |
27 | import java.io.BufferedReader;
28 | import java.io.File;
29 | import java.io.FileInputStream;
30 | import java.io.FileNotFoundException;
31 | import java.io.FileReader;
32 | import java.io.IOException;
33 | import java.io.InputStreamReader;
34 | import java.util.ArrayList;
35 | import java.util.List;
36 |
37 | import static com.example.admin.wxaddfrienddemo.AddUtils.getRandom;
38 |
39 | public class MainActivity extends AppCompatActivity {
40 |
41 | private static final String TAG = "xyz";
42 |
43 |
44 | @Override
45 | protected void onCreate(Bundle savedInstanceState) {
46 | super.onCreate(savedInstanceState);
47 | setContentView(R.layout.activity_main);
48 |
49 | if (isWxAviliable()){
50 | gotoWxFriend();
51 | }
52 |
53 | // findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {
54 | // @Override
55 | // public void onClick(View view) {
56 | // if (isWxAviliable()){
57 | // gotoWxFriend();
58 | // }
59 | // }
60 | // });
61 | }
62 |
63 |
64 |
65 | // 是否安装了微信
66 | private boolean isWxAviliable() {
67 | PackageManager pm = getPackageManager();
68 | List list = pm.getInstalledPackages(0);
69 | for (PackageInfo info : list){
70 | String pkg = info.packageName;
71 | if (pkg.equals("com.tencent.mm")){
72 | Log.i(TAG, "isWxAviliable: "+true);
73 | return true;
74 | }
75 | }
76 | Log.i(TAG, "isWxAviliable: "+false);
77 | return false;
78 | }
79 |
80 | private void gotoWxFriend() {
81 | // 微信主界面可以通过这种代码的方式直接打开,但是这次的目标是到加好友的界面,所以得采用adb命令的形式
82 | // Intent intent = new Intent(Intent.ACTION_MAIN);
83 | // intent.addCategory(Intent.CATEGORY_LAUNCHER);
84 | // ComponentName cn = new ComponentName("com.tencent.mm","com.tencent.mm.ui.LauncherUI");
85 | // intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
86 | // intent.setComponent(cn);
87 | // startActivity(intent);
88 |
89 |
90 |
91 | // ei表示插入的bundle是int类型,es表示是String,注意加上""(这里用转义字符), ez表示boolean类型
92 | try {
93 | //I/set ( 2625): intent = Intent { cmp=com.tencent.mm/.plugin.profile.ui.ContactInfoUI (has extras) }
94 | // I/set ( 2625): bundle = Bundle[{Contact_NeedShowChangeRemarkButton=false, Contact_QuanPin=wxidmj208er62zri22,
95 | // Contact_PyInitial=WXIDMJ208ER62ZRI22, Contact_RegionCode=, Contact_BrandList=,
96 | // Contact_KSnsBgId=0, add_more_friend_search_scene=2, Contact_KWeiboNick=null, Contact_KSnsBgUrl=null, Contact_KSnsIFlag=0,
97 | // Contact_KWeibo_flag=0, Contact_Signature=null, Contact_BIZ_KF_WORKER_ID=null, Contact_VUser_Info=null, Contact_KHideExpose=true,
98 | // Contact_Nick=明, Contact_User=v1_cecdf08b2bda1a00e1263cca852eb5aefa6cbdec9fde130f32b1d1d7b1a80ff363bfd4426332556365b479beadc44169@stranger,
99 | // Contact_VUser_Info_Flag=0, Contact_Sex=0, Contact_Alias=lyming1965, Contact_Scene=3, Contact_KWeibo=null, Contact_NeedShowChangeSnsPreButton=false}]
100 | // 通过微信号搜索的形式
101 | String s = "adb shell am start -n com.tencent.mm/com.tencent.mm.plugin.profile.ui.ContactInfoUI "+
102 | // "--ez Contact_NeedShowChangeRemarkButton false "+ // 都是false,可以不用管
103 | // "--es Contact_QuanPin \"wxidmj208er62zri22\" "+ // 微信id ,有些人没有就是微信号,这个asd就是没有的那种。
104 | // "--es Contact_PyInitial \"WXIDMJ208ER62ZRI22\" "+
105 | // "--es Contact_RegionCode \"\" "+ // 地区,去掉也行,会自己显示出来
106 | // "--ei add_more_friend_search_scene 2 "+ // 都为2,无论是通过手机号或者是微信号,可不管
107 | // "--ez Contact_KHideExpose true "+ // 都是true ,去掉也行
108 | // "--es Contact_Nick \"明\" "+ // 微信昵称 ,可以改动,去掉显示微信号了
109 | // 只要有这个v1就可以了,去掉就不行了
110 | // "--es Contact_User \"v1_f2beaa1797ef0252d0421242b04ab14613f59c18c49bab2e395fc26badaf517a@stranger\" "+ // v1 值
111 | "--es Contact_User \"v1_3030c5f2180425b41b787251deae1f25f4c3b9135b75109c44248cd1f245241ff77aedf1ef2502d629fd7eadaa543a71@stranger\" "+
112 | // "--ei Contact_VUser_Info_Flag 0 "+ // 都为0,可去掉
113 | // "--ei Contact_Sex 1 "+ // 性别,0为女 1为男。设置错误或者去掉的话,性别就没有显示出来了
114 | // "--es Contact_Alias \"lyming1965\" "+ // 微信号
115 | "--ei Contact_Scene 15 " +// 微信号搜索的为3,手机号搜索为15
116 | // "--ez Contact_NeedShowChangeSnsPreButton false " + // 都是false,可以去掉
117 |
118 | // "Contact_Search_Mobile \"13430013863\" "+ // 通过手机搜索的方式,多这个参数
119 | "";
120 |
121 | // 通过手机号搜索的形式,多了这个字段 Contact_Search_Mobile=13430013863; 然后就是Contact_Scene 为15 ,其他都一样
122 | // Runtime.getRuntime().exec(s);
123 |
124 |
125 | // 现在通过群跳转到加人的界面,有两种,第一种是直接在聊天界面点击头像的情况,
126 |
127 | //I/set ( 2625): bundle = Bundle[{Contact_NeedShowChangeRemarkButton=false, room_name=636235605@chatroom,
128 | // Is_RoomOwner=false, Contact_RoomNickname=吃瓜的鸿, Contact_User=wxid_n24mdcaqj37s22,
129 | // Contact_Scene=14, Contact_NeedShowChangeSnsPreButton=false}]
130 |
131 | String s1 = "adb shell am start -n com.tencent.mm/com.tencent.mm.plugin.profile.ui.ContactInfoUI "+
132 | // "--ez Contact_NeedShowChangeRemarkButton false "+ // 都是false,可以不用管
133 | // "--es room_name \"636235605@chatroom\" "+ // 群号,加不加都行。。。
134 | // "--ez Is_RoomOwner false "+ // 全为false 一开始猜测是否是群主,但是结果不是。
135 | // "--es Contact_RoomNickname \"吃瓜的鸿\" "+ // 群昵称,可修改,去掉不显示
136 | "--es Contact_User \"wxid_n24mdcaqj37s22\" "+ // 微信id,只给这个就可以跳到加人界面了
137 | "--ei Contact_Scene 3 " +// 微信号搜索的为3,手机号搜索为15,群的方式是14
138 | // "--ez Contact_NeedShowChangeSnsPreButton false " + // 都是false,可以去掉
139 | // 第二种是点击右上角显示群信息后再点击群员到加人的界面,多了如下三个字段
140 | // "--es Contact_ChatRoomId \"636235605@chatroom\" "+
141 | // "--es Contact_Nick \"Hong\" "+ // 昵称
142 | // "--ez Contact_RoomMember true "+ // 全为true
143 | "";
144 | // Runtime.getRuntime().exec(s1);
145 |
146 | // 通讯录方式
147 | //I/set ( 2625): bundle = Bundle[{Contact_NeedShowChangeRemarkButton=false,
148 | // Contact_Mobile_MD5=270bae1b55a890759987f9047b81c027, Contact_RegionCode=CN_Guangdong_Dongguan,
149 | // Contact_ShowUserName=false, Contact_Signature= boeey, Contact_Nick=桌球,
150 | // Contact_User=v1_f2beaa1797ef0252d0421242b04ab14613f59c18c49bab2e395fc26badaf517a@stranger,
151 | // Contact_Sex=1, Contact_Alias=, Contact_Scene=13, Contact_NeedShowChangeSnsPreButton=false}]
152 |
153 | String s2 = "adb shell am start -n com.tencent.mm/com.tencent.mm.plugin.profile.ui.ContactInfoUI "+
154 | "--es Contact_Mobile_MD5 \"270bae1b55a890759987f9047b81c027\" "+ // 手机号码的MD5值
155 | "--ez Contact_ShowUserName false "+ // 全为false
156 | // "--es Contact_Signature \"boeey\" "+ // 个性签名
157 | "--es Contact_Nick \"桌球\" "+ // 昵称
158 | // v1 值,只给这个就可以跳到加人界面了
159 | "--es Contact_User \"v1_f2beaa1797ef0252d0421242b04ab14613f59c18c49bab2e395fc26badaf517a@stranger\" "+
160 | "--ei Contact_Scene 13 " + // 微信号搜索的为3,手机号搜索为15,群的方式是14,通讯录是13
161 | "--ei Contact_Sex 1 " + // 性别,1为男,2为女
162 | "--ez Contact_NeedShowChangeSnsPreButton false " + // 都是false,可以去掉
163 | "";
164 | // Runtime.getRuntime().exec(s2);
165 |
166 |
167 | // 名片的方式,有一个细节,就是推名片的时候,推荐人可以看到被推荐人的wxid,收信息的人看不到
168 | // I/set ( 1116): intent = Intent { cmp=com.tencent.mm/.plugin.profile.ui.ContactInfoUI (has extras) }
169 | // I/set ( 1116): bundle = Bundle[{Contact_NeedShowChangeRemarkButton=false, Contact_QuanPin=莎雯[西瓜],
170 | // Contact_Mobile_MD5=null, Contact_PyInitial=SWXG, Contact_ShowUserName=true, Contact_BrandIconURL=,
171 | // Contact_Source_FMessage=17, source_from_user_name=wxid_lnt4ahvg2esr22, Contact_KSnsIFlag=0, Contact_Signature=,
172 | // Contact_Province=, Contact_FMessageCard=true, User_From_Fmessage=false, Contact_VUser_Info=, source_from_nick_name=林,
173 | // Contact_City=, Contact_Nick=莎雯[西瓜],
174 | // Contact_User=v1_3030c5f2180425b41b787251deae1f25f4c3b9135b75109c44248cd1f245241ff77aedf1ef2502d629fd7eadaa543a71@stranger,
175 | // Contact_VUser_Info_Flag=0, Contact_Sex=2, Contact_Uin=0, Contact_Alias=, Contact_Scene=17, Contact_RemarkName=null,
176 | // Contact_full_Mobile_MD5=null, Contact_QQNick=0,
177 | // AntispamTicket=v2_f04caa0fcae53fdb9ace3bb69bf1c94ed9ed7bb05f97563a12d2517e9f04115082978692df51d276b522ca1b06060be6@stranger,
178 | // Contact_NeedShowChangeSnsPreButton=false}]
179 |
180 | String s3 = "adb shell am start -n com.tencent.mm/com.tencent.mm.plugin.profile.ui.ContactInfoUI "+
181 | // "--ez Contact_ShowUserName true "+ // 前面的全为false,这种模式为true
182 | // "--es source_from_user_name \"wxid_lnt4ahvg2esr22\" "+ // 推荐人的微信id
183 | // "--es source_from_nick_name \"林\" "+ // 推荐人的昵称
184 | // "--es Contact_Nick \"莎雯[西瓜]\" "+
185 | // // v1 值,被推荐人的v1 值。只给这个就可以跳到加人界面了
186 | "--es Contact_User \"v1_3030c5f2180425b41b787251deae1f25f4c3b9135b75109c44248cd1f245241ff77aedf1ef2502d629fd7eadaa543a71@stranger\" "+
187 | // 新的字段。v2值
188 | // "--es AntispamTicket \"v2_f04caa0fcae53fdb9ace3bb69bf1c94ed9ed7bb05f97563a12d2517e9f04115082978692df51d276b522ca1b06060be6@stranger\" "+
189 | "--ei Contact_Scene 3 " + // 微信号搜索的为3,手机号搜索为15,群的方式是14,通讯录是13,名片为17,qq号是12
190 | // "--ei Contact_Sex 2 " + // 性别,1为男,2为女,0为未设置
191 | // "--ez Contact_NeedShowChangeSnsPreButton false " + // 都是false,可以去掉
192 | "";
193 | // Runtime.getRuntime().exec(s3);
194 |
195 |
196 | // 扫描
197 | // I/set ( 1517): bundle = Bundle[{Contact_NeedShowChangeRemarkButton=false,
198 | // Contact_QuanPin=wxidqxve6fsx4ery12, Contact_PyInitial=WXIDQXVE6FSX4ERY12,
199 | // Contact_RegionCode=CN_Guangdong_Guangzhou, Contact_BrandList=, Contact_KSnsBgId=0, Contact_IsLBSFriend=true, Contact_KWeiboNick=null,
201 | // Contact_KSnsBgUrl=null, Contact_KSnsIFlag=0, Contact_KWeibo_flag=0, Contact_Signature=宅若久时天然呆, 呆到深处自然萌,
202 | // Contact_BIZ_KF_WORKER_ID=null, Contact_VUser_Info=null, Contact_KHideExpose=true, Contact_Nick=雯雯,
203 | // Contact_User=v1_4b6ece89d367aed49ce765008cd11b297b3c3836bbc71c70ad71dc3e5da1b2359ee868dfe958ef76121ce676f53ab246@stranger,
204 | // Contact_VUser_Info_Flag=0, Contact_Sex=2, Contact_Alias=aa15596417033, Contact_Scene=30,
205 | // Contact_KWeibo=null, AntispamTicket=v2_973dea324a20f5da3d5de134c8c725d768ffb73ba1ec057d61c89f3140fb128e211dd1239af7f458ef7d20df144fcc76@stranger,
206 | // Contact_NeedShowChangeSnsPreButton=false}]
207 |
208 |
209 |
210 |
211 | //I/set (12773): bundle = Bundle[{Contact_NeedShowChangeRemarkButton=false, Contact_QuanPin=wxidm1hu9rqhn38b12,
212 | // Contact_PyInitial=WXIDM1HU9RQHN38B12, Contact_RegionCode=, Contact_BrandList=,
213 | // Contact_KSnsBgId=0, add_more_friend_search_scene=2, Contact_KWeiboNick=null, Contact_KSnsBgUrl=null, Contact_KSnsIFlag=0,
214 | // Contact_KWeibo_flag=0, Contact_Signature=null, Contact_BIZ_KF_WORKER_ID=null, Contact_VUser_Info=null, Contact_KHideExpose=true,
215 | // Contact_Nick=惠雯, Contact_User=v1_b0c79abc0b38218a5882503152a0d516530ef152a5378a0a91cf07de975ea354ec4cc8eb4dfb18fbaaca4085087bae45@stranger,
216 | // Contact_VUser_Info_Flag=0, Contact_Sex=2, Contact_Alias=huiwenasdfgh, Contact_Scene=3, Contact_KWeibo=null,
217 | // AntispamTicket=v2_22161d61454a505ba2978ef2b27609848a66406f2f671f1c7c84d1fb83e14cc073ea942588ac2ceabceaee13523870d9@stranger,
218 | // Contact_NeedShowChangeSnsPreButton=false}]
219 | String s4 = "adb shell am start -n com.tencent.mm/com.tencent.mm.plugin.profile.ui.ContactInfoUI "+
220 | "--ez Contact_NeedShowChangeRemarkButton false "+
221 | "--es Contact_QuanPin \"wxidm1hu9rqhn38b12\" "+
222 | "--es Contact_PyInitial \"WXIDM1HU9RQHN38B12\" "+
223 | // // v1 值,只给这个就可以跳到加人界面了,可以替换为微信id
224 |
225 | "--es Contact_User \"wxid_m1hu9rqhn38b12\" "+
226 | "--es Contact_Nick \"惠雯\" "+
227 |
228 | "--es Contact_BrandList \"\" "+
229 | // 新的字段。v2值
230 | "--ei Contact_VUser_Info_Flag 0 "+
231 | "--es Contact_Alias \"huiwenasdfgh\" "+
232 | "--es AntispamTicket \"v2_22161d61454a505ba2978ef2b27609848a66406f2f671f1c7c84d1fb83e14cc073ea942588ac2ceabceaee13523870d9@stranger\" "+
233 | "--ei Contact_Scene \"3\" " + // 微信号搜索的为3,手机号搜索为15,群的方式是14,通讯录是13,名片为17,qq号是12,扫一扫是30
234 | "--ei Contact_Sex 2 " + // 性别,1为男,2为女,0为未设置
235 | "--ez Contact_NeedShowChangeSnsPreButton false " + // 都是false,可以去掉
236 | "";
237 | // Runtime.getRuntime().exec(s4);
238 |
239 |
240 |
241 | // 11.15 下午
242 | // 手机号
243 | // I/set (18729): bundle = Bundle[{Contact_NeedShowChangeRemarkButton=false, Contact_QuanPin=wxidba2bjnsjlf5g22,
244 | // Contact_PyInitial=WXIDBA2BJNSJLF5G22, Contact_RegionCode=, Contact_BrandList=,
245 | // Contact_KSnsBgId=0, add_more_friend_search_scene=2, Contact_Search_Mobile=15708467068, Contact_KWeiboNick=null,
246 | // Contact_KSnsBgUrl=null, Contact_KSnsIFlag=0, Contact_KWeibo_flag=0, Contact_Signature=null, Contact_BIZ_KF_WORKER_ID=null,
247 | // Contact_VUser_Info=null, Contact_KHideExpose=true, Contact_Nick=尚恩i,
248 | // Contact_User=v1_84ed1072b6840b8ec31868f21275e3f169d024735145537c804332a0f66f2f8fbdac2ccdb2c0807feefa7810d57d54fb@stranger,
249 | // Contact_VUser_Info_Flag=0, Contact_Sex=0, Contact_Alias=sangeni, Contact_Scene=15, Contact_KWeibo=null,
250 | // AntispamTicket=v2_5762b5784df9d222e714eaea9853c3246f93f29d8186436ca33ad734c83ed2fcaee0b6caa20d31012a127c3e0cbc5bea@stranger,
251 | // Contact_NeedShowChangeSnsPreButton=false}]
252 | String s5 = "adb shell am start -n com.tencent.mm/com.tencent.mm.plugin.profile.ui.ContactInfoUI "+
253 | "--ez Contact_NeedShowChangeRemarkButton false "+
254 | // "--es Contact_QuanPin \"wxidba2bjnsjlf5g22\" "+
255 | // "--es Contact_PyInitial \"WXIDBA2BJNSJLF5G22\" "+
256 | "--es Contact_BrandList \"\" "+
257 | // "--es Contact_Nick \"尚恩i\" "+
258 | // v1 值,只给这个就可以跳到加人界面了,可以替换为微信id
259 | "--es Contact_User \"wxid_ba2bjnsjlf5g22\" "+
260 | // 新的字段。v2值
261 | "--ei Contact_VUser_Info_Flag 0 "+
262 | // "--es Contact_Alias \"huiwenasdfgh\" "+
263 | // "--es AntispamTicket \"v2_22161d61454a505ba2978ef2b27609848a66406f2f671f1c7c84d1fb83e14cc073ea942588ac2ceabceaee13523870d9@stranger\" "+
264 | "--ei Contact_Scene \"15\" " + // 微信号搜索的为3,手机号搜索为15,群的方式是14,通讯录是13,名片为17,qq号是12,扫一扫是30
265 | // "--ei Contact_Sex 2 " + // 性别,1为男,2为女,0为未设置
266 | "--ez Contact_NeedShowChangeSnsPreButton false " + // 都是false,可以去掉
267 | "";
268 | // Runtime.getRuntime().exec(s5);
269 |
270 |
271 |
272 | // 名片
273 | //I/set (18729): bundle = Bundle[{Contact_NeedShowChangeRemarkButton=false, Contact_QuanPin=丹[蛋糕]雯,
274 | // Contact_Mobile_MD5=null, Contact_PyInitial=DDGW, Contact_ShowUserName=true, Contact_BrandIconURL=,
275 | // Contact_Source_FMessage=17, source_from_user_name=wxid_lnt4ahvg2esr22, Contact_KSnsIFlag=0, Contact_Signature=,
276 | // Contact_Province=, Contact_FMessageCard=true, User_From_Fmessage=false, Contact_VUser_Info=, source_from_nick_name=林,
277 | // Contact_City=, Contact_Nick=丹[蛋糕]雯,
278 | // Contact_User=v1_d5609682e4fddebbba9fd0ad68aa8cfde2c7eb905852c2fb468c3741090b38438cedf125e694e373ce93a38bf2b4cc78@stranger,
279 | // Contact_VUser_Info_Flag=0, Contact_Sex=2, Contact_Uin=0, Contact_Alias=, Contact_Scene=17, Contact_RemarkName=null,
280 | // Contact_full_Mobile_MD5=null, Contact_QQNick=0,
281 | // AntispamTicket=v2_bf73e7b747042edb062a0ae26e9b362a87a2b8d18b465a04b96938da8c83c440eee5dee0c12471f877167062f3b9b3d2@stranger,
282 | // Contact_NeedShowChangeSnsPreButton=false}]
283 | // 手机号
284 | // I/set (18729): bundle = Bundle[{Contact_NeedShowChangeRemarkButton=false, Contact_QuanPin=wxidzmwujjbdt1vm12,
285 | // Contact_PyInitial=WXIDZMWUJJBDT1VM12, Contact_RegionCode=, Contact_BrandList=,
286 | // Contact_KSnsBgId=0, add_more_friend_search_scene=2, Contact_Search_Mobile=17182774674, Contact_KWeiboNick=null, Contact_KSnsBgUrl=null,
287 | // Contact_KSnsIFlag=0, Contact_KWeibo_flag=0, Contact_Signature=null, Contact_BIZ_KF_WORKER_ID=null, Contact_VUser_Info=null,
288 | // Contact_KHideExpose=true, Contact_Nick=丹[蛋糕]雯,
289 | // Contact_User=v1_d5609682e4fddebbba9fd0ad68aa8cfde2c7eb905852c2fb468c3741090b38438cedf125e694e373ce93a38bf2b4cc78@stranger,
290 | // Contact_VUser_Info_Flag=0, Contact_Sex=2, Contact_Alias=null, Contact_Scene=15, Contact_KWeibo=null,
291 | // AntispamTicket=v2_bf73e7b747042edb062a0ae26e9b362a9dfc362fabdc9d68bdc9bedcc4b236a13eca84951682b165b686cf613ba5ebb9@stranger,
292 | // Contact_NeedShowChangeSnsPreButton=false}]
293 | String s6 = "adb shell am start -n com.tencent.mm/com.tencent.mm.plugin.profile.ui.ContactInfoUI "+
294 | // "--ez Contact_NeedShowChangeRemarkButton false "+
295 | // "--es Contact_QuanPin \"丹[蛋糕]雯\" "+
296 | // "--es Contact_PyInitial \"DDGW\" "+
297 | // "--es source_from_user_name \"wxid_lnt4ahvg2esr22\" "+
298 | // "--es Contact_Nick \"尚恩i\" "+
299 | // v1 值,只给这个就可以跳到加人界面了,可以替换为微信id
300 | "--es Contact_User \"wxid_zmwujjbdt1vm12\" "+
301 | // 新的字段。v2值
302 | // "--ei Contact_VUser_Info_Flag 0 "+
303 | // "--es Contact_Alias \"huiwenasdfgh\" "+
304 | // "--es AntispamTicket \"v2_bf73e7b747042edb062a0ae26e9b362a87a2b8d18b465a04b96938da8c83c440eee5dee0c12471f877167062f3b9b3d2@stranger\" "+
305 | "--ei Contact_Scene \"15\" " + // 微信号搜索的为3,手机号搜索为15,群的方式是14,通讯录是13,名片为17,qq号是12,扫一扫是30
306 | // "--ei Contact_Sex 2 " + // 性别,1为男,2为女,0为未设置
307 | // "--ez Contact_NeedShowChangeSnsPreButton false " + // 都是false,可以去掉
308 | "";
309 | // Runtime.getRuntime().exec(s6);
310 |
311 |
312 |
313 | // 手机号
314 | // I/set (18729): bundle = Bundle[{Contact_NeedShowChangeRemarkButton=false, Contact_QuanPin=wxid0r3mea7v5wvc12,
315 | // Contact_PyInitial=WXID0R3MEA7V5WVC12, Contact_RegionCode=, Contact_BrandList=,
316 | // Contact_KSnsBgId=0, add_more_friend_search_scene=2, Contact_Search_Mobile=13535296697, Contact_KWeiboNick=null, Contact_KSnsBgUrl=null,
317 | // Contact_KSnsIFlag=0, Contact_KWeibo_flag=0, Contact_Signature=null, Contact_BIZ_KF_WORKER_ID=null, Contact_VUser_Info=null,
318 | // Contact_KHideExpose=true, Contact_Nick=玻璃雯,
319 | // Contact_User=v1_087eeb4bde77e18cc4595b35dd05f60a6c2c49259e34cd20eacccbbedb6a729723b4459bf8a67d1ace6daa85ffd24bf5@stranger,
320 | // Contact_VUser_Info_Flag=0, Contact_Sex=2, Contact_Alias=boliwenasd, Contact_Scene=15, Contact_KWeibo=null,
321 | // AntispamTicket=v2_a5a426a6f958ef0e74a2d516725af86bae5e37fc47d57813340af1208e8cfbd1cc195a0001d3223744484be3b7aeaa8c@stranger,
322 | // Contact_NeedShowChangeSnsPreButton=false}]
323 | String s7 = "adb shell am start -n com.tencent.mm/com.tencent.mm.plugin.profile.ui.ContactInfoUI "+
324 | "--ez Contact_NeedShowChangeRemarkButton false "+
325 | "--es Contact_QuanPin \"wxid0r3mea7v5wvc12\" "+
326 | "--es Contact_PyInitial \"WXID0R3MEA7V5WVC12\" "+
327 | "--es Contact_BrandList \"\" "+
328 | "--ez Contact_KHideExpose true "+
329 | "--ei add_more_friend_search_scene 2 "+
330 | "--es Contact_Nick \"玻璃雯\" "+
331 | // v1 值,只给这个就可以跳到加人界面了,可以替换为微信id
332 | "--es Contact_User \"wxid_0r3mea7v5wvc12\" "+
333 | "--es Contact_Alias \"boliwenasd\" "+
334 | "--ei Contact_VUser_Info_Flag 0 "+
335 | "--es AntispamTicket \"v2_a5a426a6f958ef0e74a2d516725af86bae5e37fc47d57813340af1208e8cfbd1cc195a0001d3223744484be3b7aeaa8c@stranger\" "+
336 | "--ei Contact_Scene \"15\" " + // 微信号搜索的为3,手机号搜索为15,群的方式是14,通讯录是13,名片为17,qq号是12,扫一扫是30
337 | "--ei Contact_Sex 2 " + // 性别,1为男,2为女,0为未设置
338 | "--ez Contact_NeedShowChangeSnsPreButton false " + // 都是false,可以去掉
339 | "";
340 | // Runtime.getRuntime().exec(s7);
341 |
342 |
343 |
344 | // 11.16
345 | //I/set ( 1193): bundle = Bundle[{Contact_NeedShowChangeRemarkButton=false, Contact_QuanPin=wxidy2o2iapftivz22,
346 | // Contact_PyInitial=WXIDY2O2IAPFTIVZ22, Contact_RegionCode=, Contact_BrandList=,
347 | // Contact_KSnsBgId=0, add_more_friend_search_scene=2, Contact_Search_Mobile=18483660024, Contact_KWeiboNick=null, Contact_KSnsBgUrl=null,
348 | // Contact_KSnsIFlag=0, Contact_KWeibo_flag=0, Contact_Signature=null, Contact_BIZ_KF_WORKER_ID=null, Contact_VUser_Info=null,
349 | // Contact_KHideExpose=true, Contact_Nick=飘雯,
350 | // Contact_User=v1_864c3055b0c6f481aeded517dfccd61f392856e1bcea6acb41e917f82fa76af201d9b531f537091774462585a1feaab0@stranger,
351 | // Contact_VUser_Info_Flag=0, Contact_Sex=0, Contact_Alias=swm18483660024, Contact_Scene=15, Contact_KWeibo=null,
352 | // AntispamTicket=v2_e2727d506e1f4afe6083dddfd630ea80237ecb07cb11b62291400bb0401328386ca778a34ec2a0ab88e7298fedcfb945@stranger,
353 | // Contact_NeedShowChangeSnsPreButton=false}]
354 | String s8 = "adb shell am start -n com.tencent.mm/com.tencent.mm.plugin.profile.ui.ContactInfoUI "+
355 | "--ez Contact_NeedShowChangeRemarkButton false "+
356 | "--es Contact_QuanPin \"nanguaiiasd\" "+
357 | "--es Contact_PyInitial \"NANGUAIIASD\" "+
358 | "--es Contact_BrandList \"\" "+
359 | "--ei Contact_KSnsBgId 0 "+
360 | // "--ei add_more_friend_search_scene 2 " +
361 | // "--es Contact_Search_Mobile \"13553324534\" "+
362 | "--es Contact_KWeiboNick \"null\" "+
363 | "--es Contact_KSnsBgUrl \"null\" "+
364 | "--ei Contact_KSnsIFlag 0 "+
365 | "--ei Contact_KWeibo_flag 0 "+
366 | "--es Contact_Signature \"null\" "+
367 | "--es Contact_BIZ_KF_WORKER_ID \"null\" "+
368 | "--es Contact_VUser_Info \"null\" "+
369 | "--ez Contact_KHideExpose true "+
370 | // "--es Contact_Nick \"飘雯\" "+
371 | // v1 值,只给这个就可以跳到加人界面了,可以替换为微信id
372 | "--es Contact_User \"nanguaiiasd\" "+
373 | // "--ei Contact_VUser_Info_Flag 0 "+ ............
374 | "--ei Contact_Sex 0 "+
375 | // "--es Contact_Alias \"s6ffdfsw23\" "+
376 | "--ei Contact_Scene \"15\" " + // 微信号搜索的为3,手机号搜索为15,群的方式是14,通讯录是13,名片为17,qq号是12,扫一扫是30
377 | "--es Contact_KWeibo \"null\" "+
378 | // "--es AntispamTicket \"v2_e2727d506e1f4afe6083dddfd630ea80237ecb07cb11b62291400bb0401328386ca778a34ec2a0ab88e7298fedcfb945@stranger\" "+
379 | "--ez Contact_NeedShowChangeSnsPreButton false "+
380 | "";
381 | // Runtime.getRuntime().exec(s8);
382 |
383 | //I/set ( 1193): bundle = Bundle[{Contact_NeedShowChangeRemarkButton=false, Contact_QuanPin=wxidlnt4ahvg2esr22,
384 | // Contact_PyInitial=WXIDLNT4AHVG2ESR22, Contact_RegionCode=CN_Guangdong_Guangzhou, Contact_BrandList=,
385 | // Contact_KSnsBgId=0, add_more_friend_search_scene=2, Contact_Search_Mobile=18814143556, Contact_KWeiboNick=null, Contact_KSnsBgUrl=null,
386 | // Contact_KSnsIFlag=0, Contact_KWeibo_flag=0, Contact_Signature=多的是,你不知道的事, Contact_BIZ_KF_WORKER_ID=null, Contact_VUser_Info=null,
387 | // Contact_KHideExpose=true, Contact_Nick=林, Contact_User=wxid_lnt4ahvg2esr22, Contact_VUser_Info_Flag=0, Contact_Sex=1,
388 | // Contact_Alias=q961513094, Contact_Scene=15, Contact_KWeibo=null,
389 | // AntispamTicket=v2_e574085f9339eb7cdac3e14cac25a4bcbb1f186311910df6c32be54b4ebe4c5b3caafa2fcee01e96195b5e1c39f1dd8f@stranger,
390 | // Contact_NeedShowChangeSnsPreButton=false}]
391 | String s9 = "adb shell am start -n com.tencent.mm/com.tencent.mm.plugin.profile.ui.ContactInfoUI "+
392 | "--ez Contact_NeedShowChangeRemarkButton false "+
393 | "--es Contact_QuanPin \"wxidlnt4ahvg2esr22\" "+
394 | "--es Contact_PyInitial \"WXIDLNT4AHVG2ESR22\" "+
395 | "--ei Contact_KSnsBgId 0 "+
396 | "--ei add_more_friend_search_scene 2 " +
397 | // "--es Contact_Search_Mobile \"13553324534\" "+
398 | "--es Contact_KWeiboNick \"null\" "+
399 | "--es Contact_KSnsBgUrl \"null\" "+
400 | "--ei Contact_KSnsIFlag 0 "+
401 | "--ei Contact_KWeibo_flag 0 "+
402 | "--es Contact_Signature \"null\" "+
403 | "--es Contact_BIZ_KF_WORKER_ID \"null\" "+
404 | "--es Contact_VUser_Info \"null\" "+
405 | "--ez Contact_KHideExpose true "+
406 | // "--es Contact_Nick \"飘雯\" "+
407 | // v1 值,只给这个就可以跳到加人界面了,可以替换为微信id
408 | "--es Contact_User \"wxid_lnt4ahvg2esr22\" "+
409 | "--ei Contact_VUser_Info_Flag 0 " +// ............
410 |
411 | // "--ei Contact_Sex 0 "+
412 | // "--es Contact_Alias \"s6ffdfsw23\" "+
413 | "--ei Contact_Scene 15 "+ // 微信号搜索的为3,手机号搜索为15,群的方式是14,通讯录是13,名片为17,qq号是12,扫一扫是30
414 | "--es Contact_KWeibo \"null\" "+
415 | //// "--es AntispamTicket \"v2_e2727d506e1f4afe6083dddfd630ea80237ecb07cb11b62291400bb0401328386ca778a34ec2a0ab88e7298fedcfb945@stranger\" "+
416 | "--ez Contact_NeedShowChangeSnsPreButton false "+
417 | "";
418 | // Runtime.getRuntime().exec(s9);
419 |
420 |
421 | //I/set ( 1517): bundle = Bundle[{Contact_NeedShowChangeRemarkButton=false, Contact_QuanPin=wxidqxve6fsx4ery12,
422 | // Contact_PyInitial=WXIDQXVE6FSX4ERY12, Contact_RegionCode=CN_Guangdong_Guangzhou,
423 | // Contact_BrandList=, Contact_KSnsBgId=0, Contact_IsLBSFriend=true,
424 | // Contact_KWeiboNick=null, Contact_KSnsBgUrl=null, Contact_KSnsIFlag=0, Contact_KWeibo_flag=0,
425 | // Contact_Signature=宅若久时天然呆, 呆到深处自然萌, Contact_BIZ_KF_WORKER_ID=null, Contact_VUser_Info=null,
426 | // Contact_KHideExpose=true, Contact_Nick=雯雯,
427 | // Contact_User=v1_4b6ece89d367aed49ce765008cd11b297b3c3836bbc71c70ad71dc3e5da1b2359ee868dfe958ef76121ce676f53ab246@stranger,
428 | // Contact_VUser_Info_Flag=0, Contact_Sex=2, Contact_Alias=aa15596417033, Contact_Scene=30, Contact_KWeibo=null,
429 | // AntispamTicket=v2_973dea324a20f5da3d5de134c8c725d768ffb73ba1ec057d61c89f3140fb128e211dd1239af7f458ef7d20df144fcc76@stranger,
430 | // Contact_NeedShowChangeSnsPreButton=false}]
431 | String test = "adb shell am start -n com.tencent.mm/com.tencent.mm.plugin.profile.ui.ContactInfoUI "+
432 | "--ez Contact_NeedShowChangeRemarkButton false "+
433 | "--es Contact_QuanPin \"wxidlnt4ahvg2esr22\" "+
434 | "--es Contact_PyInitial \"WXIDLNT4AHVG2ESR22\" "+
435 | "--es Contact_BrandList \"\" "+
436 | "--ei Contact_KSnsBgId 0 "+
437 | "--ez Contact_IsLBSFriend true "+
438 | "--es Contact_KWeiboNick \"null\" "+
439 | "--es Contact_KSnsBgUrl \"null\" "+
440 | "--ei Contact_KSnsIFlag 0 "+
441 | "--ei Contact_KWeibo_flag 0 "+
442 | "--es Contact_Signature \"null\" "+
443 | "--es Contact_BIZ_KF_WORKER_ID \"null\" "+
444 | "--es Contact_VUser_Info \"null\" "+
445 | "--ez Contact_KHideExpose true "+
446 | "--es Contact_User \"wxid_lnt4ahvg2esr22\" "+
447 | "--ei Contact_VUser_Info_Flag 0 "+
448 | "--ei Contact_Scene 30 "+
449 | "--es Contact_KWeibo \"null\" "+
450 | "--ez Contact_NeedShowChangeSnsPreButton false "+
451 | "";
452 | Runtime.getRuntime().exec(test);
453 |
454 | } catch (IOException e) {
455 | e.printStackTrace();
456 | }
457 |
458 |
459 | }
460 | }
461 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/admin/wxaddfrienddemo/AddActivity.java:
--------------------------------------------------------------------------------
1 | package com.example.admin.wxaddfrienddemo;
2 |
3 | import android.accessibilityservice.AccessibilityService;
4 | import android.annotation.SuppressLint;
5 | import android.annotation.TargetApi;
6 | import android.content.ClipData;
7 | import android.content.ClipboardManager;
8 | import android.content.ComponentName;
9 | import android.content.ContentResolver;
10 | import android.content.ContentUris;
11 | import android.content.ContentValues;
12 | import android.content.Context;
13 | import android.content.Intent;
14 | import android.database.Cursor;
15 | import android.graphics.Rect;
16 | import android.net.Uri;
17 | import android.os.Build;
18 | import android.os.Bundle;
19 | import android.os.Environment;
20 | import android.os.Handler;
21 | import android.os.Looper;
22 | import android.os.Message;
23 | import android.os.SystemClock;
24 | import android.provider.DocumentsContract;
25 | import android.provider.MediaStore;
26 | import android.support.annotation.Nullable;
27 | import android.support.annotation.RequiresApi;
28 | import android.support.v7.app.AppCompatActivity;
29 | import android.text.TextUtils;
30 | import android.util.Log;
31 | import android.view.View;
32 | import android.view.accessibility.AccessibilityEvent;
33 | import android.view.accessibility.AccessibilityNodeInfo;
34 | import android.widget.Button;
35 | import android.widget.EditText;
36 | import android.widget.TextView;
37 | import android.widget.Toast;
38 |
39 | import java.io.BufferedReader;
40 | import java.io.File;
41 | import java.io.FileNotFoundException;
42 | import java.io.FileOutputStream;
43 | import java.io.FileReader;
44 | import java.io.IOException;
45 | import java.text.SimpleDateFormat;
46 | import java.util.ArrayList;
47 | import java.util.Date;
48 | import java.util.List;
49 |
50 | import static android.widget.Toast.LENGTH_SHORT;
51 | import static com.example.admin.wxaddfrienddemo.MyService.getContext;
52 |
53 | /**
54 | * Created by admin on 2017/11/8.
55 | */
56 |
57 | public class AddActivity extends AppCompatActivity {
58 | private static final String TAG = "xyz";
59 |
60 | Button btnSelect, btnStart;
61 | EditText etScene;
62 | EditText etHello;
63 |
64 | TextView tvFilePath;
65 | private static final int SELECT_CODE = 1;
66 |
67 | private String filePath;
68 |
69 | private List list = new ArrayList<>();
70 |
71 | String hello;
72 | int scene;
73 |
74 | private AccessibilityService mService;
75 |
76 | EditText etTime;
77 |
78 | long time;
79 |
80 | TextView tvSum;
81 |
82 | int sum, successNum, failNum , num;
83 |
84 | Handler handler;
85 |
86 | String wxid;
87 |
88 | StringBuilder saveString = new StringBuilder();
89 |
90 | EditText etBundleScene;
91 |
92 | int bundleScene;
93 |
94 | Button btnWxid;
95 |
96 | EditText etTuiWxid;
97 |
98 | String tuiWxid = "";
99 |
100 | EditText etTuiNickName;
101 |
102 | String tuiNickName = "";
103 |
104 | @Override
105 | protected void onCreate(@Nullable Bundle savedInstanceState) {
106 | super.onCreate(savedInstanceState);
107 | setContentView(R.layout.activity_add);
108 |
109 |
110 | int mode = getIntent().getIntExtra("mode",-1);
111 |
112 | if (mode == 1){
113 | findViewById(R.id.wxid).setVisibility(View.INVISIBLE);
114 | findViewById(R.id.tuiwxid).setVisibility(View.INVISIBLE);
115 | findViewById(R.id.tuinick).setVisibility(View.INVISIBLE);
116 | }else if (mode ==2){
117 | findViewById(R.id.bundle).setVisibility(View.INVISIBLE);
118 | findViewById(R.id.start).setVisibility(View.INVISIBLE);
119 | }
120 |
121 | btnSelect = findViewById(R.id.select);
122 | etScene = findViewById(R.id.et_scene);
123 | etHello = findViewById(R.id.et_hello);
124 | tvFilePath = findViewById(R.id.tv_hint);
125 | btnStart = findViewById(R.id.start);
126 | etTime = findViewById(R.id.time);
127 | tvSum = findViewById(R.id.sum);
128 | etBundleScene = findViewById(R.id.bundle);
129 | btnWxid = findViewById(R.id.wxid);
130 |
131 | etTuiWxid = findViewById(R.id.tuiwxid);
132 |
133 | etTuiNickName = findViewById(R.id.tuinick);
134 |
135 | handler = new Handler(){ // 更新已添加的总数
136 | @Override
137 | public void handleMessage(Message msg) {
138 | switch (msg.what){
139 | case 666:
140 | tvSum.setText(""+sum);
141 | break;
142 | case 111:
143 | Log.i("xyz","接受到111");
144 | // 在主线程中弹吐司,虽然子线程可以吐司,但是有时显示不出来,被微信自己的覆盖了
145 | Toast.makeText(getApplicationContext(),"尝试添加"+wxid,Toast.LENGTH_SHORT).show();
146 | break;
147 | case 222:
148 | String s = (String) msg.obj;
149 | Toast.makeText(getApplicationContext(),s,Toast.LENGTH_SHORT).show();
150 | break;
151 | }
152 | }
153 | };
154 |
155 | btnSelect.setOnClickListener(new View.OnClickListener() {
156 | @Override
157 | public void onClick(View v) {
158 | selectFile();
159 | }
160 | });
161 |
162 | btnStart.setOnClickListener(new View.OnClickListener() {
163 | @Override
164 | public void onClick(View v) {
165 |
166 | new Thread(new Runnable() { // 开启子线程是为了线程间的通信和同步操作
167 |
168 | @Override
169 | public void run() {
170 | Looper.prepare();
171 | startJump();
172 | Looper.loop();
173 | }
174 | }).start();
175 |
176 | }
177 | });
178 |
179 | btnWxid.setOnClickListener(new View.OnClickListener() {
180 | @Override
181 | public void onClick(View v) {
182 |
183 | new Thread(new Runnable() {
184 | @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
185 | @Override
186 | public void run() {
187 | Looper.prepare();
188 | startJumpByWxid();
189 | Looper.loop();
190 | }
191 | }).start();
192 | }
193 | });
194 | }
195 |
196 | @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
197 | private void startJumpByWxid() {
198 |
199 |
200 | if (TextUtils.isEmpty(etScene.getText()) || TextUtils.isEmpty(etHello.getText()) ) {
201 | Toast.makeText(AddActivity.this, "场景、验证信息,推荐人微信id和昵称不能为空", LENGTH_SHORT).show();
202 | }else {
203 |
204 | if (!TextUtils.isEmpty(etTuiWxid.getText()) ){
205 | tuiWxid = etTuiWxid.getText().toString().trim();
206 | }
207 | if (!TextUtils.isEmpty(etTuiNickName.getText())){
208 | tuiNickName = etTuiNickName.getText().toString().trim();
209 | }
210 |
211 | scene = Integer.parseInt(etScene.getText().toString().trim());
212 | hello = etHello.getText().toString().trim();
213 |
214 | if (TextUtils.isEmpty(etTime.getText())){
215 | time = 10 * 1000;
216 | }else {
217 | time = Long.parseLong(etTime.getText().toString().trim()) * 1000;
218 | }
219 | num = list.size();
220 | //先跳到主界面
221 | startWechat();
222 | if (!startFinish()) {
223 | Log.i("xyz","微信启动失败");
224 | }else {
225 |
226 | // SystemClock.sleep(10000);
227 | for (String info : list) {
228 | wxid = info;
229 | setCnt(0);
230 |
231 |
232 |
233 | sendMyBroadcast(info, scene,tuiWxid,tuiNickName);
234 |
235 |
236 | // // 将数据存储进sp里面
237 | // putDataToSp(info,scene);
238 |
239 |
240 | // sleepRandom();
241 | // // 获取微信context
242 | // Context wxContext = Module.applicationContext;
243 | // // 跳转到验证界面
244 | // AddUtils.addFriendByWxid(wxContext,info,scene);
245 | // 线程睡眠,让出cpu
246 | // waitfor(20000);
247 | // // 是否跳转成功,点击添加到通讯录按钮
248 | // if(getCnt() >= 1){
249 | // setCnt(0);
250 | // if (!hasAddBtn()){ // 没有添加按钮,说明已经是好友了,直接返回
251 | // Log.i("xyz","没有添加按钮,说明已经是好友了");
252 | // finishAndReturn();
253 | // }
254 |
255 | // 点击添加按钮
256 | // clickAddButton();
257 | // 显示尝试添加的吐司
258 | // showToast();
259 | // sendToUI();
260 | // try {
261 | // // 输出log到本地
262 | // writeToLocal();
263 | // } catch (IOException e) {
264 | // e.printStackTrace();
265 | // }
266 | // showTextToast("尝试添加 "+wxid);
267 | // 是否跳转成功,填入验证信息,点击发送按钮
268 | waitfor(20000);
269 | if (getCnt() >= 1) {
270 | setCnt(0);
271 | sendToUI();
272 | try {
273 | // 输出log到本地
274 | writeToLocal();
275 | } catch (IOException e) {
276 | e.printStackTrace();
277 | }
278 | // 如果对方设置了不能通过某场景添加ta
279 | if (cannotAddBySomeScene()) {
280 | // 点击确认按钮
281 | clickConfirm();
282 | sleepRandom();
283 | // 接着点击返回
284 | finishAndReturn();
285 | }
286 | // 判断是否需要验证
287 | if (isNeedVerify()) {
288 | // 设置验证信息并发送
289 | sendMessage();
290 | // 更新添加个数
291 | refrensh();
292 | waitfor(20000);
293 | if (getCnt() >= 1) {
294 | // // 是否发送成功,点击左上角返回
295 | // finishAndReturn();
296 | SystemClock.sleep(time);
297 | }
298 | } else {
299 | finishAndReturn();
300 | SystemClock.sleep(time);
301 | }
302 | }
303 | // }
304 | }
305 | }
306 | }
307 | }
308 |
309 | private boolean startFinish() {
310 | // 获取到添加按钮
311 | List list = null;
312 | long aa = System.currentTimeMillis();
313 | do {
314 | AccessibilityNodeInfo root = getRoot();
315 | long bb = System.currentTimeMillis();
316 | if (bb - aa >= 30000){
317 | Log.e("xyz","sss");
318 | return false;
319 |
320 | }
321 |
322 | if (root!=null) {
323 | list = root.findAccessibilityNodeInfosByText("微信");
324 | }
325 | SystemClock.sleep(500);
326 | }while (list == null || list.size() == 0);
327 |
328 | if (list!=null && list.size() > 0){
329 | Log.i("xyz","微信启动完成");
330 | return true;
331 | }else {
332 | return false;
333 | }
334 | }
335 |
336 | private void sendMyBroadcast(String info, int scene,String tuiWxid,String tuiNickName) {
337 | Intent intent = new Intent("com.example.admin.wxaddfrienddemo.broadcast");
338 | Bundle bundle = new Bundle();
339 | bundle.putString("wxid",info);
340 | bundle.putInt("scene",scene);
341 | bundle.putString("tuiWxid",tuiWxid);
342 | bundle.putString("tuiNickName",tuiNickName);
343 | intent.putExtras(bundle);
344 | sendBroadcast(intent);
345 | Log.i("xyz","activity 发送广播");
346 | }
347 |
348 |
349 |
350 | private void startWechat() {
351 | Intent intent = new Intent();
352 | ComponentName cmp=new ComponentName("com.tencent.mm","com.tencent.mm.ui.LauncherUI");
353 | intent.setAction(Intent.ACTION_MAIN);
354 | intent.addCategory(Intent.CATEGORY_LAUNCHER);
355 | intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
356 | intent.setComponent(cmp);
357 | startActivity(intent);
358 | }
359 |
360 |
361 | @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
362 | private void startJump() {
363 | if (TextUtils.isEmpty(etScene.getText()) || TextUtils.isEmpty(etHello.getText()) || TextUtils.isEmpty(etBundleScene.getText())) {
364 | Toast.makeText(AddActivity.this, "场景和验证信息不能为空", LENGTH_SHORT).show();
365 | }else {
366 | scene = Integer.parseInt(etScene.getText().toString().trim());
367 | hello = etHello.getText().toString().trim();
368 | bundleScene = Integer.parseInt(etBundleScene.getText().toString().trim());
369 | if (bundleScene > 3 || bundleScene < 1 ){
370 | Message message = new Message();
371 | message.what = 222;
372 | message.obj = "请选择正确的bundle方式";
373 | handler.sendMessage(message);
374 | }
375 | if ((bundleScene == 2 || bundleScene == 3)&& (scene !=14 && scene !=15 && scene !=30) ){
376 | Message message = new Message();
377 | message.what = 222;
378 | message.obj = "此种bundle模式下的添加场景只能为14、15或30";
379 | handler.sendMessage(message);
380 | }
381 |
382 | if (TextUtils.isEmpty(etTime.getText())){
383 | time = 10 * 1000;
384 | }else {
385 | time = Long.parseLong(etTime.getText().toString().trim()) * 1000;
386 | }
387 | num = list.size();
388 | for (String info : list) {
389 | wxid = info;
390 | setCnt(0);
391 | sleepRandom();
392 | // 跳转到加人界面
393 | AddUtils.addFriend(info, scene, bundleScene);
394 | //showToast();
395 | // 线程睡眠,让出cpu
396 | waitfor(20000);
397 | // 是否跳转成功,点击添加到通讯录按钮
398 | if(getCnt() >= 1){
399 | setCnt(0);
400 | if (!hasAddBtn()){ // 没有添加按钮,说明已经是好友了,直接返回
401 | Log.i("xyz","没有添加按钮,说明已经是好友了");
402 | finishAndReturn();
403 | }
404 |
405 | // 点击添加按钮
406 | clickAddButton();
407 | // 显示尝试添加的吐司
408 | // showToast();
409 | sendToUI();
410 | try {
411 | // 输出log到本地
412 | writeToLocal();
413 | } catch (IOException e) {
414 | e.printStackTrace();
415 | }
416 | // showTextToast("尝试添加 "+wxid);
417 | // 是否跳转成功,填入验证信息,点击发送按钮
418 | waitfor(20000);
419 | if (getCnt()>= 1){
420 | setCnt(0);
421 | // 如果对方设置了不能通过某场景添加ta
422 | if (cannotAddBySomeScene()){
423 | // 点击确认按钮
424 | clickConfirm();
425 | sleepRandom();
426 | // 接着点击返回
427 | finishAndReturn();
428 | }
429 | // 判断是否需要验证
430 | if (isNeedVerify()){
431 | // 设置验证信息并发送
432 | sendMessage();
433 | // 更新添加个数
434 | refrensh();
435 | waitfor(20000);
436 | if (getCnt()>=1){
437 | // 是否发送成功,点击左上角返回
438 | finishAndReturn();
439 | SystemClock.sleep(time);
440 | }
441 | }else {
442 | finishAndReturn();
443 | SystemClock.sleep(time);
444 | }
445 | }
446 | }
447 | }
448 | }
449 | }
450 |
451 | private void sleepRandom(){
452 |
453 | double ran = Math.random();
454 |
455 | long lon = (long) (1500 + ran *1000);
456 |
457 | SystemClock.sleep(lon);
458 |
459 | }
460 |
461 |
462 |
463 | @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
464 |
465 | private void clickConfirm() {
466 |
467 | Log.i("xyz","进入点击确认按钮");
468 |
469 | AccessibilityNodeInfo root = getRoot();
470 |
471 | List list ;
472 |
473 | do {
474 |
475 | list = root.findAccessibilityNodeInfosByText("确定");
476 |
477 | }while (list == null);
478 |
479 | if (list.size() > 0){
480 |
481 | Log.i("xyz","找到确定按钮");
482 |
483 | for (AccessibilityNodeInfo info : list){
484 |
485 | Log.i("xyz","info - "+info);
486 |
487 | // 点击按钮
488 |
489 | info.performAction(AccessibilityNodeInfo.ACTION_CLICK);
490 |
491 | break;
492 |
493 | }
494 |
495 | }
496 |
497 | }
498 |
499 |
500 |
501 |
502 |
503 | @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
504 |
505 | private boolean cannotAddBySomeScene() { // 找到界面中是否有确定按钮
506 |
507 | Log.i("xyz","进入查找确认按钮");
508 |
509 | AccessibilityNodeInfo root = getRoot();
510 |
511 | // List list ;
512 |
513 | // long s = System.currentTimeMillis();
514 |
515 | // do {
516 |
517 | // long s2 = System.currentTimeMillis();
518 |
519 | // if (s2 - s >=5000){
520 |
521 | // return false;
522 |
523 | // }
524 |
525 | // list = root.findAccessibilityNodeInfosByText("确定");
526 |
527 | // SystemClock.sleep(200);
528 |
529 | // }while (list == null);
530 |
531 |
532 |
533 | List list = root.findAccessibilityNodeInfosByText("确定");
534 |
535 | if (list.size() > 0){
536 |
537 | Log.i("xyz","找到确定按钮");
538 |
539 | return true;
540 |
541 | }else {
542 |
543 | Log.i("xyz","找不到确认按钮");
544 |
545 | return false;
546 |
547 | }
548 |
549 | }
550 |
551 |
552 |
553 |
554 |
555 |
556 |
557 | private void sendToUI() {
558 |
559 | Message message = new Message();
560 |
561 | message.what = 111;
562 |
563 | Log.i("xyz","发送111给主线程");
564 |
565 | handler.sendMessage(message);
566 |
567 | }
568 |
569 |
570 |
571 | private void writeToLocal() throws IOException {
572 |
573 | // 路径名
574 |
575 | File file = new File("/sdcard/tmp/");
576 |
577 | if (!file.exists()){
578 |
579 | file.mkdirs(); // 创建目录
580 |
581 | }
582 |
583 | // 具体文件名 , 路径 + 文件
584 |
585 | File localFile = new File(file,"log.txt");
586 |
587 | if (!localFile.exists()){
588 |
589 | localFile.createNewFile();
590 |
591 | }
592 |
593 |
594 |
595 | SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss ");
596 |
597 | Date curDate = new Date(System.currentTimeMillis());
598 |
599 | String date = format.format(curDate);
600 |
601 | saveString.append(date +": 尝试添加 "+wxid+"\n");
602 |
603 | Log.i("xyz",saveString.toString());
604 |
605 |
606 |
607 | FileOutputStream fos = new FileOutputStream(localFile,false); // 这里的第二个参数代表追加还是覆盖,true为追加,false为覆盖
608 |
609 | fos.write(saveString.toString().getBytes());
610 |
611 | fos.close();
612 |
613 | }
614 |
615 |
616 |
617 |
618 |
619 | //设置Toast对象
620 |
621 | private Toast mToast = null;
622 |
623 | private void showTextToast(String msg) {
624 |
625 | //判断队列中是否包含已经显示的Toast
626 |
627 | if (mToast == null) {
628 |
629 | mToast = Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_LONG);
630 |
631 | }else{
632 |
633 | mToast.setText(msg);
634 |
635 | }
636 |
637 | mToast.show();
638 |
639 | }
640 |
641 |
642 |
643 | private boolean hasAddBtn() {
644 |
645 | AccessibilityNodeInfo root = getRoot();
646 |
647 | // 获取到添加按钮
648 |
649 | // List list = root.findAccessibilityNodeInfosByViewId("com.tencent.mm:id/ahp");
650 |
651 | List list;
652 |
653 | long aa = System.currentTimeMillis();
654 |
655 | do {
656 |
657 | long bb = System.currentTimeMillis();
658 |
659 | if (bb - aa >= 5000){
660 |
661 | Log.i("xyz","规定时间内找不到添加按钮,直接返回false");
662 |
663 | return false;
664 |
665 | }
666 |
667 | list = root.findAccessibilityNodeInfosByText("添加");
668 |
669 | SystemClock.sleep(200);
670 |
671 | }while (list == null);
672 |
673 |
674 |
675 | if (list.size() > 0){
676 |
677 | Log.i("xyz","找到添加按钮");
678 |
679 | return true;
680 |
681 | }else {
682 |
683 | return false;
684 |
685 | }
686 |
687 |
688 |
689 |
690 |
691 | }
692 |
693 |
694 |
695 | private AccessibilityNodeInfo findReturn(AccessibilityNodeInfo root) {
696 |
697 | if (root == null){
698 |
699 | return null;
700 |
701 | }
702 |
703 | AccessibilityNodeInfo res = null;
704 |
705 | for (int i = 0; i < root.getChildCount(); i++) {
706 |
707 | AccessibilityNodeInfo nodeInfo = root.getChild(i);
708 |
709 | if (nodeInfo.getClassName().equals("android.widget.ImageView")) {
710 |
711 | Log.i("xyz","获取到ImageView");
712 |
713 | Log.i("xyz","nodeInfo = "+nodeInfo);
714 |
715 | Rect rect = new Rect();
716 |
717 | nodeInfo.getBoundsInScreen(rect);
718 |
719 | int x = rect.centerX();
720 |
721 | int y = rect.centerY();
722 |
723 | if (0 < x && x < 35 && 15 < y && y < 50) {
724 |
725 | res = nodeInfo;
726 |
727 | Log.i("xyz","找到返回键");
728 |
729 | break; // 这里必须有这个break,表示找到返回键之后就会打破循环,将找到的值返回
730 |
731 | }
732 |
733 | }else {
734 |
735 | res = findReturn(nodeInfo);
736 |
737 | if (res != null){
738 |
739 | return res;
740 |
741 | }
742 |
743 | }
744 |
745 | }
746 |
747 | return res;
748 |
749 | }
750 |
751 |
752 |
753 | private void refrensh() {
754 |
755 | Message message = new Message();
756 |
757 | message.what = 666;
758 |
759 | sum++;
760 |
761 | Log.i("xyz","sum = "+sum);
762 |
763 | handler.sendMessage(message);
764 |
765 |
766 |
767 | // 是否添加成功
768 |
769 | // if (isNeedVerify()){
770 |
771 | // Log.i("xyz","添加失败");
772 |
773 | // failNum++;
774 |
775 | // Log.i("xyz","添加"+ wxid +"失败,当前总个数"+sum+"/"+num+"其中成功个数为: "+successNum+
776 |
777 | // " 失败个数为: "+failNum);
778 |
779 | // Toast.makeText(getApplication(),"添加"+ wxid +"失败,当前总个数"+sum+"/"+num+"其中成功个数为: "+successNum+
780 |
781 | // " 失败个数为: "+failNum,Toast.LENGTH_LONG).show();
782 |
783 | // }else {
784 |
785 | // Log.i("xyz","添加成功");
786 |
787 | // successNum++;
788 |
789 | // Log.i("xyz","添加"+ wxid +"成功,当前总个数"+sum+"/"+num+"其中成功个数为: "+successNum+
790 |
791 | // " 失败个数为: "+failNum);
792 |
793 | // Toast.makeText(getApplicationContext(),"添加"+ wxid +"成功,当前总个数"+sum+"/"+num+"其中成功个数为: "+successNum+
794 |
795 | // " 失败个数为: "+failNum,Toast.LENGTH_LONG).show();
796 |
797 | // }
798 |
799 | SystemClock.sleep(1000);
800 |
801 | }
802 |
803 |
804 |
805 | private boolean isNeedVerify() {
806 | AccessibilityNodeInfo rootInfo = getRoot();
807 | List list;
808 | do {
809 | list = rootInfo.findAccessibilityNodeInfosByText("验证");
810 | SystemClock.sleep(200);
811 | }while (list==null);
812 | if (list.size()<=0){
813 | return false;
814 | }else {
815 | return true;
816 | }
817 | }
818 |
819 |
820 |
821 | // 线程睡眠,让出cpu
822 | public void waitfor(long overTime){
823 | long before = System.currentTimeMillis();
824 | do{
825 | long now = System.currentTimeMillis();
826 | if (now - before >= overTime){
827 | Log.i("xyz","等待超时");
828 | return;
829 | }
830 | SystemClock.sleep(500);
831 | }while (getCnt() == 0);
832 | }
833 |
834 |
835 |
836 | private int getCnt(){
837 | int i;
838 | synchronized (MyService.gs_lockObj){
839 | i = MyService.cnt;
840 | Log.i("xyz","get cnt = "+ MyService.cnt);
841 | }
842 | return i;
843 | }
844 |
845 |
846 |
847 | private void setCnt(int i){
848 | synchronized (MyService.gs_lockObj){
849 | MyService.cnt = i;
850 | Log.i("xyz","set cnt = "+ MyService.cnt);
851 | }
852 | }
853 |
854 | AccessibilityNodeInfo returnInfo;
855 | @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
856 | private void finishAndReturn() {
857 | Log.i("xyz","开始查找返回键");
858 | // 找到左上角的返回键
859 | AccessibilityNodeInfo root = getRoot();
860 |
861 | returnInfo = findReturn(root);
862 |
863 |
864 | sleepRandom();
865 |
866 | if (returnInfo == null){
867 |
868 | Log.i("xyz","找到的返回为null");
869 |
870 | }else {
871 |
872 | Log.i("xyz","找到的返回不为null");
873 |
874 | while (!returnInfo.isClickable()) {
875 |
876 | returnInfo = returnInfo.getParent();
877 |
878 | }
879 |
880 | // 点击返回
881 |
882 | returnInfo.performAction(AccessibilityNodeInfo.ACTION_CLICK);
883 |
884 | }
885 |
886 | }
887 |
888 |
889 |
890 |
891 |
892 | // 每次都等待1s后获取root根节点信息
893 |
894 | @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
895 |
896 | private AccessibilityNodeInfo getRoot() {
897 |
898 | mService = (AccessibilityService) MyService.getContext();
899 |
900 | AccessibilityNodeInfo root;
901 |
902 | do {
903 |
904 | root = mService.getRootInActiveWindow();
905 |
906 | SystemClock.sleep(200);
907 |
908 | }while (root==null);
909 |
910 | return root;
911 |
912 | }
913 |
914 |
915 |
916 | // 验证信息EditText框
917 |
918 | AccessibilityNodeInfo edit;
919 |
920 | @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
921 |
922 | private void sendMessage() {
923 |
924 | AccessibilityNodeInfo root = getRoot();
925 |
926 |
927 |
928 | // printfAll(root);
929 |
930 | // 找到输入框
931 |
932 | edit = findEditText(root);
933 |
934 | // if (edit == null){
935 |
936 | // Log.i("xyz","edit为空");
937 |
938 | // }else {
939 |
940 | // Log.i("xyz","edit不为空");
941 |
942 | // }
943 |
944 | // 清除原本信息
945 |
946 | do {
947 | ClearAllText(edit);
948 | edit = findEditText(root);
949 | }while (!TextUtils.isEmpty(edit.getText()));
950 |
951 |
952 |
953 |
954 |
955 | //
956 | // if (!TextUtils.isEmpty(edit.getText())){ // 如果不为空。清理
957 | //
958 | // ClearAllText(edit);
959 | //
960 | // }
961 |
962 | // 设置验证信息
963 |
964 | ClipboardManager manager = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
965 |
966 | String text = hello;
967 |
968 | ClipData data = ClipData.newPlainText("text",text);
969 |
970 | manager.setPrimaryClip(data);
971 |
972 | edit.performAction(AccessibilityNodeInfo.ACTION_PASTE);
973 |
974 |
975 |
976 |
977 |
978 | // 点击发送按钮
979 |
980 | //List sendList = root.findAccessibilityNodeInfosByViewId("com.tencent.mm:id/gy");
981 |
982 | List sendList;
983 |
984 | do {
985 |
986 | sendList = root.findAccessibilityNodeInfosByText("发送");
987 |
988 | SystemClock.sleep(200);
989 |
990 | }while (sendList == null);
991 |
992 | sleepRandom();
993 |
994 | for (AccessibilityNodeInfo info : sendList){
995 |
996 | Log.i("xyz","点击了发送");
997 |
998 | info.performAction(AccessibilityNodeInfo.ACTION_CLICK);
999 |
1000 | }
1001 |
1002 | }
1003 |
1004 |
1005 |
1006 | // 找到验证输入框
1007 |
1008 | private AccessibilityNodeInfo findEditText(AccessibilityNodeInfo root) {
1009 |
1010 | if (root == null){
1011 |
1012 | return null;
1013 |
1014 | }
1015 |
1016 | AccessibilityNodeInfo res = null;
1017 |
1018 |
1019 |
1020 | for (int i = 0; i < root.getChildCount(); i++) {
1021 |
1022 | AccessibilityNodeInfo nodeInfo = root.getChild(i);
1023 |
1024 | if (nodeInfo.getClassName().equals("android.widget.EditText")) {
1025 |
1026 | Log.i("xyz","获取到editteXt");
1027 |
1028 | Log.i("xyz","nodeInfo = "+nodeInfo);
1029 |
1030 | Rect rect = new Rect();
1031 |
1032 | nodeInfo.getBoundsInScreen(rect);
1033 |
1034 | int x = rect.centerX();
1035 |
1036 | int y = rect.centerY();
1037 |
1038 | if (9 < x && x < 371 && 80 < y && y < 108) {
1039 |
1040 | res = nodeInfo;
1041 |
1042 | break; // 这里必须有这个break,表示找到输入框之后就会打破循环,将找到的值返回
1043 |
1044 | }
1045 |
1046 | }else {
1047 |
1048 | res = findEditText(nodeInfo);
1049 |
1050 | if (res != null){
1051 |
1052 | return res;
1053 |
1054 | }
1055 |
1056 | }
1057 |
1058 | }
1059 |
1060 | return res;
1061 |
1062 | }
1063 |
1064 |
1065 |
1066 | private void printfAll(AccessibilityNodeInfo root){
1067 |
1068 | for (int i = 0; i < root.getChildCount(); i++) {
1069 |
1070 | AccessibilityNodeInfo nodeInfo = root.getChild(i);
1071 |
1072 | Log.i("xyz","class name = "+nodeInfo.getClassName());
1073 |
1074 | printfAll(nodeInfo);
1075 |
1076 | }
1077 |
1078 | }
1079 |
1080 |
1081 |
1082 | // 清除原来的文本信息
1083 |
1084 | private void ClearAllText(AccessibilityNodeInfo info) {
1085 |
1086 | // 每次只能删除一个字符
1087 |
1088 | String adb = "adb shell input keyevent 67";
1089 |
1090 |
1091 |
1092 | int length = info.getText().length();
1093 |
1094 | Log.i("xyz","原先文本长度 "+ length);
1095 |
1096 | for (int i = 0; i < length; i++) {
1097 |
1098 | try {
1099 |
1100 | Runtime.getRuntime().exec(adb);
1101 |
1102 | Log.i("xyz","执行一次");
1103 |
1104 | SystemClock.sleep(300); // 睡眠是为了保证能够全部清除
1105 |
1106 | } catch (IOException e) {
1107 |
1108 | e.printStackTrace();
1109 |
1110 | }
1111 |
1112 | }
1113 |
1114 | }
1115 |
1116 |
1117 |
1118 | @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
1119 |
1120 | // 点击添加按钮
1121 |
1122 | private void clickAddButton() {
1123 |
1124 |
1125 |
1126 | AccessibilityNodeInfo root = getRoot();
1127 |
1128 | // 获取到添加按钮
1129 |
1130 | // List list = root.findAccessibilityNodeInfosByViewId("com.tencent.mm:id/ahp");
1131 |
1132 | List list;
1133 |
1134 | do {
1135 |
1136 | list = root.findAccessibilityNodeInfosByText("添加");
1137 |
1138 | SystemClock.sleep(200);
1139 |
1140 | }while (list == null);
1141 |
1142 |
1143 |
1144 | sleepRandom();
1145 |
1146 | if (list.size() > 0){
1147 |
1148 | Log.i("xyz","找到添加按钮");
1149 |
1150 | for (AccessibilityNodeInfo info : list){
1151 |
1152 | // 点击按钮
1153 |
1154 | info.performAction(AccessibilityNodeInfo.ACTION_CLICK);
1155 |
1156 | break;
1157 |
1158 | }
1159 |
1160 | }
1161 |
1162 | }
1163 |
1164 |
1165 |
1166 | private void selectFile() {
1167 | // 打开系统文件浏览功能
1168 | Intent intent = new Intent();
1169 | intent.setAction(Intent.ACTION_GET_CONTENT);
1170 | intent.setType("*/*");
1171 | intent.addCategory(Intent.CATEGORY_OPENABLE);
1172 | startActivityForResult(Intent.createChooser(intent, "Select a file path"), SELECT_CODE);
1173 |
1174 | }
1175 |
1176 | @Override
1177 | protected void onActivityResult(int requestCode, int resultCode, Intent data) {
1178 | if (resultCode == RESULT_OK && requestCode == SELECT_CODE) {
1179 | Uri uri = data.getData();
1180 | if ("file".equalsIgnoreCase(uri.getScheme())) { // 使用第三方应用打开
1181 | filePath = uri.getPath();
1182 | tvFilePath.setText(filePath);
1183 | Log.i(TAG, "filePath = " + filePath);
1184 | return;
1185 | }
1186 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { // 4.4以后
1187 | filePath = getPathKitKat(this, uri);
1188 | tvFilePath.setText(filePath);
1189 | Log.i(TAG, "filePath = " + filePath);
1190 | } else {
1191 | filePath = getPathUnderKitKat(uri); // 4.4 以前
1192 | tvFilePath.setText(filePath);
1193 | Log.i(TAG, "filePath = " + filePath);
1194 | }
1195 |
1196 |
1197 | // 获取txt文本信息
1198 | if (TextUtils.isEmpty(filePath)) {
1199 | Toast.makeText(AddActivity.this, "请选择文件路径", LENGTH_SHORT).show();
1200 | } else {
1201 | getTxtInfo();
1202 | }
1203 | }
1204 | }
1205 |
1206 | private String getPathUnderKitKat(Uri uri) {
1207 | String res = null;
1208 | String[] proj = {MediaStore.Images.Media.DATA};
1209 | Cursor cursor = getContentResolver().query(uri, proj, null, null, null);
1210 | if (null != cursor && cursor.moveToFirst()) {
1211 | int index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
1212 | res = cursor.getString(index);
1213 | cursor.close();
1214 | }
1215 | return res;
1216 | }
1217 |
1218 | // 4.4 以后从uri获取文件的绝对路径
1219 | @SuppressLint("NewApi")
1220 | private String getPathKitKat(Context context, Uri uri) {
1221 | final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
1222 |
1223 | // 文件提供者 DocumentProvider
1224 | if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
1225 | // ExternalStorageProvider
1226 | if (isExternalStorageDocument(uri)) {
1227 | final String docId = DocumentsContract.getDocumentId(uri);
1228 | final String[] split = docId.split(":");
1229 | final String type = split[0];
1230 | if ("primary".equalsIgnoreCase(type)) {
1231 | return Environment.getExternalStorageDirectory() + "/" + split[1];
1232 | }
1233 | }
1234 | // DownloadsProvider
1235 | else if (isDownloadDocument(uri)) {
1236 | final String id = DocumentsContract.getDocumentId(uri);
1237 | final Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
1238 | return getDataColumn(context, contentUri, null, null);
1239 | }
1240 | // MediaProvider
1241 | else if (isMediaDocument(uri)) {
1242 | final String docId = DocumentsContract.getDocumentId(uri);
1243 | final String[] split = docId.split(":");
1244 | final String type = split[0];
1245 | Uri contentUri = null;
1246 | if ("image".equals(type)) {
1247 | contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
1248 | } else if ("video".equals(type)) {
1249 | contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
1250 | } else if ("audio".equals(type)) {
1251 | contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
1252 | }
1253 | final String selection = "_id=?";
1254 | final String[] selectionArgs = new String[]{split[1]};
1255 | return getDataColumn(context, contentUri, selection, selectionArgs);
1256 | }
1257 | }
1258 | // MediaStore (general)
1259 | else if ("content".equalsIgnoreCase(uri.getScheme())) {
1260 | return getDataColumn(context, uri, null, null);
1261 | }
1262 | // file文件类型
1263 | else if ("file".equalsIgnoreCase(uri.getScheme())) {
1264 | return uri.getPath();
1265 | }
1266 | return null;
1267 | }
1268 |
1269 |
1270 | // 返回从uri获取到的数据column ,这种只对MediaStore有效。其他的都是ContentProviders
1271 | private String getDataColumn(Context context, Uri contentUri, String selection, String[] selectArgs) {
1272 | Cursor cursor = null;
1273 | final String column = "_data";
1274 | final String[] proj = {column};
1275 | cursor = context.getContentResolver().query(contentUri, proj, selection, selectArgs, null);
1276 | try {
1277 | if (cursor != null && cursor.moveToFirst()) {
1278 | int index = cursor.getColumnIndexOrThrow(column);
1279 | return cursor.getString(index);
1280 | }
1281 | } finally {
1282 | if (cursor != null) {
1283 | cursor.close();
1284 | }
1285 | }
1286 | return null;
1287 | }
1288 |
1289 |
1290 | // 是否是Media路径下的
1291 | private boolean isMediaDocument(Uri uri) {
1292 | return "com.android.providers.media.documents".equals(uri.getAuthority());
1293 | }
1294 |
1295 | // 是否是下载路径下的
1296 | private boolean isDownloadDocument(Uri uri) {
1297 | return "com.android.providers.downloads.documents".equals(uri.getAuthority());
1298 |
1299 | }
1300 |
1301 | // 是否是ExternalStorage路径下的
1302 | private boolean isExternalStorageDocument(Uri uri) {
1303 | return "com.android.externalstorage.documents".equals(uri.getAuthority());
1304 | }
1305 |
1306 |
1307 | // 遍历文本中的每一行,将信息放入list中
1308 | private void getTxtInfo() {
1309 | File file = new File(filePath);
1310 | String line = "";
1311 | list.clear();
1312 | sum = 0 ;
1313 | try {
1314 | BufferedReader br = new BufferedReader(new FileReader(file));
1315 | while ((line = br.readLine()) != null) {
1316 | list.add(line);
1317 | }
1318 | br.close();
1319 | } catch (FileNotFoundException e) {
1320 | e.printStackTrace();
1321 | } catch (IOException e) {
1322 | e.printStackTrace();
1323 | }
1324 | }
1325 | }
1326 |
--------------------------------------------------------------------------------