├── .gitignore ├── .idea ├── caches │ └── build_file_checksums.ser ├── codeStyles │ └── Project.xml ├── gradle.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── Postern-3.1.2.apk ├── README.md ├── UI.png ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── assets │ ├── chinalist.txt │ └── postern.conf │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── koolwiki │ │ └── goflyway_android │ │ ├── BusProvider.java │ │ ├── CmdParam.java │ │ ├── Constants.java │ │ ├── MainActivity.java │ │ ├── MessageEvent.java │ │ ├── SettingActivity.java │ │ ├── ShellCallback.java │ │ ├── StreamGobbler.java │ │ └── service │ │ └── WhiteService.java │ └── res │ ├── layout │ ├── activity_main.xml │ └── activity_setting.xml │ ├── mipmap-hdpi │ └── ic_launcher.png │ ├── mipmap-mdpi │ └── ic_launcher.png │ ├── mipmap-xhdpi │ └── ic_launcher.png │ ├── mipmap-xxhdpi │ └── ic_launcher.png │ ├── mipmap-xxxhdpi │ └── ic_launcher.png │ ├── raw │ ├── chinalist │ └── goflyway │ ├── values-en │ └── strings.xml │ ├── values-w820dp │ └── dimens.xml │ ├── values-zh │ └── strings.xml │ └── values │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── goflyway_amd64 ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── logic.png ├── rules.jpg ├── servers.jpg └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | /app/cracker-release.apk 10 | /release_beta_apk/ 11 | -------------------------------------------------------------------------------- /.idea/caches/build_file_checksums.ser: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koolwiki/goflyway_android/32599a5883f1185f8b5c846f89c280dda10f5cca/.idea/caches/build_file_checksums.ser -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 15 | 16 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 27 | 28 | 29 | 30 | 31 | 32 | 34 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Postern-3.1.2.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koolwiki/goflyway_android/32599a5883f1185f8b5c846f89c280dda10f5cca/Postern-3.1.2.apk -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Fork自Kcptun_android,通过修改适配了goflyway,支持CDN,kcp和https。 2 | 3 | [预编译安装包latest 下载](https://github.com/koolwiki/goflyway_android/releases/latest) 4 | 5 | 软件设置如下图,有的手机杀后台比较严重,可以把goflyway加入白名单或者设置成不进行省电优化,这样可以避免在后台中被杀掉。或者在termux里面运行goflyway(推荐采用这种方法)。 6 | 7 | 代理设置有3种方法,3种方法都可以(推荐第3种): 8 | 9 | 1、直接在wifi里面设置代理:直接在连接的wifi里面设置代理为“手动”,主机名称设为“127.0.0.1”,端口号为“8100”。设置好后手机就可以自由上网了。 10 | 11 | 2、利用Postern设置代理:这种模式需要[Postern](https://play.google.com/store/apps/details?id=com.tunnelworkshop.postern&hl=zh)这个软件(可以去[这里下载](https://github.com/koolwiki/goflyway_android/raw/master/Postern-3.1.2.apk))配合一起使用。Postern代理服务器栏填127.0.0.1,端口栏填goflyway上面填写的本地端口号(纯端口号,如下图的8100)。 12 | 13 | 3、利用BifrostV设置代理:这种模式需要[BifrostV](https://play.google.com/store/apps/details?id=com.github.dawndiy.bifrostv&hl=zh)这个软件配合一起使用。BifrostV里面添加代理,选择手动设置,将VMess修改成Socks,然后将主机名称设为“127.0.0.1”,端口号为“8100”,并设置分应用代理,保存。使用是点击左下角的红色开关图标即可。 14 | 15 | ![UI](https://github.com/koolwiki/goflyway_android/raw/master/UI.png "UI") 16 | 17 | Postern设置如下(配置代理规则项,目标地址那里自行编辑需要走代理的域名): 18 | 19 | ![配置代理](https://github.com/koolwiki/goflyway_android/raw/master/servers.jpg "配置代理") 20 | 21 | ![配置代理规则](https://github.com/koolwiki/goflyway_android/raw/master/rules.jpg "配置代理规则") 22 | 23 | #感谢 [goflyway项目](https://github.com/coyove/goflyway) 24 | 25 | #感谢 [Kcptun_android项目](https://github.com/shutup/Kcptun_android) 26 | 27 | #感谢 [KcpTun项目](https://github.com/xtaci/kcptun) 28 | -------------------------------------------------------------------------------- /UI.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koolwiki/goflyway_android/32599a5883f1185f8b5c846f89c280dda10f5cca/UI.png -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | " sourceSets { main { assets.srcDirs = ['src/assets', 'src/assets/'] } } " 4 | 5 | android { 6 | compileSdkVersion 23 7 | buildToolsVersion '23.0.1' 8 | defaultConfig { 9 | applicationId "com.koolwiki.goflyway_android" 10 | minSdkVersion 10 11 | targetSdkVersion 23 12 | versionCode 1 13 | versionName '1.0' 14 | javaCompileOptions { 15 | annotationProcessorOptions { 16 | includeCompileClasspath = true 17 | } 18 | } 19 | } 20 | buildTypes { 21 | release { 22 | minifyEnabled false 23 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 24 | } 25 | } 26 | productFlavors { 27 | } 28 | } 29 | 30 | dependencies { 31 | compile fileTree(include: ['*.jar'], dir: 'libs') 32 | testCompile 'junit:junit:4.12' 33 | compile 'com.android.support:appcompat-v7:23.4.0' 34 | compile 'com.jakewharton:butterknife:5.1.1' 35 | compile 'com.android.support:design:23.4.0' 36 | compile 'com.squareup:otto:1.3.5' 37 | compile 'com.google.code.gson:gson:2.8.2' 38 | 39 | } 40 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/shutup/Library/Android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 15 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /app/src/main/java/com/koolwiki/goflyway_android/BusProvider.java: -------------------------------------------------------------------------------- 1 | package com.koolwiki.goflyway_android; 2 | 3 | import com.squareup.otto.Bus; 4 | import com.squareup.otto.ThreadEnforcer; 5 | 6 | /** 7 | * Created by shutup on 16/7/23. 8 | */ 9 | public class BusProvider { 10 | private static Bus ourInstance = new Bus(ThreadEnforcer.ANY); 11 | 12 | public static Bus getInstance() { 13 | return ourInstance; 14 | } 15 | 16 | private BusProvider() { 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /app/src/main/java/com/koolwiki/goflyway_android/CmdParam.java: -------------------------------------------------------------------------------- 1 | package com.koolwiki.goflyway_android; 2 | 3 | /** 4 | * Created by shutup on 16/7/19. 5 | */ 6 | public class CmdParam { 7 | 8 | public static String LOCALADDR = "-l"; 9 | public static String REMOTEADDR = "-up"; 10 | public static String KEY = "-k"; 11 | public static String CRYPT = "-crypt"; 12 | public static String UNDERLAY = "-U"; 13 | public static String ACL = "-acl"; 14 | 15 | 16 | public String localaddr; 17 | public String remoteaddr; 18 | public String key; 19 | public String crypt; 20 | public String U; 21 | public String A; 22 | public String mtu; 23 | public String sndwnd; 24 | public String revwnd; 25 | public boolean nocmp; 26 | 27 | public Boolean isBasicOk(){ 28 | if (remoteaddr.equalsIgnoreCase("")){ 29 | return false; 30 | } 31 | if (key.equalsIgnoreCase("")) { 32 | return false; 33 | } 34 | 35 | return true; 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /app/src/main/java/com/koolwiki/goflyway_android/Constants.java: -------------------------------------------------------------------------------- 1 | package com.koolwiki.goflyway_android; 2 | 3 | /** 4 | * Created by shutup on 16/7/20. 5 | */ 6 | public interface Constants { 7 | String AppVersionCode = "AppVersionCode"; 8 | String SettingChanged = "SettingChanged"; 9 | 10 | String RemoteServerIp = "RemoteServerIp"; 11 | String RemoteServerPort = "RemoteServerPort"; 12 | String LocalServerPort = "LocalServerPort"; 13 | String ServerKey = "ServerKey"; 14 | String UnderLay = "UnderLay"; 15 | 16 | int SET_INFO_CONTENT = 0; 17 | int APPEND_INFO_CONTENT = 1; 18 | int CHANGE_START_BTN_NAME = 2; 19 | int CHANGE_START_BTN_ENABLE = 3; 20 | int CHANGE_SETTING_BTN_ENABLE = 5; 21 | } 22 | -------------------------------------------------------------------------------- /app/src/main/java/com/koolwiki/goflyway_android/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.koolwiki.goflyway_android; 2 | 3 | 4 | import com.koolwiki.goflyway_android.service.WhiteService; 5 | 6 | 7 | import android.content.Context; 8 | import android.content.Intent; 9 | import android.content.SharedPreferences; 10 | import android.content.pm.PackageInfo; 11 | import android.content.pm.PackageManager; 12 | import android.os.Bundle; 13 | import android.preference.PreferenceManager; 14 | import android.support.v7.app.AppCompatActivity; 15 | import android.util.Log; 16 | import android.view.View; 17 | import android.widget.Button; 18 | import android.widget.TextView; 19 | import android.widget.Toast; 20 | 21 | 22 | import com.squareup.otto.Subscribe; 23 | 24 | 25 | import java.io.File; 26 | import java.io.FileOutputStream; 27 | import java.io.IOException; 28 | import java.io.InputStream; 29 | import java.util.ArrayList; 30 | 31 | 32 | import butterknife.ButterKnife; 33 | import butterknife.InjectView; 34 | import butterknife.OnClick; 35 | 36 | import static com.koolwiki.goflyway_android.CmdParam.ACL; 37 | 38 | 39 | public class MainActivity extends AppCompatActivity implements Constants{ 40 | 41 | private static final String TAG = "MainActivity"; 42 | private String goflyway = "goflyway"; 43 | private String chinalist = "chinalist.txt"; 44 | private String binary_path = null; 45 | private String chinalist_path = null; 46 | private int count_acl = 0; 47 | @InjectView(R.id.info) 48 | TextView mInfo; 49 | @InjectView(R.id.settingBtn) 50 | Button mSettingBtn; 51 | @InjectView(R.id.startBtn) 52 | Button mStartBtn; 53 | private CmdParam cmdParam = null; 54 | private Process process = null; 55 | private SharedPreferences mSharedPreferences = null; 56 | 57 | @Override 58 | protected void onCreate(Bundle savedInstanceState) { 59 | super.onCreate(savedInstanceState); 60 | setContentView(R.layout.activity_main); 61 | ButterKnife.inject(this); 62 | BusProvider.getInstance().register(this); 63 | mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(this); 64 | tryToStart(); 65 | Intent whiteIntent = new Intent(getApplicationContext(), WhiteService.class); 66 | startService(whiteIntent); 67 | if (BuildConfig.DEBUG) Log.d(TAG, "onCreate"); 68 | } 69 | 70 | @Override 71 | protected void onResume() { 72 | super.onResume(); 73 | if (BuildConfig.DEBUG) Log.d(TAG, "onResume"); 74 | Boolean settingChanged = false; 75 | settingChanged = mSharedPreferences.getBoolean(SettingChanged, false); 76 | if (settingChanged){ 77 | if (process != null) { 78 | killgoflyway(); 79 | } 80 | tryToStart(); 81 | SharedPreferences.Editor editor = mSharedPreferences.edit(); 82 | editor.putBoolean(SettingChanged, false); 83 | editor.commit(); 84 | } 85 | } 86 | 87 | @Override 88 | protected void onDestroy() { 89 | super.onDestroy(); 90 | killgoflyway(); 91 | BusProvider.getInstance().unregister(this); 92 | } 93 | 94 | private void tryToStart() { 95 | SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this); 96 | cmdParam = new CmdParam(); 97 | //cmdParam.A = "chinalist"; 98 | cmdParam.localaddr = "0.0.0.0:" + sharedPreferences.getString(LocalServerPort, ""); 99 | cmdParam.remoteaddr = sharedPreferences.getString(RemoteServerIp, "").equalsIgnoreCase("") ? "": sharedPreferences.getString(RemoteServerIp, "") + ":" + sharedPreferences.getString(RemoteServerPort,""); 100 | cmdParam.key = sharedPreferences.getString(ServerKey, ""); 101 | cmdParam.U = sharedPreferences.getString(UnderLay, ""); 102 | if (cmdParam.isBasicOk()){ 103 | handleStartBtnClick(); 104 | }else { 105 | cmdParam = null; 106 | if (BuildConfig.DEBUG) Log.d(TAG, "need more info "); 107 | Toast.makeText(this, getString(R.string.no_setting_info), Toast.LENGTH_SHORT).show(); 108 | BusProvider.getInstance().post(new MessageEvent(getString(R.string.no_setting_info), SET_INFO_CONTENT)); 109 | } 110 | } 111 | 112 | @OnClick({R.id.settingBtn, R.id.startBtn}) 113 | public void onClick(View view) { 114 | switch (view.getId()) { 115 | case R.id.settingBtn: 116 | handleSettingBtnClick(); 117 | break; 118 | case R.id.startBtn: 119 | tryToStart(); 120 | break; 121 | } 122 | } 123 | 124 | private void handleSettingBtnClick() { 125 | Intent intent = new Intent(this,SettingActivity.class); 126 | startActivity(intent); 127 | } 128 | 129 | private void handleStartBtnClick() { 130 | if (mStartBtn.getText().toString().equalsIgnoreCase(getString(R.string.start))){ 131 | BusProvider.getInstance().post(new MessageEvent("", SET_INFO_CONTENT)); 132 | String arch = System.getProperty("os.arch"); 133 | if (BuildConfig.DEBUG) Log.d(TAG, arch); 134 | BusProvider.getInstance().post(new MessageEvent(getString(R.string.arch_info)+arch, APPEND_INFO_CONTENT)); 135 | int identifier = detectCpuArchInfo(); 136 | if (identifier == 0){ 137 | Toast.makeText(this, R.string.detect_cpu_info_error, Toast.LENGTH_SHORT).show(); 138 | return; 139 | } 140 | BusProvider.getInstance().post(new MessageEvent(getString(R.string.stop),CHANGE_START_BTN_NAME)); 141 | BusProvider.getInstance().post(new MessageEvent(false,CHANGE_SETTING_BTN_ENABLE)); 142 | binary_path = installBinary(this, identifier, goflyway); 143 | chinalist_path = installList(this); 144 | 145 | // BusProvider.getInstance().post(new MessageEvent(binary_path, APPEND_INFO_CONTENT)); 146 | if (BuildConfig.DEBUG) Log.d(TAG, binary_path); 147 | 148 | new Thread(new Runnable() { 149 | @Override 150 | public void run() { 151 | runCmdLine(new ShellCallback() { 152 | @Override 153 | public void shellOut(String shellLine) { 154 | BusProvider.getInstance().post(new MessageEvent(shellLine, APPEND_INFO_CONTENT)); 155 | } 156 | 157 | @Override 158 | public void processComplete(int exitValue) { 159 | if (BuildConfig.DEBUG) Log.d(TAG, "exitValue:" + exitValue); 160 | //restore 161 | BusProvider.getInstance().post(new MessageEvent(getString(R.string.start),CHANGE_START_BTN_NAME)); 162 | BusProvider.getInstance().post(new MessageEvent(true,CHANGE_SETTING_BTN_ENABLE)); 163 | } 164 | }); 165 | } 166 | }).start(); 167 | }else if (mStartBtn.getText().toString().equalsIgnoreCase(getString(R.string.stop))) { 168 | killgoflyway(); 169 | BusProvider.getInstance().post(new MessageEvent(getString(R.string.start),CHANGE_START_BTN_NAME)); 170 | BusProvider.getInstance().post(new MessageEvent(true,CHANGE_SETTING_BTN_ENABLE)); 171 | } 172 | } 173 | 174 | /** 175 | * 根据CPU指令集的不同,返回不同的可执行程序ID 176 | * 177 | * @return 178 | */ 179 | private int detectCpuArchInfo() { 180 | String arch = System.getProperty("os.arch"); 181 | int identifierId = 0; 182 | arch = arch == null ? "" : arch; 183 | if (arch.contains("arm")) { 184 | if (arch.contains("v7")) { 185 | identifierId = getResources().getIdentifier("goflyway", "raw", getPackageName()); 186 | } else if (arch.contains("v6")) { 187 | identifierId = getResources().getIdentifier("goflyway", "raw", getPackageName()); 188 | } else if (arch.contains("v5")) { 189 | identifierId = getResources().getIdentifier("goflyway", "raw", getPackageName()); 190 | } 191 | }else if (arch.contains("aarch64")) { 192 | //目前采取兼容模式 193 | identifierId = getResources().getIdentifier("goflyway", "raw", getPackageName()); 194 | }else if (arch.contains("x86_64")) { 195 | //目前采取兼容模式 196 | identifierId = getResources().getIdentifier("goflyway", "raw", getPackageName()); 197 | } 198 | if (BuildConfig.DEBUG) Log.d(TAG, "identifierId:" + identifierId); 199 | return identifierId; 200 | } 201 | 202 | 203 | /** 204 | * 安装可执行程序 205 | * 206 | * @param ctx 207 | * @param resId 208 | * @param filename 209 | * @return 210 | */ 211 | private String installBinary(Context ctx, int resId, String filename) { 212 | try { 213 | File f = new File(ctx.getApplicationContext().getFilesDir().getAbsolutePath(), filename); 214 | if (f.exists()) { 215 | handleKcptunUpdate(ctx, resId, f); 216 | } else { 217 | copyRawFile(ctx,resId,f,"0755"); 218 | Log.d(TAG, f + " installed(copy)"); 219 | } 220 | return f.getCanonicalPath(); 221 | } catch (Exception e) { 222 | Log.e(TAG, "installBinary failed: " + e.getLocalizedMessage()); 223 | return null; 224 | } 225 | } 226 | 227 | 228 | private void handleKcptunUpdate(Context ctx, int resId, File f) throws PackageManager.NameNotFoundException, IOException, InterruptedException { 229 | PackageInfo pInfo = getPackageManager().getPackageInfo(getPackageName(), 0); 230 | int currentVersionCode = pInfo.versionCode; 231 | int localVersionCode = mSharedPreferences.getInt(AppVersionCode,0); 232 | if (localVersionCode < currentVersionCode) { 233 | copyRawFile(ctx,resId,f,"0755"); 234 | Log.d(TAG, f + " installed(handle)"); 235 | } 236 | else{ 237 | if (BuildConfig.DEBUG) Log.d(TAG, f + " not updated"); 238 | } 239 | } 240 | 241 | private static void copyRawFile(Context ctx, int resid, File file, String mode) throws IOException, InterruptedException { 242 | final String abspath = file.getAbsolutePath(); 243 | final FileOutputStream out = new FileOutputStream(file); 244 | final InputStream is = ctx.getResources().openRawResource(resid); 245 | byte buf[] = new byte[1024]; 246 | int len; 247 | while ((len = is.read(buf)) > 0) { 248 | out.write(buf, 0, len); 249 | } 250 | out.close(); 251 | is.close(); 252 | // Change the permissions 253 | Runtime.getRuntime().exec("chmod " + mode + " " + abspath).waitFor(); 254 | } 255 | 256 | 257 | 258 | private String installList(Context ctx) { 259 | try { 260 | File f = new File(getApplicationContext().getFilesDir().getAbsolutePath() + "/chinalist.txt"); 261 | if (f.exists()) { 262 | handleListUpdate(f); 263 | } else { 264 | //handleListUpdate(f); 265 | copyListFile(f,"0644"); 266 | Log.d(TAG, f + " installed(copy)"); 267 | // Log.d(TAG, f + " exist: " ); 268 | } 269 | return f.getCanonicalPath(); 270 | } catch (Exception e) { 271 | Log.e(TAG, "installList failed: " + e.getLocalizedMessage()); 272 | return null; 273 | } 274 | } 275 | 276 | 277 | private void handleListUpdate(File f) throws PackageManager.NameNotFoundException, IOException, InterruptedException { 278 | PackageInfo pInfo = getPackageManager().getPackageInfo(getPackageName(), 0); 279 | int currentVersionCode = pInfo.versionCode; 280 | int localVersionCode = mSharedPreferences.getInt(AppVersionCode,0); 281 | if (localVersionCode < currentVersionCode) { 282 | copyListFile(f,"0644"); 283 | SharedPreferences.Editor editor = mSharedPreferences.edit(); 284 | editor.putInt(AppVersionCode,currentVersionCode); 285 | editor.commit(); 286 | Log.d(TAG, f + " installed(handle)"); 287 | } 288 | else{ 289 | if (BuildConfig.DEBUG) Log.d(TAG, f + " not updated"); 290 | } 291 | } 292 | 293 | private void copyListFile(File file, String mode) throws IOException, InterruptedException { 294 | final String abspath = file.getAbsolutePath(); 295 | final FileOutputStream out = new FileOutputStream(file); 296 | final InputStream is = getResources().openRawResource(R.raw.chinalist); 297 | byte buf[] = new byte[1024]; 298 | int len; 299 | while ((len = is.read(buf)) > 0) { 300 | out.write(buf, 0, len); 301 | } 302 | out.close(); 303 | is.close(); 304 | // Change the permissions 305 | Runtime.getRuntime().exec("chmod " + mode + " " + abspath).waitFor(); 306 | } 307 | 308 | 309 | 310 | /** 311 | * 执行指令 312 | * 313 | * @param sc 314 | * @return 315 | */ 316 | private int runCmdLine(ShellCallback sc) { 317 | // Executes the command. 318 | 319 | 320 | 321 | if (cmdParam == null){ 322 | // Toast.makeText(this, "Please Fill The Setting First", Toast.LENGTH_SHORT).show(); 323 | if (BuildConfig.DEBUG) Log.d(TAG, "Please Fill The Setting First"); 324 | return -1; 325 | } 326 | if (binary_path == null) { 327 | return -1; 328 | } 329 | 330 | final String cmd = setup_cmd(binary_path, cmdParam); 331 | 332 | BusProvider.getInstance().post(new MessageEvent(cmd,APPEND_INFO_CONTENT)); 333 | 334 | process = null; 335 | try { 336 | process = Runtime.getRuntime().exec(cmd); 337 | } catch (IOException e) { 338 | e.printStackTrace(); 339 | } 340 | 341 | // any error message? 342 | StreamGobbler errorGobbler = new StreamGobbler( 343 | process.getErrorStream(), "ERROR", sc); 344 | 345 | // any output? 346 | StreamGobbler outputGobbler = new 347 | StreamGobbler(process.getInputStream(), "OUTPUT", sc); 348 | 349 | errorGobbler.start(); 350 | outputGobbler.start(); 351 | 352 | int exitVal = 0; 353 | try { 354 | exitVal = process.waitFor(); 355 | } catch (InterruptedException e) { 356 | e.printStackTrace(); 357 | } 358 | 359 | sc.processComplete(exitVal); 360 | 361 | return exitVal; 362 | } 363 | 364 | 365 | 366 | private String setup_cmd(String binary_path, CmdParam cmdParam) { 367 | 368 | ArrayList params = new ArrayList<>(); 369 | if (cmdParam.localaddr != null) { 370 | if(cmdParam.localaddr.indexOf("-acl") != -1) 371 | { 372 | count_acl = count_acl + 1; 373 | } 374 | params.add(CmdParam.LOCALADDR); 375 | params.add(cmdParam.localaddr); 376 | } 377 | 378 | if (cmdParam.remoteaddr != null) { 379 | if(cmdParam.remoteaddr.indexOf("-acl") != -1) 380 | { 381 | count_acl = count_acl + 1; 382 | } 383 | params.add(CmdParam.REMOTEADDR); 384 | params.add(cmdParam.remoteaddr); 385 | } 386 | 387 | if (cmdParam.key != null) { 388 | if(cmdParam.key.indexOf(" -acl") != -1) 389 | { 390 | count_acl = count_acl + 1; 391 | } 392 | params.add(CmdParam.KEY); 393 | params.add(cmdParam.key); 394 | } 395 | 396 | if (cmdParam.U != null) { 397 | if(cmdParam.U.indexOf("-acl") != -1) 398 | { 399 | count_acl = count_acl + 1; 400 | } 401 | } 402 | 403 | if (count_acl != 0) { 404 | params.add(CmdParam.UNDERLAY); 405 | params.add(cmdParam.U); 406 | Log.d(TAG, "count_acl!=" + count_acl ); 407 | count_acl = 0; 408 | } 409 | 410 | else { 411 | params.add(CmdParam.UNDERLAY); 412 | params.add(cmdParam.U + " " + ACL + " " + chinalist_path); 413 | Log.d(TAG, "count_acl==" + count_acl ); 414 | 415 | } 416 | StringBuilder stringBuilder = new StringBuilder(binary_path); 417 | for (String param : params) { 418 | stringBuilder.append(' '); 419 | stringBuilder.append(param); 420 | stringBuilder.append(' '); 421 | } 422 | return stringBuilder.toString(); 423 | } 424 | 425 | 426 | private void killgoflyway(){ 427 | if (process != null){ 428 | process.destroy(); 429 | try { 430 | int retVal = process.waitFor(); 431 | if (BuildConfig.DEBUG) Log.d(TAG, "retVal:" + retVal); 432 | if (retVal == 9) { 433 | BusProvider.getInstance().post(new MessageEvent(getString(R.string.stop_kcp_tun_normal),SET_INFO_CONTENT)); 434 | }else{ 435 | BusProvider.getInstance().post(new MessageEvent(getString(R.string.stop_kcp_tun_exception),SET_INFO_CONTENT)); 436 | } 437 | } catch (InterruptedException e) { 438 | e.printStackTrace(); 439 | } 440 | } 441 | } 442 | 443 | @Subscribe 444 | public void handleInfoContentChange(final MessageEvent messageEvent) { 445 | runOnUiThread(new Runnable() { 446 | @Override 447 | public void run() { 448 | if (messageEvent.getType() == SET_INFO_CONTENT) { 449 | mInfo.setText(messageEvent.getMsg()); 450 | }else if (messageEvent.getType() == APPEND_INFO_CONTENT){ 451 | mInfo.append(messageEvent.getMsg()+"\n"); 452 | } 453 | } 454 | }); 455 | } 456 | 457 | @Subscribe 458 | public void handleBtnName(final MessageEvent messageEvent) { 459 | runOnUiThread(new Runnable() { 460 | @Override 461 | public void run() { 462 | if (messageEvent.getType() == CHANGE_START_BTN_NAME) { 463 | mStartBtn.setText(messageEvent.getMsg()); 464 | } 465 | } 466 | }); 467 | } 468 | 469 | @Subscribe 470 | public void handleBtnEnable(final MessageEvent messageEvent) { 471 | runOnUiThread(new Runnable() { 472 | @Override 473 | public void run() { 474 | if (messageEvent.getType() == CHANGE_START_BTN_ENABLE) { 475 | mStartBtn.setEnabled(messageEvent.isEnable()); 476 | }else if (messageEvent.getType() == CHANGE_SETTING_BTN_ENABLE) { 477 | mSettingBtn.setEnabled(messageEvent.isEnable()); 478 | } 479 | } 480 | }); 481 | } 482 | 483 | 484 | } 485 | -------------------------------------------------------------------------------- /app/src/main/java/com/koolwiki/goflyway_android/MessageEvent.java: -------------------------------------------------------------------------------- 1 | package com.koolwiki.goflyway_android; 2 | 3 | /** 4 | * Created by shutup on 16/7/23. 5 | */ 6 | public class MessageEvent { 7 | private String msg; 8 | private int type; 9 | private boolean isEnable; 10 | 11 | public MessageEvent(String msg, int type) { 12 | this.msg = msg; 13 | this.type = type; 14 | } 15 | 16 | public MessageEvent( boolean isEnable,int type) { 17 | this.type = type; 18 | this.isEnable = isEnable; 19 | } 20 | 21 | public String getMsg() { 22 | return msg; 23 | } 24 | 25 | public int getType() { 26 | return type; 27 | } 28 | 29 | public boolean isEnable() { 30 | return isEnable; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /app/src/main/java/com/koolwiki/goflyway_android/SettingActivity.java: -------------------------------------------------------------------------------- 1 | package com.koolwiki.goflyway_android; 2 | 3 | import android.content.SharedPreferences; 4 | import android.os.Bundle; 5 | import android.preference.PreferenceManager; 6 | import android.support.design.widget.TextInputEditText; 7 | import android.support.design.widget.TextInputLayout; 8 | import android.support.v7.app.AppCompatActivity; 9 | 10 | import butterknife.ButterKnife; 11 | import butterknife.InjectView; 12 | 13 | public class SettingActivity extends AppCompatActivity implements Constants{ 14 | 15 | @InjectView(R.id.remote_server_ip) 16 | TextInputEditText mRemoteServerIp; 17 | @InjectView(R.id.remote_server_ip_wrapper) 18 | TextInputLayout mRemoteServerIpWrapper; 19 | @InjectView(R.id.remote_server_port) 20 | TextInputEditText mRemoteServerPort; 21 | @InjectView(R.id.remote_server_port_wrapper) 22 | TextInputLayout mRemoteServerPortWrapper; 23 | @InjectView(R.id.local_server_port) 24 | TextInputEditText mLocalServerPort; 25 | @InjectView(R.id.local_server_port_wrapper) 26 | TextInputLayout mLocalServerPortWrapper; 27 | @InjectView(R.id.remote_server_key) 28 | TextInputEditText mRemoteServerKey; 29 | @InjectView(R.id.remote_server_key_wrapper) 30 | TextInputLayout mRemoteServerKeyWrapper; 31 | @InjectView(R.id.under_lay) 32 | TextInputEditText mUnderLay; 33 | @InjectView(R.id.under_lay_wrapper) 34 | TextInputLayout mUnderLayWrapper; 35 | 36 | @Override 37 | protected void onCreate(Bundle savedInstanceState) { 38 | super.onCreate(savedInstanceState); 39 | setContentView(R.layout.activity_setting); 40 | ButterKnife.inject(this); 41 | loadOldContent(); 42 | } 43 | 44 | private void loadOldContent() { 45 | SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this); 46 | handleRestore(sharedPreferences, mRemoteServerIp, RemoteServerIp); 47 | handleRestore(sharedPreferences, mRemoteServerPort, RemoteServerPort); 48 | handleRestore(sharedPreferences, mLocalServerPort, LocalServerPort); 49 | handleRestore(sharedPreferences, mRemoteServerKey, ServerKey); 50 | handleRestore(sharedPreferences, mUnderLay, UnderLay); 51 | } 52 | 53 | @Override 54 | public void onBackPressed() { 55 | super.onBackPressed(); 56 | handleContentChange(); 57 | } 58 | 59 | private void handleRestore(SharedPreferences sharedPreferences,TextInputEditText textInputEditText, String key) { 60 | String oldStr = sharedPreferences.getString(key,""); 61 | textInputEditText.setText(oldStr); 62 | } 63 | 64 | private void handleContentChange(){ 65 | SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this); 66 | handleChange(sharedPreferences, mRemoteServerIp, RemoteServerIp); 67 | handleChange(sharedPreferences, mRemoteServerPort, RemoteServerPort); 68 | handleChange(sharedPreferences, mLocalServerPort, LocalServerPort); 69 | handleChange(sharedPreferences, mRemoteServerKey, ServerKey); 70 | handleChange(sharedPreferences, mUnderLay, UnderLay); 71 | } 72 | 73 | private void handleChange(SharedPreferences sharedPreferences,TextInputEditText textInputEditText, String key){ 74 | SharedPreferences.Editor editor = sharedPreferences.edit(); 75 | String newStr = textInputEditText.getText().toString().trim(); 76 | String oldStr = sharedPreferences.getString(key,""); 77 | if (!newStr.contentEquals(oldStr)){ 78 | editor.putString(key, newStr); 79 | editor.putBoolean(SettingChanged,true); 80 | editor.commit(); 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /app/src/main/java/com/koolwiki/goflyway_android/ShellCallback.java: -------------------------------------------------------------------------------- 1 | package com.koolwiki.goflyway_android; 2 | 3 | /** 4 | * Created by shutup on 16/7/20. 5 | */ 6 | public interface ShellCallback { 7 | public void shellOut(String shellLine); 8 | 9 | public void processComplete(int exitValue); 10 | } 11 | -------------------------------------------------------------------------------- /app/src/main/java/com/koolwiki/goflyway_android/StreamGobbler.java: -------------------------------------------------------------------------------- 1 | package com.koolwiki.goflyway_android; 2 | 3 | import android.util.Log; 4 | 5 | import java.io.BufferedReader; 6 | import java.io.IOException; 7 | import java.io.InputStream; 8 | import java.io.InputStreamReader; 9 | 10 | /** 11 | * Created by shutup on 16/7/20. 12 | */ 13 | public class StreamGobbler extends Thread{ 14 | private static final String TAG = "StreamGobbler"; 15 | InputStream is; 16 | String type; 17 | ShellCallback sc; 18 | 19 | StreamGobbler(InputStream is, String type, ShellCallback sc) { 20 | this.is = is; 21 | this.type = type; 22 | this.sc = sc; 23 | } 24 | 25 | public void run() { 26 | try { 27 | InputStreamReader isr = new InputStreamReader(is); 28 | BufferedReader br = new BufferedReader(isr); 29 | String line = null; 30 | while ((line = br.readLine()) != null) { 31 | if (sc != null) { 32 | if (BuildConfig.DEBUG) Log.d(TAG, line); 33 | sc.shellOut(line); 34 | } 35 | } 36 | } catch (IOException ioe) { 37 | // Log.e(TAG,"error reading shell slog",ioe); 38 | ioe.printStackTrace(); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /app/src/main/java/com/koolwiki/goflyway_android/service/WhiteService.java: -------------------------------------------------------------------------------- 1 | package com.koolwiki.goflyway_android.service; 2 | 3 | import android.app.Notification; 4 | import android.app.PendingIntent; 5 | import android.app.Service; 6 | import android.content.Intent; 7 | import android.os.IBinder; 8 | import android.support.v7.app.NotificationCompat; 9 | import android.util.Log; 10 | 11 | import com.koolwiki.goflyway_android.MainActivity; 12 | import com.koolwiki.goflyway_android.R; 13 | import com.koolwiki.goflyway_android.ShellCallback; 14 | 15 | 16 | public class WhiteService extends Service { 17 | 18 | private final static String TAG = WhiteService.class.getSimpleName(); 19 | 20 | private final static int FOREGROUND_ID = 1000; 21 | 22 | @Override 23 | public void onCreate() { 24 | Log.i(TAG, "WhiteService->onCreate"); 25 | super.onCreate(); 26 | } 27 | 28 | @Override 29 | public int onStartCommand(Intent intent, int flags, int startId) { 30 | Log.i(TAG, "WhiteService->onStartCommand"); 31 | 32 | NotificationCompat.Builder builder = new NotificationCompat.Builder(this); 33 | builder.setSmallIcon(R.mipmap.ic_launcher); 34 | builder.setContentTitle("Goflyway"); 35 | builder.setContentText("正在运行!"); 36 | builder.setContentInfo("运行中"); 37 | builder.setWhen(System.currentTimeMillis()); 38 | Intent activityIntent = new Intent(this, MainActivity.class); 39 | 40 | PendingIntent pendingIntent = PendingIntent.getActivity(this, 1, activityIntent, PendingIntent.FLAG_UPDATE_CURRENT); 41 | builder.setContentIntent(pendingIntent); 42 | Notification notification = builder.build(); 43 | startForeground(FOREGROUND_ID, notification); 44 | // return super.onStartCommand(intent, flags, startId); 45 | return START_STICKY; 46 | } 47 | 48 | @Override 49 | public IBinder onBind(Intent intent) { 50 | // TODO: Return the communication channel to the service. 51 | throw new UnsupportedOperationException("Not yet implemented"); 52 | } 53 | 54 | @Override 55 | public void onDestroy() { 56 | Log.i(TAG, "WhiteService->onDestroy"); 57 | super.onDestroy(); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 17 | 20 | 27 |