SOUL ANDROID APP 悬浮VIEW以及帖子中VIEW的联动刷新逆向分析

简介:

SOUL ANDROID APP 悬浮VIEW以及帖子中VIEW的联动刷新逆向分析

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。通过他们可以实现一些棘手的问题。

原文地址https://www.cnblogs.com/xing-star/p/12768379.html

相关文章
|
16天前
|
安全 Android开发 数据安全/隐私保护
深入探讨iOS与Android系统安全性对比分析
在移动操作系统领域,iOS和Android无疑是两大巨头。本文从技术角度出发,对这两个系统的架构、安全机制以及用户隐私保护等方面进行了详细的比较分析。通过深入探讨,我们旨在揭示两个系统在安全性方面的差异,并为用户提供一些实用的安全建议。
|
1月前
|
XML Java 数据库
安卓项目:app注册/登录界面设计
本文介绍了如何设计一个Android应用的注册/登录界面,包括布局文件的创建、登录和注册逻辑的实现,以及运行效果的展示。
147 0
安卓项目:app注册/登录界面设计
|
25天前
|
缓存 Java Shell
Android 系统缓存扫描与清理方法分析
Android 系统缓存从原理探索到实现。
48 15
Android 系统缓存扫描与清理方法分析
|
11天前
|
开发框架 监控 .NET
【Azure App Service】部署在App Service上的.NET应用内存消耗不能超过2GB的情况分析
x64 dotnet runtime is not installed on the app service by default. Since we had the app service running in x64, it was proxying the request to a 32 bit dotnet process which was throwing an OutOfMemoryException with requests >100MB. It worked on the IaaS servers because we had the x64 runtime install
|
2月前
|
Java 数据库 Android开发
一个Android App最少有几个线程?实现多线程的方式有哪些?
本文介绍了Android多线程编程的重要性及其实现方法,涵盖了基本概念、常见线程类型(如主线程、工作线程)以及多种多线程实现方式(如`Thread`、`HandlerThread`、`Executors`、Kotlin协程等)。通过合理的多线程管理,可大幅提升应用性能和用户体验。
126 15
一个Android App最少有几个线程?实现多线程的方式有哪些?
|
1月前
|
存储 Linux Android开发
Android底层:通熟易懂分析binder:1.binder准备工作
本文详细介绍了Android Binder机制的准备工作,包括打开Binder驱动、内存映射(mmap)、启动Binder主线程等内容。通过分析系统调用和进程与驱动层的通信,解释了Binder如何实现进程间通信。文章还探讨了Binder主线程的启动流程及其在进程通信中的作用,最后总结了Binder准备工作的调用时机和重要性。
Android底层:通熟易懂分析binder:1.binder准备工作
|
2月前
|
安全 Android开发 数据安全/隐私保护
探索安卓与iOS的安全性差异:技术深度分析与实践建议
本文旨在深入探讨并比较Android和iOS两大移动操作系统在安全性方面的不同之处。通过详细的技术分析,揭示两者在架构设计、权限管理、应用生态及更新机制等方面的安全特性。同时,针对这些差异提出针对性的实践建议,旨在为开发者和用户提供增强移动设备安全性的参考。
138 3
|
2月前
|
Android开发 开发者 索引
Android实战经验之如何使用DiffUtil提升RecyclerView的刷新性能
本文介绍如何使用 `DiffUtil` 实现 `RecyclerView` 数据集的高效更新,避免不必要的全局刷新,尤其适用于处理大量数据场景。通过定义 `DiffUtil.Callback`、计算差异并应用到适配器,可以显著提升性能。同时,文章还列举了常见错误及原因,帮助开发者避免陷阱。
187 9
|
2月前
|
存储 开发工具 Android开发
使用.NET MAUI开发第一个安卓APP
【9月更文挑战第24天】使用.NET MAUI开发首个安卓APP需完成以下步骤:首先,安装Visual Studio 2022并勾选“.NET Multi-platform App UI development”工作负载;接着,安装Android SDK。然后,创建新项目时选择“.NET Multi-platform App (MAUI)”模板,并仅针对Android平台进行配置。了解项目结构,包括`.csproj`配置文件、`Properties`配置文件夹、平台特定代码及共享代码等。
164 2
|
1月前
|
开发工具 Android开发 Swift
安卓与iOS开发环境的差异性分析
【10月更文挑战第8天】 本文旨在探讨Android和iOS两大移动操作系统在开发环境上的不同,包括开发语言、工具、平台特性等方面。通过对这些差异性的分析,帮助开发者更好地理解两大平台,以便在项目开发中做出更合适的技术选择。