Soul app是我司的竞品,对它的语音音乐播放同步联动的逻辑很感兴趣,于是就开启了一波逆向分析。

下面看代码,以及技术分析,直接步入正轨,哈哈。

我们根据https://github.com/xingstarx/ActivityTracker 这个工具,找到某一个页面,比如cn.soulapp.android/.ui.post.detail.PostDetailActivity 这个页面,然后我们用反编译工具AndroidToolPlus反编译soul 的Android apk, 然后搜索下PostDetailActivity这个类。然后找到这个类之后,我们在根据代码经验猜测,这个语音音乐封装的控件可能在哪,肯定是在PostDetailActivity里面或者是他内容的某个成员变量里面,一不小心,我们就找到了PostDetailHeaderProvider。在这个类里面找到了MusicStoryPlayView, AudioPostView这两个view类,他们就是封装好的音频view,音乐view。(就不截图了。有人感兴趣可以按照我说的实践一番就能得到结论了)

关键代码找到了。那就看看他们内部实现吧。

public class MusicStoryPlayView
extends FrameLayout
implements SoulMusicPlayer.MusicPlayListener

类结构上,实现了核心播放器的listener逻辑,那就说明,他的刷新逻辑,都是通过播放器自身的播放状态回调到view自身上,然后view自身实现了对应的刷新机制就可以更改view的状态了

我们选取几个回调的逻辑看看。不做仔细分析。

 public void onPause(cn.soulapp.android.lib.common.c.i parami)
{
d();
} public void onPlay(cn.soulapp.android.lib.common.c.i parami)
{
LoveBellingManager.e().d();
} public void onPrepare(cn.soulapp.android.lib.common.c.i parami)
{
if (this.e == null) {
return;
}
if (parami.b().equals(this.e.songMId)) {
e();
}
}

那么我们还得思考一个问题,这个listener是什么时候被添加进来的呢。关键点在于view自身的两个方法

  protected void onAttachedToWindow()
{
super.onAttachedToWindow();
SoulMusicPlayer.k().a(this);
} protected void onDetachedFromWindow()
{
super.onDetachedFromWindow();
SoulMusicPlayer.k().b(this);
}

所以很明显,在view被添加到window上(也就是在页面上显示出来)的时候,添加入listener里面,从页面消失,就移除出去。

接着我们在看看核心播放器的逻辑里面,是怎么调度的?

根据代码相关联的逻辑,我们很容易找到核心播放器类SoulMusicPlayer

 public void a(cn.soulapp.android.lib.common.c.i parami)
{
y0.d().a();
LoveBellingManager.e().d();
MusicPlayer.i().f();
if (TextUtils.isEmpty(parami.f())) {
return;
}
Object localObject1 = this.d;
if (localObject1 != null) {
if (!((cn.soulapp.android.lib.common.c.i)localObject1).equals(parami))
{
i();
}
else
{
if (!f())
{
this.a.setLooping(parami.g());
h();
}
return;
}
}
if (this.a == null)
{
this.a = new IjkMediaPlayer();
this.a.setOnErrorListener(this);
this.a.setOnCompletionListener(this);
this.a.setOnPreparedListener(this);
}
this.a.setLooping(parami.g());
try
{
if (l0.e(parami.f()))
{
SoulApp localSoulApp;
Object localObject2;
if (parami.a() != null)
{
localObject1 = this.a;
localSoulApp = SoulApp.e();
localObject2 = new java/io/File;
((File)localObject2).<init>(parami.f());
((IjkMediaPlayer)localObject1).setDataSource(localSoulApp, Uri.fromFile((File)localObject2), parami.a());
}
else
{
localObject2 = this.a;
localSoulApp = SoulApp.e();
localObject1 = new java/io/File;
((File)localObject1).<init>(parami.f());
((IjkMediaPlayer)localObject2).setDataSource(localSoulApp, Uri.fromFile((File)localObject1));
}
}
else
{
localObject1 = parami.a();
if (localObject1 != null) {
this.a.setDataSource(SoulApp.e(), Uri.parse(parami.f().replace("https", "http")), parami.a());
} else {
this.a.setDataSource(SoulApp.e(), Uri.parse(parami.f().replace("https", "http")));
}
}
this.a.prepareAsync();
this.d = parami;
this.b = true;
}
catch (IOException parami)
{
parami.printStackTrace();
}
}
 public void g()
{
if (f())
{
Object localObject = this.a;
if (localObject != null)
{
this.b = false;
((IjkMediaPlayer)localObject).pause();
localObject = this.e.iterator();
while (((Iterator)localObject).hasNext()) {
((MusicPlayListener)((Iterator)localObject).next()).onPause(this.d);
}
this.c.removeCallbacksAndMessages(null);
}
}
}

仔细观察分析这两个方法体,大致可以猜测出,他们是start逻辑,以及暂停播放的逻辑。可以分析出,核心播放器执行完播放,暂停,停止等逻辑后,都会调用List里面的listener,遍历listener,然后触发对应的回调逻辑。

恩,大体的思路有了,就是这么搞,哈哈。

那么我用于我自己项目中,是这么用的么,还是有一些细微差异的,整体方案是参考的soul。细微不同之处在于我是将MusicStoryPlayView放在xml里面,不是像soul那样,直接new的。所以MusicStoryPlayView会被添加很多次,比如在列表中有很多个的话,后面需要判断播放的媒体资源,跟MusicStoryPlayView存放的媒体资源的主键是否一致。

此外出了view类,我对于一些特殊的逻辑,比如Activity或者是悬浮view等等,都实现了PlayListener。通过他们可以实现一些棘手的问题。

好了,本篇到此结束,如果大家有疑问,欢迎留言交流。

Soul Android app 悬浮view以及帖子中view的联动刷新逆向分析的更多相关文章

  1. 通过Hack方式实现SDC中Stage配置联动刷新

    目录 问题描述 如何从外部获取下拉列表参数 如何实现根据下拉列表选项动态刷新 总结 问题描述 最近项目组准备开发一个IoT平台项目,需要使用到StreamSets DataCollector组件进行数 ...

  2. 写给Android App开发人员看的Android底层知识(2)

    (五)AMS 如果站在四大组件的角度来看,AMS就是Binder中的Server. AMS全称是ActivityManagerService,看字面意思是管理Activity的,但其实四大组件都归它管 ...

  3. MAC安裝《Genymotion Android模擬器》大玩Android APP (神魔之塔)

    链接地址:http://www.minwt.com/mac/10083.html/comment-page-2 MAC» 智慧型裝罝» Android | 2014/02/12 Android是一個開 ...

  4. Android app启动耗时分析

    前言 app启动耗时过长的话,无论你的app里面的内容多么丰富有趣,作为一个用户,首先是没有耐心去等待的,如果我是一个用户,我会这样想:这是什么垃圾公司出的什么烂app,再等2s不进来就卸载,黑人问号 ...

  5. Android悬浮框,在Service中打开悬浮窗;在Service中打开Dialog;

    文章介绍了如何在Service中显示悬浮框,在Service中弹出Dialog,在Service中做耗时的轮询操作: 背景需求: 公司的项目现在的逻辑是这样的:发送一个指令,然后3秒一次轮询去查询这个 ...

  6. Android无需权限显示悬浮窗, 兼谈逆向分析app

    前言 最近UC浏览器中文版出了一个快速搜索的功能, 在使用其他app的时候, 如果复制了一些内容, 屏幕顶部会弹一个窗口, 提示一些操作, 点击后跳转到UC, 显示这个悬浮窗不需要申请android. ...

  7. Android中View的绘制过程 onMeasure方法简述 附有自定义View例子

    Android中View的绘制过程 onMeasure方法简述 附有自定义View例子 Android中View的绘制过程 当Activity获得焦点时,它将被要求绘制自己的布局,Android fr ...

  8. Android中 View not attached to window manager错误的解决办法

    前几日出现这样一个Bug是一个RuntimeException,详细信息是这样子的:java.lang.IllegalArgumentException: View not attached to w ...

  9. 源码解析Android中View的measure量算过程

    Android中的Veiw从内存中到呈现在UI界面上需要依次经历三个阶段:量算 -> 布局 -> 绘图,关于View的量算.布局.绘图的总体机制可参见博文< Android中View ...

随机推荐

  1. OpenCV-Python 轮廓属性 | 二十三

    目标 在这里,我们将学习提取一些常用的物体属性,如坚实度,等效直径,掩模图像,平均强度等.更多的功能可以在Matlab regionprops文档中找到. (注:质心.面积.周长等也属于这一类,但我们 ...

  2. 成为视频分析专家:自动生成视频集锦(Python实现)

    介绍 我是个超级板球迷.从我记事起,我就迷上了这项运动,至今它仍在我的日常生活中起着重要的作用.我相信很多读到这篇文章的人都会点头! 但是自从我开始工作以来,要跟上所有的比赛就成了一件棘手的事.我不能 ...

  3. “GANs”与“ODEs”:数学建模的终结?

    在本文中,我想将经典数学建模和机器学习之间建立联系,它们以完全不同的方式模拟身边的对象和过程.虽然数学家基于他们的专业知识和对世界的理解来创建模型,而机器学习算法以某种隐蔽的不完全理解的方式描述世界, ...

  4. [RH134] 10-NFS和Samba客户端

    NFS和samba服务器的配置,请参考: 这里,我们只讨论客户端的使用 1.NFS客户端的使用 nfs实现的是类Unix系统之间的远程共享目录. 假设我们已经有一个提供nfs服务的服务器,IP为192 ...

  5. 来讨论一下这些常见的 Redis 面试题

    Redis应该算面试中必问的一个知识点,但是发现很多童鞋并不熟悉这块,这篇就常见的一些问题做一些整理,有不对的地方欢迎留言指正! 1.Redis支持的数据类型? String(字符串) 格式: set ...

  6. Downgrade ASM DATABASE_COMPATIBILITY (from 11.2.0.4.0 to 11.2.0.0.0) on 12C CRS stack.

    使用Onecommand完成快速Oracle 12c RAC部署后 发现ASM database compatibilty无法设置,默认为11.2.0.4.0. 由于我们还有些数据库低于这个版本,所以 ...

  7. [HDU2546]饭卡<dp 01背包>

    链接:http://acm.hdu.edu.cn/showproblem.php?pid=2546 #题目描述: 电子科大本部食堂的饭卡有一种很诡异的设计,即在购买之前判断余额.如果购买一个商品之前, ...

  8. python使用镜像源安装库

    pip install django -i http://pypi.douban.com/simple --trusted-host pypi.douban.com 豆瓣 :http://pypi.d ...

  9. 关于k12领域Lucene.net+pangu搜索引擎设计开发的一些回顾

    在中国最大的教育资源门户网站两年期间, 黄药师负责学科网搜吧的设计与开发…正好赶上了公司飞速发展的阶段.. 作为专注于k12领域内容与服务的互联网公司的一员,同时整个公司又在积极提升用户体验的氛围中, ...

  10. Html,css构建一个对话框,练习201911281028

    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/stri ...