Support library for easier development on shadowsocks plugin for Android. Also includes some useful resources to easily get consistent styling with the main app.
These are some plugins ready to use on shadowsocks-android.
WARNING: This library is still in beta (0.x) and its content is subject to massive changes.
This library is designed with Java interoperability in mind so theoretically you can use this library with other languages and/or build tools but there isn't documentation for that yet. This guide is written for Scala + SBT. Contributions are welcome.
There are no arbitrary restrictions/requirements on package name, component name and content
provider authority, but you're suggested to follow the format in this documentations. For package
name, use com.github.shadowsocks.plugin.$PLUGIN_ID
if it only contains a single plugin to
prevent duplicated plugins. In some places hyphens are not accepted, for example package name. In
that case, hyphens -
should be changed into underscores _
. For example, the package name for
obfs-local
would probably be com.github.shadowsocks.plugin.obfs_local
.
First you need to add this library to your dependencies. This library is written mostly in Scala and it's most convenient to use it with SBT:
libraryDependencies += "com.github.shadowsocks" %% "plugin" % "0.0.4"
First you need to get your native binary compiling on Android platform.
In addition to functionalities of a normal plugin, it has to support these additional flags that may get passed through arguments:
-V
: VPN mode. In this case, the plugin should pass all file descriptors that needs protecting from VPN connections (i.e. its traffic will not be forwarded through the VPN) through an ancillary message to./protect_path
;--fast-open
: TCP fast open enabled.
It's super easy. You just need to implement two or three methods. For example for obfs-local
:
final class BinaryProvider extends NativePluginProvider {
override protected def populateFiles(provider: PathProvider) {
provider.addPath("obfs-local", "755")
// add additional files here
}
// remove this method to disable fast mode, read more in the documentation
override def getExecutable: String =
getContext.getApplicationInfo.nativeLibraryDir + "/libobfs-local.so"
override def openFile(uri: Uri): ParcelFileDescriptor = uri.getPath match {
case "/obfs-local" =>
ParcelFileDescriptor.open(new File(getExecutable), ParcelFileDescriptor.MODE_READ_ONLY)
// handle additional files here
case _ => throw new FileNotFoundException()
}
}
Then add it to your manifest:
<manifest>
...
<application>
...
<provider android:name=".BinaryProvider"
android:exported="true"
android:authorities="$FULLY_QUALIFIED_NAME_OF_YOUR_CONTENTPROVIDER">
<intent-filter>
<action android:name="com.github.shadowsocks.plugin.ACTION_NATIVE_PLUGIN"/>
</intent-filter>
<intent-filter>
<action android:name="com.github.shadowsocks.plugin.ACTION_NATIVE_PLUGIN"/>
<data android:scheme="plugin"
android:host="com.github.shadowsocks"
android:pathPrefix="/$PLUGIN_ID"/>
</intent-filter>
<meta-data android:name="com.github.shadowsocks.plugin.id"
android:value="$PLUGIN_ID"/>
<meta-data android:name="com.github.shadowsocks.plugin.default_config"
android:value="dummy=default;plugin=options"/>
</provider>
...
</application>
</manifest>
You should add to your plugin app a configuration activity or a help activity or both if you're
going to use ConfigurationActivity.fallbackToManualEditor
.
This is used if found instead of a manual input dialog when user clicks "Configure..." in the main
app. This gives you maximum freedom of the user interface. To implement this, you need to extend
ConfigurationActivity
and you will get current options via
onInitializePluginOptions(PluginOptions)
and you can invoke saveChanges(PluginOptions)
or
discardChanges()
before finish()
or fallbackToManualEditor()
. Then add it to your manifest:
<manifest>
...
<application>
...
<activity android:name=".ConfigActivity">
<intent-filter>
<action android:name="com.github.shadowsocks.plugin.ACTION_CONFIGURE"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:scheme="plugin"
android:host="com.github.shadowsocks"
android:path="/$PLUGIN_ID"/>
</intent-filter>
</activity>
...
</application>
</manifest>
This is started when user taps "?" in manual editor. To implement this, you need to extend
HelpCallback
if you want a simple dialog with help message as CharSequence
or HelpActivity
if you want to provide custom user interface, implement the required methods, then add it to your
manifest:
<manifest>
...
<application>
...
<activity android:name=".HelpActivity">
<intent-filter>
<action android:name="com.github.shadowsocks.plugin.ACTION_HELP"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:scheme="plugin"
android:host="com.github.shadowsocks"
android:path="/$PLUGIN_ID"/>
</intent-filter>
</activity>
...
</application>
</manifest>
Great. Now your plugin is ready to use.