try
This commit is contained in:
10 files changed
+228
-33
No files matched your search
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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())
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user