众所周知(屁),Easy163通过拦截网易云的流量请求,从而实现一些比较NB的效果,比如无版权歌曲下载和付费歌曲下载。可是笔者更喜欢用倒带,而Easy163却不支持倒带,于是决定自己来试试适配倒带。

适配倒带

  先在Github仓库搜下网易云的包名,结果如下:

吆西,AS启动!

打开LocalVPNServices.java,定位到如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
{
try
{
builder.addAllowedApplication("com.netease.cloudmusic");
}catch (PackageManager.NameNotFoundException e)
{
Log.d(TAG, "未检测到网易云音乐");
}
try
{
builder.addAllowedApplication("com.netease.cloudmusic.lite");
}catch (PackageManager.NameNotFoundException e)
{
Log.d(TAG, "未检测到网易云音乐极速版");
}
}

在这一段结尾加上倒带包名:

1
2
3
4
5
6
7
8
try
{
builder.addAllowedApplication("com.kuss.rewind");
}
catch (PackageManager.NameNotFoundException e)
{
Log.d(TAG,"未检测到倒带");
}

  然后就是对数据包的处理了,这里本来是想着播放列表的请求也要拦截的,最好发现倒带对歌曲播放链接的请求机制和网易云不太一样,于是放弃对Playlist.java的修改,直接修改SongPlayHook.java。之间又发现一个小细节,倒带的请求头host是小写,而网易云请求头Host是大写,就因为这个小细节不知道浪费了我多少时间…

在SongPlayHook.java的请求判断加上下面的代码:

1
2
3
4
5
6
7
8
9
if(host != null)
{
if(method.equals("GET") && host.endsWith("music.163.com") && path.contains("/song/enhance/player/url"))
{
Log.d("check rule","Rewind");
isRewind = true;
return true;
}
}

同时,倒带的请求没有AES加密,而网易云都有AES加密,所以在hookResponse方法内加上判断,如果是倒带的请求则不采用AES加解密,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
super.hookResponse(response);
byte[] bytes = response.getContent();
Log.d("ResponseSong:",new String(bytes));
if (!isRewind)
{
bytes = Crypto.aesDecrypt(bytes);
}
JSONObject jsonObject = JSONObject.parseObject(new String(bytes));
handleNoFreeSong(jsonObject);
bytes = JSONObject.toJSONString(jsonObject, SerializerFeature.WriteMapNullValue).getBytes();
if(!isRewind)
{
bytes = Crypto.aesEncrypt(bytes);
}
Log.d("ResponseSong hooked:",new String(bytes));
response.setContent(bytes);
}

其中的isRewind是在BaseHook.java添加的布尔值变量。

还有一个小问题,倒带的请求结果JSON与网易云的也有区别,比如data数组里请求码套在了外面,所以还要在handleNoFreeSong方法里加上判断,代码跟上面判断差不多,就不放了。

看下效果:

添加通知栏快捷设置

  这个应该比上面的简单一点。新建类QuickTileService继承自TileService。由于Service内不能直接创建新VPN,所以要先判断是否已经创建过,代码如下:

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
public void onClick() {
super.onClick();
Tile tile = getQsTile();
int State = tile.getState();
if(State == Tile.STATE_INACTIVE)
{
Intent vpnIntent = VpnService.prepare(this);
if (vpnIntent != null)
{
Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
Toast.makeText(this,"请先在软件内开启一次VPN!",Toast.LENGTH_LONG).show();
return;
}
else
{
Intent intent = new Intent(this, LocalVPNService.class);
startService(intent);
}
tile.setState(Tile.STATE_ACTIVE);
}
else
{
Intent intent = new Intent("activity");
intent.putExtra("cmd", "stop");
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
Log.d("stopVPN");
}
}

然后在AndroidManifest.xml里面添加服务,代码如下:

1
2
3
4
5
6
7
8
9
10
<service android:name=".utils.QuickTileService"
android:label="@string/app_name"
android:icon="@drawable/ic_netease_cloud_music"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE"/>
</intent-filter>
<meta-data android:name="android.service.quicksettings.ACTIVE_TILE"
android:value="true"/>
</service>

编译运行看一下效果:

效果还不错,然后就可以正式打包成APK文件了。

结尾

写这篇文章加上写代码总共花了大半天时间吧,更改后的代码我会放在GitHub,并且尝试合并到原作者的项目。

下载地址:点这里
安装不上的请先卸载旧版本
已知Bug:部分情况下网易云会无法播放歌曲,清除缓存即可还是用原版吧。

都看到这里了,还不去酷安给个三连支持一下?