web-dev-qa-db-ger.com

Wie erfasse ich den Android Gerätebildschirminhalt?

Mögliches Duplikat:
Wie programmiere ich einen Screenshot auf Android?

Wie erfasse ich den Bildschirminhalt des Android Geräts und erstelle aus den Schnappschussdaten eine Bilddatei? Welche API sollte ich verwenden oder wo finde ich verwandte Ressourcen?

Übrigens: kein Kamera-Schnappschuss, sondern ein Gerätebildschirm

49
Jagie

Laut dieser Link ist es möglich, ddms im Tools-Verzeichnis des Android sdk zu verwenden, um Screenshots zu machen.

Um dies innerhalb einer Anwendung (und nicht während der Entwicklung) zu tun, gibt es auch Anwendungen, die dies tun. Aber wie @ zed_0xff zeigt, benötigt es auf jeden Fall root.

13
Joubarc

Verwenden Sie den folgenden Code:

Bitmap bitmap;
View v1 = MyView.getRootView();
v1.setDrawingCacheEnabled(true);
bitmap = Bitmap.createBitmap(v1.getDrawingCache());
v1.setDrawingCacheEnabled(false);

Hier ist MyView das View, über das wir in den Bildschirm aufnehmen müssen. Sie können auch DrawingCache von jedem View auf diese Weise erhalten (ohne getRootView()).


Es gibt auch einen anderen Weg ..
Wenn wir ScrollView als Root-Ansicht haben, ist es besser, folgenden Code zu verwenden,

LayoutInflater inflater = (LayoutInflater) this.getSystemService(LAYOUT_INFLATER_SERVICE);
FrameLayout root = (FrameLayout) inflater.inflate(R.layout.activity_main, null); // activity_main is UI(xml) file we used in our Activity class. FrameLayout is root view of my UI(xml) file.
root.setDrawingCacheEnabled(true);
Bitmap bitmap = getBitmapFromView(this.getWindow().findViewById(R.id.frameLayout)); // here give id of our root layout (here its my FrameLayout's id)
root.setDrawingCacheEnabled(false);

Hier ist die getBitmapFromView() Methode

public static Bitmap getBitmapFromView(View view) {
        //Define a bitmap with the same size as the view
        Bitmap returnedBitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(),Bitmap.Config.ARGB_8888);
        //Bind a canvas to it
        Canvas canvas = new Canvas(returnedBitmap);
        //Get the view's background
        Drawable bgDrawable =view.getBackground();
        if (bgDrawable!=null) 
            //has background drawable, then draw it on the canvas
            bgDrawable.draw(canvas);
        else 
            //does not have background drawable, then draw white background on the canvas
            canvas.drawColor(Color.WHITE);
        // draw the view on the canvas
        view.draw(canvas);
        //return the bitmap
        return returnedBitmap;
    }

Es wird der gesamte Bildschirm einschließlich des in Ihrem ScrollView verborgenen Inhalts angezeigt.


AKTUALISIERT AM 20-04-2016

Es gibt noch einen besseren Weg, um einen Screenshot zu machen.
Hier habe ich einen Screenshot von WebView gemacht.

WebView w = new WebView(this);
    w.setWebViewClient(new WebViewClient()
    {
        public void onPageFinished(final WebView webView, String url) {

            new Handler().postDelayed(new Runnable(){
                @Override
                public void run() {
                    webView.measure(View.MeasureSpec.makeMeasureSpec(
                                    View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED),
                            View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
                    webView.layout(0, 0, webView.getMeasuredWidth(),
                            webView.getMeasuredHeight());
                    webView.setDrawingCacheEnabled(true);
                    webView.buildDrawingCache();
                    Bitmap bitmap = Bitmap.createBitmap(webView.getMeasuredWidth(),
                            webView.getMeasuredHeight(), Bitmap.Config.ARGB_8888);

                    Canvas canvas = new Canvas(bitmap);
                    Paint paint = new Paint();
                    int height = bitmap.getHeight();
                    canvas.drawBitmap(bitmap, 0, height, Paint);
                    webView.draw(canvas);

                    if (bitmap != null) {
                        try {
                            String filePath = Environment.getExternalStorageDirectory()
                                    .toString();
                            OutputStream out = null;
                            File file = new File(filePath, "/webviewScreenShot.png");
                            out = new FileOutputStream(file);

                            bitmap.compress(Bitmap.CompressFormat.PNG, 50, out);
                            out.flush();
                            out.close();
                            bitmap.recycle();
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
            }, 1000);
        }
    });

Hoffe das hilft..!

43
Nirav Dangi

Für neuere Android Plattformen kann ein Systemdienstprogramm screencap in /system/bin Ausgeführt werden, um den Screenshot ohne Root-Berechtigung zu erhalten. Sie können /system/bin/screencap -h um zu sehen, wie man es unter adb oder einer anderen Shell benutzt.

Übrigens denke ich, dass diese Methode nur für einzelne Momentaufnahmen geeignet ist. Wenn wir mehrere Bilder für das Bildschirmspiel aufnehmen möchten, ist dies zu langsam. Ich weiß nicht, ob es einen anderen Ansatz für eine schnellere Bildschirmaufnahme gibt.

23
Ducky Chen

AFAIK, Alle Methoden zur Erfassung eines Screenshots von Android verwenden den/dev/graphics/fb0-Framebuffer. Dies schließt ddms ein. Zum Lesen aus diesem Stream ist root erforderlich. Ddms verwendet adbd to fordern Sie die Informationen an, sodass root nicht erforderlich ist, da adb über die erforderlichen Berechtigungen zum Anfordern der Daten von/dev/graphics/fb0 verfügt.

Der Framebuffer enthält 2+ "Frames" von RGB565-Bildern. Wenn Sie die Daten lesen können, müssen Sie die Bildschirmauflösung kennen, um zu wissen, wie viele Bytes benötigt werden, um das Bild zu erhalten. Jedes Pixel ist 2 Byte groß. Wenn also die Bildschirmauflösung 480 x 800 beträgt, müssten Sie 768.000 Byte für das Bild lesen, da ein 480 x 800 RGB565-Bild 384.000 Pixel hat.

23
Ryan Conrad

[Basierend auf Android Quellcode:]

Auf der C++ - Seite implementiert der SurfaceFlinger die captureScreen-API. Dies wird über die Binder IPC Schnittstelle angezeigt und gibt jedes Mal einen neuen Ashmem-Bereich zurück, der die Rohpixel vom Bildschirm enthält. Der eigentliche Screenshot wird über OpenGL aufgenommen.

Für die System-C++ - Clients wird die Schnittstelle über die ScreenshotClient-Klasse verfügbar gemacht, die in <surfaceflinger_client/SurfaceComposerClient.h> Für Android <4.1; für Android> 4.1 definiert ist benutze <gui/SurfaceComposerClient.h>

Vor JB reichte es aus, einen Screenshot in einem C++ - Programm zu machen:

ScreenshotClient ssc;
ssc.update();

Mit JB und mehreren Displays wird es etwas komplizierter:

ssc.update(
    Android::SurfaceComposerClient::getBuiltInDisplay(
        Android::ISurfaceComposer::eDisplayIdMain));

Dann können Sie darauf zugreifen:

do_something_with_raw_bits(ssc.getPixels(), ssc.getSize(), ...);

Mit dem Android Quellcode können Sie Ihre eigene gemeinsam genutzte Bibliothek kompilieren, um auf diese API zuzugreifen, und sie dann über JNI für Java verfügbar machen. Um einen Screenshot Ihrer App zu erstellen, muss die App über verfügen die Berechtigung READ_FRAME_BUFFER .Aber auch dann können Sie anscheinend nur Screenshots von Systemanwendungen erstellen, dh solchen, die mit demselben Schlüssel wie das System signiert sind. (Diesen Teil verstehe ich noch nicht ganz, da ich Ich kenne mich mit dem Android Berechtigungssystem nicht aus.)

Hier ist ein Stück Code für JB 4.1/4.2:

#include <utils/RefBase.h>
#include <binder/IBinder.h>
#include <binder/MemoryHeapBase.h>
#include <gui/ISurfaceComposer.h>
#include <gui/SurfaceComposerClient.h>

static void do_save(const char *filename, const void *buf, size_t size) {
    int out = open(filename, O_RDWR|O_CREAT, 0666);
    int len = write(out, buf, size);
    printf("Wrote %d bytes to out.\n", len);
    close(out);
}

int main(int ac, char **av) {
    Android::ScreenshotClient ssc;
    const void *pixels;
    size_t size;
    int buffer_index;

    if(ssc.update(
        Android::SurfaceComposerClient::getBuiltInDisplay(
            Android::ISurfaceComposer::eDisplayIdMain)) != NO_ERROR ){
        printf("Captured: w=%d, h=%d, format=%d\n");
        ssc.getWidth(), ssc.getHeight(), ssc.getFormat());
        size = ssc.getSize();
        do_save(av[1], pixels, size);
    }
    else
        printf(" screen shot client Captured Failed");
    return 0;
}
18
Pekka Nikander

Sie können die folgende Bibliothek ausprobieren: Android Screenshot Library (ASL) Ermöglicht die programmgesteuerte Erfassung von Screenshots von Android) Geräten, ohne dass Root-Zugriffsrechte erforderlich sind. Stattdessen verwendet ASL a Der native Dienst wird im Hintergrund ausgeführt und über die Android Debug Bridge (ADB) einmal pro Gerätestart gestartet.

15
Kuba

Framebuffer scheint der richtige Weg zu sein, es wird nicht immer 2+ Frames enthalten, wie von Ryan Conrad erwähnt. In meinem Fall enthielt es nur einen. Ich denke, es hängt von der Frame-/Displaygröße ab.

Ich habe versucht, den Framebuffer kontinuierlich zu lesen, aber er scheint für eine festgelegte Anzahl von gelesenen Bytes zurückzukehren. In meinem Fall sind das (3 410 432) Bytes, was ausreicht, um einen Anzeigerahmen von 854 * 480 RGBA (3 279 360 Bytes) zu speichern. Ja, der von fb0 ausgegebene binäre Frame ist in meinem Gerät RGBA. Dies hängt höchstwahrscheinlich von Gerät zu Gerät ab. Dies ist wichtig, damit Sie es entschlüsseln können =)

In meinem Gerät/dev/graphics/fb0 sind die Berechtigungen so, dass nur root und Benutzer von Gruppengrafikenlesen die fb0 können. graphics ist eine eingeschränkte Gruppe, sodass Sie wahrscheinlich nur mit einem verwurzelten Telefon mit dem Befehl su auf fb0 zugreifen können.

Android-Apps haben die Benutzer-ID (uid) app _ ## und die Gruppen-ID (guid) app _ ##.

die adb-Shell verfügt über id-Shell und guid-Shell, die wesentlich mehr Berechtigungen haben als eine App. Sie können diese Berechtigungen tatsächlich unter / system/permissions/platform.xml überprüfen

Das heißt, Sie können fb0 in der adb-Shell ohne root lesen, aber Sie werden es nicht in der App ohne root lesen.

Das Erteilen von READ_FRAME_BUFFER- und/oder ACCESS_SURFACE_FLINGER-Berechtigungen für AndroidManifest.xml führt für eine reguläre App ebenfalls zu nichts, da diese nur für Signatur-Apps funktionieren.

7
Rui Marques

wenn Sie eine Bildschirmaufnahme von Java Code in Android App AFAIK) machen möchten, müssen Sie über Root-Berechtigungen verfügen.

5
zed_0xff