【问题标题】:Android MediaProjectionManager in Service服务中的 Android MediaProjectionManager
【发布时间】:2015-11-29 15:10:28
【问题描述】:

我想构建一个必须在服务中使用 MediaProjectionManager 的应用程序。但我无法解决它,因为“startActivityForResult”不能在服务类中使用。

【问题讨论】:

  • 您需要有一个活动,用户可以指示他们希望您开始录制屏幕截图或截屏视频,然后您可以使用startActivityForResult()。我不知道有任何方法可以请求不涉及startActivityForResult()MediaProjection
  • 我必须为一些特定的应用程序截屏。所以我必须从服务中检测应用程序,并且必须使用 MediaProjection 截取屏幕截图。如果可以,请举个例子。我是初学者。谢谢
  • 你想要的实际上是不可能的。用户必须在开始记录时参与。此外,谷歌一直在逐步锁定检测前台应用程序的能力。在这一点上(Android 6.0),可以肯定地说,如果一个应用程序可以确定其他应用程序在前台,则存在需要修复的安全漏洞。
  • 实际上用户只需要在Android提示时同意授予安全令牌。如果用户信任该应用,“不要再问我”将赋予该应用随意获取令牌的能力。我有一个类似的应用程序,当目标应用程序不在前台时,它会释放令牌,然后在目标应用程序重新获得焦点时重新请求它。我这样做是因为如果我是该应用的用户,我想知道它只会在我需要时主动监控屏幕。

标签: android service broadcastreceiver android-mediaprojection


【解决方案1】:

我真的很想从服务中做到这一点,这就是我发现这个问题的方式。这是我提出的最接近的方法,所以把它扔在那里,直到出现更好的答案。这是一种通过 Activity 执行此操作的方法,几乎​​就像通过服务执行此操作:

import static your.package.YourClass.mediaProjectionManager;

public class MainActivity extends Activity {

@Override
protected void onCreate(final Bundle savedInstanceState) {
    super.onCreate(null);
    mediaProjectionManager = (MediaProjectionManager)getContext().getSystemService(MEDIA_PROJECTION_SERVICE);
    startActivityForResult(mediaProjectionManager.createScreenCaptureIntent(), 1);
    }

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == 1) {
        if (resultCode == Activity.RESULT_OK) {
            mediaProjection = mediaProjectionManager.getMediaProjection(resultCode, data);
            this.finish();
        }
    }
}

然后在您需要权限调用时为您服务

private void openMainActivity() {
    Intent mainIntent = new Intent(getContext(), MainActivity.class);
    mainIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    startActivity(mainIntent);
    }

使活动在您的 AndroidManifest.xml 中不可见

    <activity
        android:name=".MainActivity"
        android:label="@string/app_name"
        android:theme="@android:style/Theme.NoDisplay"
        android:excludeFromRecents="true"
        android:screenOrientation="portrait">
    </activity>

注意事项:

您正在截屏的应用程序会在短时间内失去焦点。

您的应用将在短时间内成为前台应用,所以不要绊倒自己的鞋带

【讨论】:

【解决方案2】:

好的,我已经设法做到了,这不是最干净的方法,但有效:

  1. 本地绑定服务:将您的服务设为Local Bound Service,这意味着您的服务会将自身的引用传递给主活动。
  2. 将 Activity 的实例传递给服务:将您的活动的引用传递给服务连接中的服务-> Activity 类中的 onServiceConnected()
  3. 调用 startActivityForResult:使用服务中的 Activity 实例调用 startActivityForResult 函数。

注意: 调用 startActivityForResult 后,将在 Activity 类的 onActivityResult() 中捕获。您将需要在 Activity 中覆盖此函数并使用服务引用返回到服务类。您还可以在完成后从服务中取消绑定 Activity。

我希望这是有道理的,很抱歉没有包含任何代码。如果您有任何问题,我们很乐意为您提供更详细的帮助。

【讨论】:

  • 仅当活动仍在运行时。即使没有活动,服务也可以运行
【解决方案3】:

我使用了与这里相同的方法https://medium.com/@debuggingisfun/android-10-audio-capture-77dd8e9070f9
在我的活动中:

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Intent intent = new Intent(this, MediaProjectionService.class);
    startForegroundService(intent);
    mProjectionManager =
            (MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE);
    startActivityForResult(mProjectionManager.createScreenCaptureIntent(),
            1);
}

服务本身只是一些样板,如果您想在前台运行,则需要通知

class MediaProjectionService : Service() {

    override fun onCreate() {
        super.onCreate()
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val builder = NotificationCompat.Builder(this, "messages")
                    .setContentText("streaming enabled")
                    .setContentTitle("Stream to e-ink")
            startForeground(101, builder.build())
        }
    }

    override fun onBind(intent: Intent): IBinder? {
        return null
    }
}

我不是安卓专家,我正在使用 Flutter - 显然你还需要先创建一个通知通道 - 这是我的 Flutter 应用程序代码 - 它可能与非 Flutter 类似

class StreaminkApplication : FlutterApplication() {
    override fun onCreate() {
        super.onCreate()
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val channel = NotificationChannel("messages", "Messages", NotificationManager.IMPORTANCE_LOW)
            val manager = getSystemService(NotificationManager::class.java)
            manager.createNotificationChannel(channel)
        }
    }
}

如果您使用应用程序,您应该在清单中更改它 - 在我的情况下:

<application
    android:name=".StreaminkApplication"

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-13
    相关资源
    最近更新 更多