In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-04-11 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/02 Report--
This article mainly introduces the example analysis of Android screenshot and WebView long picture, which is very detailed and has certain reference value. Friends who are interested must finish it!
I. Overview
Recently, while doing new business requirements, we have encountered some problems on Android that we have not encountered before, such as screenshot sharing, WebView generation of long images, blurred pictures and even failed sharing of long images in various sharing channels. We have stepped on a lot of holes in this process, and so far most of the problems still have satisfactory solutions. The following is a summary of the challenges and solutions encountered in the process from three aspects.
2. Screenshot sharing
In the native Android system, there is no broadcast of screenshots or monitoring events, that is, users' screenshots cannot be known at the code level, so they cannot meet the need for users to jump out and share prompts after taking screenshots. Since the problem of screenshot monitoring cannot be solved fundamentally, we should consider implementing it indirectly through other ways. At present, the more mature and stable solution is to monitor the changes of media database resources in the system. The specific principles of the solution are as follows:
The Android system has a media database. Every time a photo is taken or a screenshot is taken by the system, the details of the picture will be added to the media database, and the content change notice will be sent. We can use ContentObserver to monitor the change of the media database. When there is a change in the database, we can obtain a piece of image data inserted by * *. If the picture conforms to specific rules. Is thought to have been screenshot.
Considering that mobile phone storage includes internal memory and external memory, to enhance compatibility, * monitors the changes of both storage spaces at the same time. Here are the resources URI that need to be monitored by ContentObserver:
MediaStore.Images.Media.INTERNAL_CONTENT_URI MediaStore.Images.Media.EXTERNAL_CONTENT_URI
To read external storage resources, you need to add permissions:
Android.permission.READ_EXTERNAL_STORAGE
Note: dynamic application permission is required in Android version 6.0and above
1. Screenshot judgment rules
When ContentObserver listens to a change in the data of the media database, it acquires a piece of image data inserted into the database when the data changes. If the following rules are met, it is considered to have taken a screenshot:
Time judgment: usually, after the screenshot is generated, it will be stored in the system multimedia database immediately, that is, the time for monitoring changes in the database is not too different from the time for screenshot generation. It is recommended to use 10 seconds as the threshold. Of course, this is also an empirical value.
Size judgment: as the name implies, the screenshot is the current mobile phone screen size of the picture, so the picture width and height is greater than the screen width and height must not be generated by the screenshot.
Path judgment: as the file paths where screenshots are stored by different mobile phone manufacturers are different, the domestic situation may be more serious, but usually the image preservation path will contain some common keywords, such as "screenshot", "screencapture", "screencap", "screenshot", "screenshot" and so on. Check whether the image path information contains these keywords every time.
On the third point, I need to add that in order to determine whether the image file path contains keywords, only Chinese and English environments are currently supported. If you need to support other languages, you need to manually add some keywords in that language, otherwise you may not be able to get the picture.
The above three points can basically ensure the normal monitoring of screenshots, of course, in the actual testing process, we will also find that some models are overreported, so we still need to do some de-duplication and other work, which will be mentioned below.
two。 Key code
Now that the principle is clear, then there is the question of how to implement it. The most important thing here is the setting of the media content viewer. Take out * pieces of data from the database and parse the image information, and then check whether the image information conforms to the above three rules.
To make it clear how to listen for changes in the media database, let's first talk a little bit about how ContentObserver works. ContentObserver-the content watcher, whose purpose is to observe (capture) the changes in the database caused by a particular Uri, and then do some processing accordingly, similar to the Trigger in database technology, which is triggered when the Uri observed by ContentObserver changes. Of course, if you want to observe, you must first register. The Android system provides a ContentResolver#registerContentObserver method to register the viewer. Students who are not familiar with this part can review the ContentProvider related knowledge of Android.
Next, the whole registration and trigger process is directly explained in code, as follows:
Private void initMediaContentObserver () {/ / Handler running on the UI thread, used to run the listener callback private final Handler mUiHandler = new Handler (Looper.getMainLooper ()); / / create content watchers, including internal and external storage mInternalObserver = new MediaContentObserver (MediaStore.Images.Media.INTERNAL_CONTENT_URI, mUiHandler); mExternalObserver = new MediaContentObserver (MediaStore.Images.Media.EXTERNAL_CONTENT_URI, mUiHandler) / / register the content watcher mContext.getContentResolver (). RegisterContentObserver (MediaStore.Images.Media.INTERNAL_CONTENT_URI, false, mInternalObserver); mContext.getContentResolver (). RegisterContentObserver (MediaStore.Images.Media.EXTERNAL_CONTENT_URI, false, mExternalObserver);} / * Custom media content watcher class (observe changes in the media database) * / private class MediaContentObserver extends ContentObserver {private Uri mediaContentUri / / Uri public MediaContentObserver (Uri contentUri, Handler handler) {super (handler); mediaContentUri = contentUri;} @ Override public void onChange (boolean selfChange) {super.onChange (selfChange); / / data changes reported by the media database handleMediaContentChange (mediaContentUri);}}
If there is a registration, you need to cancel the registration when the Activity is destroyed, so you also need to encapsulate a de-registration method for external calls. The Android system provides a ContentResolver#unregisterContentObserver method to cancel the registration. The code is relatively simple, so it will not be shown here.
After the listener is set and registered, once the user has operated the screenshot, the system will execute the ContentObserver#onChange callback method, in which we can obtain and parse the data according to Uri. Here to show the specific data parsing process, the above-mentioned rules are relatively simple to judge, will not be shown.
Private void handleMediaContentChange (Uri contentUri) {Cursor cursor = null; try {/ / query a piece of data added in the database when the data changes cursor = mContext.getContentResolver () .query (contentUri, Build.VERSION.SDK_INT
< 16 ? MEDIA_PROJECTIONS : MEDIA_PROJECTIONS_API_16, null, null, MediaStore.Images.ImageColumns.DATE_ADDED + " desc limit 1"); if (cursor == null) return; if (!cursor.moveToFirst()) return; // cursor.getColumnIndex获取数据库列索引 int dataIndex = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA); String data = cursor.getString(dataIndex); // 图片存储地址 int dateTakenIndex = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATE_TAKEN); long dateTaken = cursor.getLong(dateTakenIndex); // 图片生成时间 int width = 0; int height = 0; if (Build.VERSION.SDK_INT >= 16) {int widthIndex = cursor.getColumnIndex (MediaStore.Images.ImageColumns.WIDTH); int heightIndex = cursor.getColumnIndex (MediaStore.Images.ImageColumns.HEIGHT); width = cursor.getInt (widthIndex); / / get picture height height = cursor.getInt (heightIndex) / / get picture width} else {Point size = getImageSize (data); / / get picture width and height according to path width = size.x; height = size.y } / / process the obtained * * rows of data to determine whether the path contains keywords, time difference, and the relationship between picture width and screen width and height handleMediaRowData (data, dateTaken, width, height);} catch (Exception e) {e.printStackTrace () } finally {if (cursor! = null & & cursor.isClosed ()) {cursor.close ();}
Some mobile phone ROM screenshots will send notification of content changes multiple times at a time, so you need to do the de-repetition operation, which is not complicated. You can cache more than a dozen recent image address data with the list. Every time you get a new image address, you will first determine whether the same image address exists in the cache. If the current image address already exists in the list, just filter it out, otherwise add it to the cache. In this way, you can ensure that screenshot monitoring events are neither omitted nor repeated.
The above are the core principles and key codes of mobile screenshots. If you need to share screenshots, it is also very simple. Data is the storage address of the images, and you can complete the sharing by converting them to Bitmap.
Second, WebView generates long diagrams
Before introducing web long images, let's talk about the generation scheme of single-screen images. Unlike mobile phone screenshots, the generated images do not display the status bar at the top, the title bar and the menu bar at the bottom, which can meet different business needs.
/ / WebView generates a picture of the current screen size, and shortImage is the final picture Bitmap shortImage = Bitmap.createBitmap (screenWidth, screenHeight, Bitmap.Config.RGB_565); Canvas canvas = new Canvas (shortImage); / / the width and height of the canvas is consistent with the width and height of the screen Paint paint = new Paint (); canvas.drawBitmap (shortImage, screenWidth, screenHeight, paint); mWebView.draw (canvas)
Sometimes we need to generate pictures from a long Web page to share. Similar examples are various note apps on mobile phones. When the content of a note exceeds one screen, you need to generate a long picture to share with the outside world.
WebView and other View, the system provides a draw method, you can directly render the content of View to the canvas, with the canvas we can draw a variety of other content on it, such as adding Logo pictures at the bottom, drawing red frames, and so on. There are many ready-made solutions and codes on the WebView generation map. The following code is a stable version that has been tested for reference.
/ / WebView generates long images, that is, pictures with more than one screen. The longImage in the code is * generated long images mWebView.measure (MeasureSpec.makeMeasureSpec (MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED), MeasureSpec.makeMeasureSpec (0, MeasureSpec.UNSPECIFIED)); mWebView.layout (0,0, mWebView.getMeasuredWidth (), mWebView.getMeasuredHeight ()); mWebView.setDrawingCacheEnabled (true); mWebView.buildDrawingCache () Bitmap longImage = Bitmap.createBitmap (mWebView.getMeasuredWidth (), mWebView.getMeasuredHeight (), Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas (longImage); / / the width and height of the canvas is consistent with the WebView web page Paint paint = new Paint (); canvas.drawBitmap (longImage, 0, mWebView.getMeasuredHeight (), paint); mWebView.draw (canvas)
In order to improve the rendering speed of scrolling and other aspects, Android can establish a cache for each View and use View#buildDrawingCache to establish a corresponding cache for its own View. This cache is a bitmap object. Using this feature, you can take a screenshot of the entire screen view and generate Bitmap, and you can also get the Bitmap object of the specified View. Here, because we also need to draw Logo on the original picture, we directly use the draw method of WebView.
Since most of our H5 pages are run in Wechat's X5 browser, in order to reduce the front-end adaptation work, we introduced Tencent's X5 browser kernel into the Android project to replace the system's native WebView kernel. There will be a special article on the introduction of X5 kernel, please look forward to it.
Here we need to explain how to generate a long Web diagram under the X5 kernel. The above code shows the system native WebView image generation scheme, but in the X5 environment, the above code is invalid. After stepping on the pit and looking at the X5 kernel source code, we finally found a solution to this problem. The following key code is used to illustrate the specific implementation.
/ / the mWebView here is the WebView of the X5 kernel, and the longImage in the code is the long graph mWebView.measure (MeasureSpec.makeMeasureSpec (MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED), MeasureSpec.makeMeasureSpec (0, MeasureSpec.UNSPECIFIED)); mWebView.layout (0,0, mWebView.getMeasuredWidth (), mWebView.getMeasuredHeight ()); mWebView.setDrawingCacheEnabled (true); mWebView.buildDrawingCache () Bitmap longImage = Bitmap.createBitmap (mWebView.getMeasuredWidth (), mWebView.getMeasuredHeight () + endHeight, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas (longImage); / / the width and height of the canvas are consistent with the web pages of WebView Paint paint = new Paint (); canvas.drawBitmap (longImage, 0, mWebView.getMeasuredHeight (), paint); float scale = getResources (). GetDisplayMetrics (). Density; x5Bitmap = Bitmap.createBitmap (mWebView.getWidth (), mWebView.getHeight (), Bitmap.Config.ARGB_8888) Canvas x5Canvas = new Canvas (x5Bitmap); x5Canvas.drawColor (ContextCompat.getColor (this, R.color.fragment_default_background)); mWebView.getX5WebViewExtension () .snapshotWholePage (x5Canvas, false, false); / / long graph Matrix matrix = new Matrix () without this line of code; matrix.setScale (scale, scale); longCanvas.drawBitmap (x5Bitmap, matrix, paint)
Note: the long picture generated by the X5 kernel is a little less clear than the native WebView, and there is no good solution yet.
Third, long picture sharing
Generally speaking, the pictures we send to various social platforms are relatively small. * *, that is, pictures the size of a mobile phone screen, are rare. But there are exceptions, such as long picture of Weibo, long picture of hammer note and so on. If we share these pictures directly through Wechat sharing SDK or Weibo sharing SDK, we will find that the pictures are basically blurry, but the pictures can be viewed normally after sending them to iPhone mobile phones. We can only bemoan the weakness of Wechat on Android.
Wechat SDK is not good, but the product experience still can not be lost, how to do? There are still ways. We all know that in addition to each social platform's own sharing SDK, the system provides a native sharing solution, which essentially means that the social platform exposes the target Activity, and then the third-party App can evoke the social platform according to the pre-defined Intent jump rules, and complete data transmission and display at the same time.
It seems that the problem can be solved, but there are still holes to keep stepping on. In Android version 7.0 and above, the system restricts the transmission of data at the beginning of file:// by Intent, which limits the system's native sharing of single pictures. What should I do? Two options, one is to use sharing SDK such as Wechat on version 7.0 or later to accept the blurred situation of sharing pictures, and the other is to skip the system's restrictions on the transfer of files starting with file:// in Intent through reflection, but this way will be risky, after all, we do not know what adjustments Android will make in the future. The following is a code snippet that skips system restrictions for reference.
If (Build.VERSION.SDK_INT > = Build.VERSION_CODES.N) {try {Method ddfu = StrictMode.class.getDeclaredMethod ("disableDeathOnFileUriExposure"); ddfu.invoke (null);} catch (Exception e) {}}
At this point, it can basically satisfy the sharing of any picture size. In addition, after verification, it is also found that SDK of Wechat sharing Android has restrictions on the size of thumbnails and sharing images. The official guidance is that thumbnails are less than 32K, and shared pictures can be shared normally if they are less than 10m, but these two values are theoretical upper limits. Do not get too close to this upper limit. If the picture is too large, both thumbnails and shared images will be blurred, or even can not be shared normally. Of course, for sharing through the system, there is no such restriction, and the picture is relatively clear.
In addition to the image size limit, the thumbnail size is also limited, which is not given in the official document. The experimental results show that the picture size less than or equal to 120 × 120 is a relatively safe range, and there is no problem with sharing.
The above is all the contents of the article "sample Analysis of Android Screenshot and WebView long Picture". Thank you for reading! Hope to share the content to help you, more related knowledge, welcome to follow the industry information channel!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.