Copy link to clipboard
Copied
I have several apps that have a drawing function that includes a way to save a screenshot. AIR 23 and earlier, this function works correctly both in iOS and Android versions. With AIR 25 and 26, it stops on the var cameraRoll line and goes no further. The Adobe API reference shows it works with AIR 25 and older with no change in the examples. What am I missing? Appreciate some insight
Thanks, Jon - Animate 2017.5, AIR 26.0.0.118 (or AIR 25.0, 23.0)
function saveCamRoll(event:MouseEvent):void
{
drawToolClose_btn.visible = false; // hides the close button so not in screenshot
toolHide_mc.visible = true; //covers all the drawing tools so don't show in screenshot
var cameraRoll:CameraRoll = new CameraRoll();
var bitmapData:BitmapData = new BitmapData(stage.stageWidth,stage.stageHeight); // want everything on the screen for the screenshot
bitmapData.draw(stage);
cameraRoll.addBitmapData(bitmapData);
camRoll_btn.gotoAndPlay("over"); // adds a "click sound show user knows something happened
drawToolClose_btn.visible = true; //shows close button
toolHide_mc.visible = false; //shows the drawing tools
}
I have imported libraries
import flash.display.MovieClip;
import flash.display.Stage;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.events.MouseEvent;
import flash.events.Event;
I have set up listeners
function addListeners(): void {
toolHide_mc.visible = false;
camRoll_btn.addEventListener(MouseEvent.CLICK, saveCamRoll);
camRoll_btn.buttonMode = true;
}
You could try this example:
import flash.display.MovieClip;
import flash.display.Stage;
import flash.events.MouseEvent;
import flash.events.Event;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.events.ErrorEvent;
import flash.media.CameraRoll;
import flash.events.PermissionEvent;
import flash.permissions.PermissionStatus;
// Make cameraRoll a public variable:
var cameraRoll:CameraRoll = new CameraRoll();
function addListeners(): void {
if ((CameraRoll.supportsAddBitmapData == true)
...Copy link to clipboard
Copied
I did set up the function listeners too
function addListeners(): void {
toolHide_mc.visible = false;
camRoll_btn.addEventListener(MouseEvent.CLICK, saveCamRoll);
camRoll_btn.buttonMode = true;
}
Copy link to clipboard
Copied
Just add this persmission to your application descriptor:
<key>NSPhotoLibraryUsageDescription</key>
<string>A string explaining your purpose..., like: We will save the image to your photo library</string>
Copy link to clipboard
Copied
You would now need to use the permissions feature introduced in AIR 24. For more details check the AIR 24 release notes @Release Notes Flash Player 24 AIR 24
Thanks,
Krati | Adobe AIR Engineering
Copy link to clipboard
Copied
I have added
<key>NSPhotoLibraryUsageDescription</key>
<string>Saving screenshot to photo library</string>
to the xml file but this does not resolve the issue. Do I have to call the dialog for permission somewhere in the code?
Thanks, Jon
Copy link to clipboard
Copied
You need to use the permissions api with AIR 24 and above. Check the sample code below-
package
{
import
flash.display.Sprite;
import
flash.display.StageAlign;
import
flash.display.StageScaleMode;
import
flash.events.PermissionEvent;
import
flash.media.Camera;
import
flash.media.Video;
import
flash.permissions.PermissionStatus;
public
class
codeSnippet
extends
Sprite
{
private
var
video:Video;
private
var
cam:Camera;
public
function
codeSnippet()
{
super
();
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
if
(Camera.isSupported)
{
cam = Camera.getCamera();
if
(Camera.permissionStatus != PermissionStatus.GRANTED)
{
cam.addEventListener(PermissionEvent.PERMISSION_STATUS,
function
(e:PermissionEvent):
void
{
if
(e.status == PermissionStatus.GRANTED)
{
connectCamera();
}
else
{
// permission denied
}
});
try
{
cam.requestPermission();
}
catch
(e:Error)
{
// another request is in progress
}
}
else
{
connectCamera();
}
}
}
private
function
connectCamera():
void
{
video =
new
Video(
640
,
480
);
video.attachCamera(cam);
addChild(video);
}
}
}
For more details check the AIR 24 release notes @Release Notes Flash Player 24 AIR 24
Thanks,
Krati | Adobe AIR Engineering
Copy link to clipboard
Copied
The code snippet addresses use of the camera, however, I am just trying to get a screenshot saved. The process is different for CameraRoll and this code does not address that. I did create code that the complier ok'd, but it did not fix the problem. Under AIR 23, first time a user clicks the save screen button, a dialog comes up to ask permission to save and that is that. The user can easily make a screen shot any time by holding 2 buttons. How will this latest "innovation" by Apple address that? There is not enough info out there to recreate for AIR 24-26 what was already in place for 23. I believe I will have to wait for some more examples to work out this issue.
Copy link to clipboard
Copied
Hi,
The above code is an example to use the permission api using AIR 24 and above for Camera. For using CameraRoll the code needs to be modified for the same, and also "NSPhotoLibraryUsageDescription" permission in the application descriptor.
Thanks,
Krati | Adobe AIR Engineering
Copy link to clipboard
Copied
You could try this example:
import flash.display.MovieClip;
import flash.display.Stage;
import flash.events.MouseEvent;
import flash.events.Event;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.events.ErrorEvent;
import flash.media.CameraRoll;
import flash.events.PermissionEvent;
import flash.permissions.PermissionStatus;
// Make cameraRoll a public variable:
var cameraRoll:CameraRoll = new CameraRoll();
function addListeners(): void {
if ((CameraRoll.supportsAddBitmapData == true)){
toolHide_mc.visible = false;
camRoll_btn.addEventListener(MouseEvent.CLICK, saveCamRoll);
camRoll_btn.buttonMode = true;
}else{
// Here you could hide camRoll_btn etc.
}
}
function saveCamRoll(event:MouseEvent):void
{
cameraRoll.addEventListener(ErrorEvent.ERROR, onError);
cameraRoll.addEventListener(Event.COMPLETE, onSave);
drawToolClose_btn.visible = false;
toolHide_mc.visible = true;
var bitmapData:BitmapData = new BitmapData(stage.stageWidth,stage.stageHeight);
bitmapData.draw(stage); // or you could use bitmapData.drawWithQuality...
drawToolClose_btn.visible = true;
toolHide_mc.visible = false;
if (CameraRoll.permissionStatus != PermissionStatus.GRANTED)
{
// cameraRoll is not yet granted...
cameraRoll.addEventListener(PermissionEvent.PERMISSION_STATUS, cameraRollPermissionStatus);
try {
cameraRoll.requestPermission();
} catch(e:Error){
// another request is in progress ...;
}
}else{
// All set. Calls addToCameraRoll now
addToCameraRoll();
}
}
function addToCameraRoll():void{
cameraRoll.addBitmapData(bitmapData);
camRoll_btn.gotoAndPlay("over");
}
function cameraRollPermissionStatus(e:PermissionEvent):void {
cameraRoll.removeEventListener(PermissionEvent.PERMISSION_STATUS, cameraRollPermissionStatus);
if (e.status == PermissionStatus.GRANTED){
addToCameraRoll();
}else{
// permission denied
}
}
function onError(e:ErrorEvent):void {
cameraRoll.removeEventListener(Event.COMPLETE, onSave);
cameraRoll.removeEventListener(ErrorEvent.ERROR, onError);
}
function onSave(e:Event):void {
cameraRoll.removeEventListener(Event.COMPLETE, onSave);
cameraRoll.removeEventListener(ErrorEvent.ERROR, onError);
}
Copy link to clipboard
Copied
Lars Laborious has the correct answer. I did have to place all of the functions below the saveCamRoll function into the saveCamRoll function. Else, I was getting a number of bitmapData undefined type errors since the variable was declared in the saveCamRoll function. It was a bit of trial and error figuring out where to show the buttons and then hide them for the screen shot and then reshow after it was saved. I also could only test this on the iPad itself as the (CameraRoll.supportsAddBitmapData == true) can only be true on an iPad! AIR 23 and before, I'd get an out of sequence error but that did show it was working. I appreciate all the info.
Jon
Here is the code as it works in the app
// for screenshot, make cameraRoll a public variable
var cameraRoll: CameraRoll = new CameraRoll();
function addListeners(): void {
if ((CameraRoll.supportsAddBitmapData == true)) {
toolHide_mc.visible = false;
camRoll_btn.addEventListener(MouseEvent.CLICK, saveCamRoll);
camRoll_btn.buttonMode = true;
} else {
// Here you could hide camRoll_btn etc.
toolHide_mc.visible = true;
}
}
function saveCamRoll(event: MouseEvent): void
{
cameraRoll.addEventListener(ErrorEvent.ERROR, onError);
cameraRoll.addEventListener(Event.COMPLETE, onSave);
drawToolClose_btn.visible = false;
toolHide_mc.visible = true;
var bitmapData: BitmapData = new BitmapData(stage.stageWidth, stage.stageHeight);
bitmapData.draw(stage); // or you could use bitmapData.drawWithQuality...
toolHide_mc.visible = false;
if (CameraRoll.permissionStatus != PermissionStatus.GRANTED) {
// cameraRoll is not yet granted...
cameraRoll.addEventListener(PermissionEvent.PERMISSION_STATUS, cameraRollPermissionStatus);
try {
cameraRoll.requestPermission();
} catch (event: Error) {
// another request is in progress ...;
}
} else {
// All set. Calls addToCameraRoll now
addToCameraRoll();
}
function addToCameraRoll(): void {
cameraRoll.addBitmapData(bitmapData);
camRoll_btn.gotoAndPlay("over");
toolHide_mc.visible = false;
drawToolClose_btn.visible = true;
}
function cameraRollPermissionStatus(event: PermissionEvent): void {
cameraRoll.removeEventListener(PermissionEvent.PERMISSION_STATUS, cameraRollPermissionStatus);
if (event.status == PermissionStatus.GRANTED) {
addToCameraRoll();
} else {
// permission denied
}
function cameraRollPermissionStatus(event: PermissionEvent): void {
cameraRoll.removeEventListener(PermissionEvent.PERMISSION_STATUS, cameraRollPermissionStatus);
if (event.status == PermissionStatus.GRANTED) {
addToCameraRoll();
} else {
// permission denied
}
}
}
function onError(e: ErrorEvent): void {
cameraRoll.removeEventListener(Event.COMPLETE, onSave);
cameraRoll.removeEventListener(ErrorEvent.ERROR, onError);
}
function onSave(e: Event): void {
cameraRoll.removeEventListener(Event.COMPLETE, onSave);
cameraRoll.removeEventListener(ErrorEvent.ERROR, onError);
}
}