作为System.Drawing.Bitmap(Xamarin)从背景应用程序的iOS屏幕截图

对于越狱的iOS设备上的私人应用程序 (=不在任何应用程序上发布),我需要将整个屏幕的屏幕截图发送到后台。

类似的问题已经发布

  • iOS:作为后台任务运行时可以截屏吗? 其结论是,由于iOS的安全沙箱,在非越狱设备上是不可能的
  • 如何从背景应用程序运行iPhone的屏幕截图? 尚未完成,但也似乎是针对非越狱设备
  • 如何在越狱iOS设备上截屏整个屏幕? (和有些类似越狱iOS从后台应用程序截图 )似乎接近我所寻找的,但代码是在Objective C中编写的,并使用一个神秘的私人函数_UICreateScreenUIImage() ,我不知道它定义了哪个模块(所以我不知道如何声明它是一个外部函数)。 此外,屏幕截图以UIImage的forms返回(请参阅http://developer.xamarin.com/api/type/MonoTouch.UIKit.UIImage/ ),但我不知道如何将其转换为System.Drawing.Bitmap(请参阅https://developer.xamarin.com/api/type/System.Drawing.Bitmap/ )。

以下是我的代码的职位。 我正在寻找与private System.Drawing.Bitmap ShootScreen()的实施帮助

 using System; using System.Collections.Generic; using System.Drawing; using System.Threading; namespace StackOverflowSnippets { public sealed class ScreenshooterThread { private Thread _t = null; // Thread-Object: Execution-Helper private Boolean _terminate = false; // Stop current execution? private Int32 _intervalMS = 0; // Take Screenshots every ? MS private Queue<Bitmap> _q; // Queue to store the Screenshots #region Interface /// <summary> /// Creates a Screenshooter /// </summary> /// <param name="intervalMS">Defines every how many MS a screenshot should be taken</param> public ScreenshooterThread(Int32 intervalMS = 200) { _intervalMS = intervalMS; } /// <summary> /// Starts taking Screenshots /// </summary> public void Run() { if(this.IsRunning || this.IsTerminating) { throw new InvalidOperationException("ScreenshooterThread is currently running or terminating"); } lock (this) { _terminate = false; _t = new Thread(this.DoWork); _t.Start(); } } /// <summary> /// Stops taking Screenshots /// </summary> public void Stop() { if (!this.IsRunning) return; if (this.IsTerminating) return; lock(this) { _terminate = true; } } /// <summary> /// Determines whether the Thread is currently running /// </summary> public Boolean IsRunning { get { if (_t == null) return false; return _t.IsAlive; } } /// <summary> /// Determines whether Thread-Termination has been invoked /// </summary> public Boolean IsTerminating { get { return _terminate; } } /// <summary> /// Get a Screenshot from the Queue. Returns null if none available /// </summary> public Bitmap Deqeue() { lock(_q) { if (_q.Count < 1) return null; return _q.Dequeue(); } } #endregion #region Implementation Details /// <summary> /// Add a Screenshot to the Queue /// </summary> private void Enqueue(Bitmap b) { lock(_q) { _q.Enqueue(b); } } /// <summary> /// Task-Implementation while running /// </summary> private void DoWork() { while(!_terminate) { if (_intervalMS > 0) Thread.Sleep(_intervalMS); this.Enqueue(this.ShootScreen()); } this.CleanUp(); } /// <summary> /// Takes a Screenshot of the device even if the app is in the Background /// </summary> private System.Drawing.Bitmap ShootScreen() { // System.Drawing.Bitmap supported by Xamarin // https://developer.xamarin.com/api/type/System.Drawing.Bitmap/ // Method in ObjC: https://stackoverflow.com/questions/33369014/how-to-take-screenshot-of-entire-screen-on-a-jailbroken-ios-device throw new NotImplementedException(); } /// <summary> /// Preparing for next launch /// </summary> private void CleanUp() { lock(this) { _terminate = false; _t = null; } } #endregion } } 

PS:屏幕截图需要是一个System.Drawing.Bitmap因为我需要在其上执行Pixelwise操作

编辑1

经进一步调查,我发现http://sharpmobilecode.com/introduction-to-xamarin-what-it-is-what-it-isnt/下面的段落

例如,假设您有现有的使用System.Drawing.Bitmap的C#代码。 这是一个共同的库,你写了多个桌面应用程序参考。 一个可能的方法看起来像这样:

 using System.Drawing; public Bitmap GetBitmapFromCache(string fileName) { return (Bitmap) Image.FromFile(fileName); } 

如果你要在Xamarin.iOS或Xamarin.Android应用程序中编译这个方法,你会得到一个编译错误。 咦? 经过进一步的调查,你会发现System.Drawing.BitmapSystem.Drawing.Image没有定义。 什么!?!? 这是有效的C#语法! 在进一步的调查中,您只能看到System.Drawing中的几个类实际上是定义的(RectangleF,PointF等)。 哪里是位图和图像? 那么这些类没有在Mono框架中实现是有很好的理由的。 这是因为它们不是跨平台兼容的。

那究竟是什么意思? 我们来看看MSDN上的System.Drawing文档。 它指出:“System.Drawing命名空间提供对GDI +基本graphicsfunction的访问。” 什么是GDI +? GDI +(graphics设备接口)是特定于Windows操作系统的graphics库(Win32)。 所以在System.Drawing.Bitmap的底层,是一个Win32实现,它绑定到Windows桌面/服务器操作系统。 这意味着System.Drawing.Bitmap和System.Drawing.Image是平台相关的,只能在Windows桌面/服务器应用程序上运行。 您将无法在iOS应用程序,Android应用程序甚至Windows Phone应用程序上使用这些类。 那么如何在iOS或Android应用程序中使用这个当前的C#代码呢? 稍微修改一下就可以了:

 public byte[] GetBitmapFromCache(string fileName) { return File.ReadAllBytes(fileName); } 

iOS和Android没有GDI +位图(System.Drawing.Bitmap)的概念,但是,每个平台都知道如何将字节数组转换为它们自己的位图实现。 使用iOS,你可以从一个字节数组创build一个UIImage,在Android中,你可以从同一个数组中创build一个Android.Graphics.Bitmap。

正如http://sharpmobilecode.com/introduction-to-xamarin-what-it-is-what-it-isnt/中所述,不可能创build一&#x4E2A;System.Drawing.Bitmap因为System.Drawing命名空间提供了对GDI +基本的graphicsfunction,特定于Windows操作系统,因此在iOS上不可用。

然而,可以像下面那样创build一个UIImage的截图

  1. 如何在越狱iOS设备上截屏整个屏幕? 显示,存在一个私人函数_UICreateScreenUIImage(void) ,返回所需的屏幕截图。 为了访问这个函数,必须声明它

     using System.Runtime.InteropServices; using ObjCRuntime; [DLLImport(/*ObjCRuntime.*/Constants.UIKitLibrary)] extern static IntPtr _UICreateScreenUIImage(); 
  2. 当被调用时,返回的IntPtr指向一个本地的UIImage,并需要被包装到一个托pipe对象中,由Runtime.GetNSObject(IntPtr)

     IntPtr ptr = _UICreateScreenUIImage(); UIImage uiimg = Runtime.GetNSObject(ptr) as UIImage; 

    由此产生的uiimg包含屏幕截图

附加的图片包含一个关于如何创build截图并将其保存为.jpeg的简单示例

关于如何创建和保存屏幕截图的简单示例

以及应用程序在后台时的屏幕截图的示例

截图的样子