This commit is contained in:
Kr328 committed 2019-11-15 16:21:24 +08:00
1 parent fa6e5841bf
commit e624618be6
10 files changed
+228 -33

No files matched your search

+7 -3
View File
@@ -1,14 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.github.kr328.clash">
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:allowBackup="false"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
android:theme="@style/AppTheme"
tools:ignore="GoogleAppIndexingWarning">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@@ -16,6 +20,6 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".ClashService" android:exported="false" android:process=":clash" />
</application>
</manifest>
@@ -0,0 +1,6 @@
// IClashService.aidl
package com.github.kr328.clash;
interface IClashService {
void loadProfile(String path);
}
@@ -0,0 +1,46 @@
package com.github.kr328.clash
import android.app.Service
import android.content.Intent
import android.os.IBinder
import android.os.RemoteException
import android.util.Log
import com.github.kr328.clash.core.Clash
import com.github.kr328.clash.core.ClashException
import java.io.File
import kotlin.concurrent.thread
class ClashService : Service() {
private val binder = object: IClashService.Stub() {
override fun loadProfile(path: String?) {
if ( path == null || !File(path).exists() )
throw RemoteException("Invalid path")
thread {
try {
Clash.loadProfileFromPath(path)
}
catch (e: ClashException) {
Log.w("ClashForAndroid", "Load failure", e)
}
}
}
}
override fun onCreate() {
super.onCreate()
Clash.init(filesDir.resolve("clash").absolutePath)
Clash.loadDefault()
}
override fun onBind(intent: Intent?): IBinder? {
return binder
}
override fun onDestroy() {
Clash.loadDefault()
super.onDestroy()
}
}
@@ -1,14 +1,65 @@
package com.github.kr328.clash
import androidx.appcompat.app.AppCompatActivity
import android.app.Activity
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.os.Bundle
import com.github.kr328.clash.core.Clash
import android.os.IBinder
import android.util.Log
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_main.*
import java.io.FileOutputStream
import java.lang.Exception
import java.lang.RuntimeException
import kotlin.concurrent.thread
class MainActivity : AppCompatActivity() {
companion object {
private const val REQUEST_CODE = 233
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
Clash.loadDefault()
button.setOnClickListener {
startActivityForResult(Intent(Intent.ACTION_GET_CONTENT).setType("*/*"), REQUEST_CODE)
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if ( requestCode == REQUEST_CODE && resultCode == Activity.RESULT_OK ) {
Toast.makeText(this, intent?.dataString, Toast.LENGTH_LONG).show()
thread {
FileOutputStream(cacheDir.resolve("config.yaml")).use {
contentResolver.openInputStream(data?.data ?: throw RuntimeException())?.apply { copyTo(it) }?.close()
}
bindService(Intent(this, ClashService::class.java), object: ServiceConnection {
override fun onServiceDisconnected(name: ComponentName?) {
Toast.makeText(this@MainActivity, "Disconnected", Toast.LENGTH_LONG).show()
}
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
try {
val clash = IClashService.Stub.asInterface(service)
clash.loadProfile(cacheDir.resolve("config.yaml").absolutePath)
}
catch (e: Exception) {
Log.e("ClashForAndroid", "Load", e)
}
}
}, Context.BIND_AUTO_CREATE)
}
}
else {
super.onActivityResult(requestCode, resultCode, data)
}
}
}
+7 -7
View File
@@ -6,13 +6,13 @@
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
<Button
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
android:text="Open" />
</androidx.constraintlayout.widget.ConstraintLayout>
+44
View File
@@ -0,0 +1,44 @@
package main
/*
#ifndef JNI_COMPILE
#define JNI_COMPILE
#include <jni.h>
#include <string.h>
#define CLASH_EXCEPTION_CLASS "com/github/kr328/clash/core/ClashException"
extern const char *_GoStringPtr(_GoString_ s);
static void jni_throw_clash_exception(JNIEnv *env, _GoString_ message) {
(*env)->ThrowNew(env, CLASH_EXCEPTION_CLASS, _GoStringPtr(message));
}
static char *jni_get_string(JNIEnv *env, jstring string) {
const char *jni_string = (*env)->GetStringUTFChars(env, string, NULL);
char *result = strdup(jni_string);
(*env)->ReleaseStringUTFChars(env, string, jni_string);
return result;
}
#endif //JNI_COMPILE
*/
import "C"
import (
"github.com/Dreamacro/clash/constant"
)
//export Java_com_github_kr328_clash_core_Clash_init
func Java_com_github_kr328_clash_core_Clash_init(env *C.JNIEnv, class C.jclass, home C.jstring) {
cs := C.jni_get_string(env, home)
if cs == nil {
C.jni_throw_clash_exception(env, "Unable to get path")
return
}
p := C.GoString(cs)
C.free(unsafe.Pointer(cs))
constant.SetHomeDir(p)
}
+45 -3
View File
@@ -1,9 +1,34 @@
package main
//#include <jni.h>
/*
#ifndef JNI_COMPILE
#define JNI_COMPILE
#include <jni.h>
#include <string.h>
#define CLASH_EXCEPTION_CLASS "com/github/kr328/clash/core/ClashException"
extern const char *_GoStringPtr(_GoString_ s);
static void jni_throw_clash_exception(JNIEnv *env, _GoString_ message) {
(*env)->ThrowNew(env, CLASH_EXCEPTION_CLASS, _GoStringPtr(message));
}
static char *jni_get_string(JNIEnv *env, jstring string) {
const char *jni_string = (*env)->GetStringUTFChars(env, string, NULL);
char *result = strdup(jni_string);
(*env)->ReleaseStringUTFChars(env, string, jni_string);
return result;
}
#endif //JNI_COMPILE
*/
import "C"
import "github.com/kr328/clash-for-android/log"
import "github.com/kr328/clash-for-android/profile"
import "unsafe"
import (
"github.com/kr328/clash-for-android/log"
"github.com/kr328/clash-for-android/profile"
)
//export Java_com_github_kr328_clash_core_Clash_loadDefault
func Java_com_github_kr328_clash_core_Clash_loadDefault(env *C.JNIEnv, class C.jclass) {
@@ -11,3 +36,20 @@ func Java_com_github_kr328_clash_core_Clash_loadDefault(env *C.JNIEnv, class C.j
profile.LoadDefault()
}
//export Java_com_github_kr328_clash_core_Clash_loadProfileFromPath
func Java_com_github_kr328_clash_core_Clash_loadProfileFromPath(env *C.JNIEnv, class C.jclass, path C.jstring) {
cs := C.jni_get_string(env, path)
if cs == nil {
C.jni_throw_clash_exception(env, "Unable to get path")
return
}
p := C.GoString(cs)
C.free(unsafe.Pointer(cs))
if err := profile.LoadFromFile(p); err != nil {
C.jni_throw_clash_exception(env, err.Error())
}
}
+10 -17
View File
@@ -8,35 +8,28 @@ package log
#define TAG "ClashForAndroid"
static void log_info(const char *msg) {
__android_log_print(ANDROID_LOG_INFO, "ClashForAndroid", "%s", msg);
static void log_info(_GoString_ msg) {
__android_log_print(ANDROID_LOG_INFO, "ClashForAndroid", "%s", _GoStringPtr(msg));
}
static void log_error(const char *msg) {
__android_log_print(ANDROID_LOG_ERROR, "ClashForAndroid", "%s", msg);
static void log_error(_GoString_ msg) {
__android_log_print(ANDROID_LOG_ERROR, "ClashForAndroid", "%s", _GoStringPtr(msg));
}
static void log_warn(const char *msg) {
__android_log_print(ANDROID_LOG_WARN, "ClashForAndroid", "%s", msg);
static void log_warn(_GoString_ msg) {
__android_log_print(ANDROID_LOG_WARN, "ClashForAndroid", "%s", _GoStringPtr(msg));
}
*/
import "C"
import "unsafe"
func Info(msg string) {
log := C.CString(msg)
C.log_info(log)
C.free(unsafe.Pointer(log))
C.log_info(msg)
}
func Error(msg string) {
log := C.CString(msg)
C.log_error(log)
C.free(unsafe.Pointer(log))
C.log_error(msg)
}
func Warn(msg string) {
log := C.CString(msg)
C.log_warn(log)
C.free(unsafe.Pointer(log))
}
C.log_warn(msg)
}
@@ -1,7 +1,9 @@
package com.github.kr328.clash.core;
public final class Clash {
public static native void init(String home);
public static native void loadDefault();
public static native void loadProfileFromPath(String path) throws ClashException;
static {
System.loadLibrary("clash");
@@ -0,0 +1,7 @@
package com.github.kr328.clash.core;
public class ClashException extends Exception {
public ClashException(String message) {
super(message);
}
}