After converting a Web Extension using safari-web-extension-converter, running extension fails with SFErrorDomain code 1 - safari

I have a web extension https://github.com/david-shortman/clickster
In the directory for that extension, I ran
david#Davids-Mac-mini clickster % xcrun safari-web-extension-converter .
Xcode Project Location: /Volumes/Samsung_T5/dev/GitHub/clickster
App Name: Clickster
App Bundle Identifier: com.yourCompany.Clickster
Language: Swift
Is this correct? [yes]: no
Xcode Project Location [/Volumes/Samsung_T5/dev/GitHub/clickster]:
App Name [Clickster]:
App Bundle Identifier [com.yourCompany.Clickster]: com.shortman.Clickster
1. Swift
2. Objective-C
Language [1]: 1
Then, Xcode automatically opens that project.
I ran the app with the default config for "My Mac".
The extension immediately encountered this error in the default guard in ViewController here
error
error Error? domain: "SFErrorDomain" - code: 1 0x0000600002706ca0
error was thrown on line 3
guard let state = state, error == nil else {
                // Insert code to inform the user that something went wrong.
                return // <- breaks here
            }

I was able to solve the problem by doing a clean install of macOS and Xcode. What a dumb as hell problem. No idea what the cause was.
I did try removing Xcode and relevant files/directories first, but that didn't help. Only the clean install of macOS seemed to do the trick.

Related

How to enable AdMob interstitial ads using the preferred structure of Jetpack Compose

As I understand the structure of Jetpack Compose and Kotlin in Android Studio, UI and factory functions are to be kept separate and xml files aren't used for layout. When I try to follow the instructions for Kotlin in AdMob for interstitial ads, I can't get it to work.
But even the instructions seems to ask for all the action to happen on the MainActivity file and not in a separate UI file (like GameScreen) or factory (like GameViewModel). I thought all the MainActivity in the modern architecture was to kick off the UI, and the UI was to handle the state of the view, and the factories were to get the date, which feels like the opposite of the AdMob guidance code.
I've been able to get Banner ads to works using a call to a function using an Android View process in the Game Screen. But I can't get interstitial ads to work at all, in particular because it is choking on the highlighted "this" calls in the sample code:
      InterstitialAd.load(***this***,"ca-app-pub-3940256099942544/1033173712", adRequest, object : InterstitialAdLoadCallback() {
        override fun onAdFailedToLoad(adError: LoadAdError) {
          Log.d(TAG, adError?.toString())
          mInterstitialAd = null
        }
        override fun onAdLoaded(interstitialAd: InterstitialAd) {
          Log.d(TAG, 'Ad was loaded.')
          mInterstitialAd = interstitialAd
        }
if (mInterstitialAd != null) {
  mInterstitialAd?.show(***this***)
} else {
  Log.d("TAG", "The interstitial ad wasn't ready yet.")
}
Any ideas?
(I've thought about starting a second activity that kicks off from the Game Screen).
(The sample fragment for AdMob in Android Studio uses xml files on a MainActivity class.)
(I've looked at the Android Training Courses for codelabs addressing this issue, but couldn't find it. Would seem to be a good one for the Android team to create!)

Executing actions when notification is received with background/killed state app?

My backend is sending Data-Only message, below shows the payload when app is in the Background state. And I'm relying Firebase messaging() to receive the payload.
{
    aps =     {
        alert =         {
            body = "msg";
            title = iOS;
        };
        sound = default;
    };
    deeplink = "myapp://profile";
    "gcm.message_id" = maskedData;
    "google.c.a.e" = 1;
    "google.c.sender.id" = maskedData;
    mediaType = image;
    notificationid = "maskedData";
}
For now, my method setBackgroundMessageHandler is not called when the banner (notification) kicks in when app is in Background/Kill state. This happened because my payload does not contain contentAvailable: true I guess.
Although my app will show the banner still but no code is run behind the scene.
Meaning if the user decides to open my app without tapping the banner, I’m unable to store the notification content hence user will never see it in app. Unless he opens the app via the banner (notification), my app gets the notification content. Hence I’m able to do certain processing behind (storing content, append into my notification list)..
My questions:
How can we wakes the app and does certain processing (store content, etc) as soon as notification banner is received?
How can we update Badge number when app is in Background/Kill stated? (I planned to do it via the “behind process” as well when notification is received. But for now, I don’t get notify until user taps the banner)
Of course, here goes my version #react-native-firebase/messaging": "^7.8.4",

testcafe how to make the selection of the conditional element

I'm having trouble making the selection of the element that conditionally appears on a page.
I've tried awaiting but it didn't work.
// Gets imported as detailedProductPage
export default class Page {
constructor () {
this.chipItem0 = Selector('[data-test-id="chipItem0"]').child('.tag-name').child('[data-test-id="tagValue"]');
}
}
test('should accept value and allow for making the selection of multiple items.', async t => {
const string0 = 'Professionelle Nassreinigung nicht erlaubt';
const string1 = 'Handwäsche';
const string2 = 'Waschen 30°C';
await t
.click(detailedProductPage.listContainerFirstChild)
.typeText(detailedProductPage.symbols, string0)
.click(detailedProductPage.symbolsResultsItem0)
.expect(string0).eql(detailedProductPage.chipItem0.innerText)
.typeText(detailedProductPage.symbols, string1)
.click(detailedProductPage.symbolsResultsItem0)
.expect(string1).eql(detailedProductPage.chipItem1.innerText)
.typeText(detailedProductPage.symbols, string2)
.click(detailedProductPage.symbolsResultsItem1)
.expect(string2).eql(detailedProductPage.chipItem2.innerText);
});
You can use the exists property to check if the element exists on the page. With this you can click on the element that conditionally appears on a page:
const el = Selector('#el');
if(await el.exists)
await t.click(el);
 
To make your test correct, you need to fix your assertions. According to the TestCafe Assertions API the eql assertion should be used in the following manner:
await t.expect( actual ).eql( expected, message, options );
 
TestCafe allows a user to pass asynchronous Selector properties as an actual argument. These properties represent a state of a related DOM-element on the tested page. In your case, the actual value is detailedProductPage.chipItem0.innerText.
The expected value can't be an asynchronous property, it should be a calculated value (like string, boolean, number or some object etc..).
 
The following code should work correctly:
await t
.click(detailedProductPage.listContainerFirstChild)
.typeText(detailedProductPage.symbols, string0)
.click(detailedProductPage.symbolsResultsItem0)
.expect(detailedProductPage.chipItem0.innerText).eql(string0);
 

macOS Swift: How to properly add application as Login Item

I have spent about one day (maybe a little more) on trying to add my application to Login Item in the order it starts up at macOS launch (user login).
The first approach was the newest one; I check this tutorial on youtube:
https://www.youtube.com/watch?v=2mmWEHUgEBo&t=660s
So following this steps, I have done:
Add new project inside my main project that I have named Launcher
I am using Automatic Signing (as version of my Xcode) is different
In Project Settings > Capabilities I toggled App Sandbox to ON.
In Build Phases I have added this:
My Launcher has Skip Install = YES
Code in my Launcher app looks like this (I have even previously use Swift to do the same)
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
// Insert code here to initialize your application
NSArray *pathComponents = [[[NSBundle mainBundle] bundlePath] pathComponents];
pathComponents = [pathComponents subarrayWithRange:NSMakeRange(0, [pathComponents count] - 4)];
NSString *path = [NSString pathWithComponents:pathComponents];
[[NSWorkspace sharedWorkspace] launchApplication:path];
[NSApp terminate:nil];
}
Finally, I have magic code in Main App to enable app as Login Item
if(!SMLoginItemSetEnabled("click.remotely.Remotely-Click-Server-Launcher"
as CFString, Bool(checkboxButton.state as NSNumber) ) ) {
let alert: NSAlert = NSAlert()
alert.messageText = "Remotely.Click Server - Error";
alert.informativeText = "Application couldn't be added as
Login Item to macOS System Preferences > Users & Groups.";
alert.alertStyle = NSAlertStyle.warning;
alert.addButton(withTitle:"OK");
alert.runModal();
}
I have made Archive, and then have different options to Export:
I couldn't decide which one to choose, so I tried all of them.
"Save for Mac App Store Deployment" - made Installation package that has installed in /Applications/ directory but the app never runs.
"Developer-Id signed," "Development-signed" , "macOS App" all makes file in a directory that I exported to Applications directory, but no one works.
When I click the checkbox button, I could see some window blinking for a while on the screen (Launcher program). When I log out and log in the same window blinking effect appears but Launcher didn't start the Main application. When I click checkbox button again (and turn off Login Item) this blinking effect on user login (system startup) doesn't happen again. So it seems that this addition of Launcher program as Login Item works, but this Launcher couldn't start the Main app. Moreover when I go to /Applications/Main.app/Contents/Library/LoginItems/Launcher.app and click it manually then Launcher app launch Main application correctly (so the path was correct).
So what's going wrong?
Then I consider implementation of deprecated approach using
kLSSharedFileListSessionLoginItems
I have thought it must work it just add something in System Preferences this
window below.
But it also could go wrong!
I have chosen implementation in Swift (all examples/tutorials I have found was in Objective-C) So I have written something like this:
class LoginItemsList : NSObject {
let loginItemsList : LSSharedFileList = LSSharedFileListCreate(nil, kLSSharedFileListSessionLoginItems.takeRetainedValue(), nil).takeRetainedValue();
func addLoginItem(_ path: CFURL) -> Bool {
if(getLoginItem(path) != nil) {
print("Login Item has already been added to the list.");
return true;
}
var path : CFURL = CFURLCreateWithString(nil, "file:///Applications/Safari.app" as CFString, nil);
print("Path adding to Login Item list is: ", path);
// add new Login Item at the end of Login Items list
if let loginItem = LSSharedFileListInsertItemURL(loginItemsList,
getLastLoginItemInList(),
nil, nil,
path,
nil, nil) {
print("Added login item is: ", loginItem);
return true;
}
return false;
}
func removeLoginItem(_ path: CFURL) -> Bool {
// remove Login Item from the Login Items list
if let oldLoginItem = getLoginItem(path) {
print("Old login item is: ", oldLoginItem);
if(LSSharedFileListItemRemove(loginItemsList, oldLoginItem) == noErr) {
return true;
}
return false;
}
print("Login Item for given path not found in the list.");
return true;
}
func getLoginItem(_ path : CFURL) -> LSSharedFileListItem! {
var path : CFURL = CFURLCreateWithString(nil, "file:///Applications/Safari.app" as CFString, nil);
// Copy all login items in the list
let loginItems : NSArray = LSSharedFileListCopySnapshot(loginItemsList, nil).takeRetainedValue();
var foundLoginItem : LSSharedFileListItem?;
var nextItemUrl : Unmanaged<CFURL>?;
// Iterate through login items to find one for given path
print("App URL: ", path);
for var i in (0..<loginItems.count) // CFArrayGetCount(loginItems)
{
var nextLoginItem : LSSharedFileListItem = loginItems.object(at: i) as! LSSharedFileListItem; // CFArrayGetValueAtIndex(loginItems, i).;
if(LSSharedFileListItemResolve(nextLoginItem, 0, &nextItemUrl, nil) == noErr) {
print("Next login item URL: ", nextItemUrl!.takeUnretainedValue());
// compare searched item URL passed in argument with next item URL
if(nextItemUrl!.takeRetainedValue() == path) {
foundLoginItem = nextLoginItem;
}
}
}
return foundLoginItem;
}
func getLastLoginItemInList() -> LSSharedFileListItem! {
// Copy all login items in the list
let loginItems : NSArray = LSSharedFileListCopySnapshot(loginItemsList, nil).takeRetainedValue() as NSArray;
if(loginItems.count > 0) {
let lastLoginItem = loginItems.lastObject as! LSSharedFileListItem;
print("Last login item is: ", lastLoginItem);
return lastLoginItem
}
return kLSSharedFileListItemBeforeFirst.takeRetainedValue();
}
func isLoginItemInList(_ path : CFURL) -> Bool {
if(getLoginItem(path) != nil) {
return true;
}
return false;
}
static func appPath() -> CFURL {
return NSURL.fileURL(withPath: Bundle.main.bundlePath) as CFURL;
}
}
I have used this to turn on/off Login Item by clicking in the checkbox
let loginItemsList = LoginItemsList();
if( checkboxButton.state == 0) {
if(!loginItemsList.removeLoginItem(LoginItemsList.appPath())) {
print("Error while removing Login Item from the list.");
}
} else {
if(!loginItemsList.addLoginItem(LoginItemsList.appPath())) {
print("Error while adding Login Item to the list.");
}
}
I have run it in Debug mode (Xcode Play button) and try to archive it and export to /Applications folder if it matters, but this approach also doesn't work.
Console-printed messaged. Error means that the function Inserting Login Item returns nil.
So after that I even try to implement this (from some stackoverflow example) using Objective-C (as there is many Unmanaged<> in Swift)
So I added new .m and .h file and Bridging-Header.h and then a code like this:
- (void)enableLoginItemWithURL:(NSURL *)itemURL
{
LSSharedFileListRef loginListRef = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL);
if (loginListRef) {
// Insert the item at the bottom of Login Items list.
LSSharedFileListItemRef loginItemRef = LSSharedFileListInsertItemURL(loginListRef,
kLSSharedFileListItemLast,
NULL,
NULL,
(__bridge CFURLRef) itemURL,
NULL,
NULL);
if (loginItemRef) {
CFRelease(loginItemRef);
}
CFRelease(loginListRef);
}
}
Simple (just insertion) without any bells and whistles.
It also has the same issue that LSSharedFileListInsertItemURL returns nil and Login Item is not added to System Preferences > Users & Groups > Login Items.
So any idea why I cannot make this work?
UPDATE 1
I have tried to implement application using first approach (helper Launcher application inside Main application) on another computer iMac (MacOS Sierra and the newest XCode 8.3) and it seems to work there correctly so maybe there is something wrong with my OS or Xcode (provisioning profiles, signing of app or whatever) On MacBook Air where this approach doesn't work I am using OS X El Capitan 10.11.5 and Xcode 8.0.
Watch how it works here:
https://youtu.be/6fnLzkh5Rbs
and testing
https://www.youtube.com/watch?v=sUE7Estju0U
The second approach doesn't work also on my iMac returning the nil while doing LSSharedFileListInsertItemURL. So I don't know why that is happening.
Watch how it works here:
https://youtu.be/S_7ctQLkIuA
UPDATE 2
After upgrade to macOS Sierra 10.12.5 from El Capitan 10.11.5 and using Xcode 8.3.2 instead of Xcode 8.0.0 the second approach also happens to work correctly and is adding Login Items to System Preferences > Users & Groups > Login Items
IMPORTANT! To work this approach with LSSharedFileListInsertItemURL needs to disable App Sandboxing! Like in the video below:
https://youtu.be/UvDkby0t_WI
I also struggled with this a few years ago and ended up making a package for it that makes it much easier to add "launch at login" functionality for sandboxed apps.
Instead of lots of manual steps, you just need:
import LaunchAtLogin
LaunchAtLogin.isEnabled = true
Since macOS 13 Ventura, we can finally use a new SMAppService.
import ServiceManagement
try SMAppService.mainApp.register()
See SMAppService documentation for more details.
For the ServiceManagement approach, sometimes it doesn't work in your development machine because there is another copy of the app in your Xcode's DerivedData. The system don't know which app to launch. So go to ~/Library/Developer/Xcode/DerivedData and delete your development copy could help.
The above solution of Login Item programming problem works correctly both using modern approach with ServiceManagement.framework, and old (deprecated) approach with inserting Login Item into System Preferences > Users & Groups > Login Items. See my UPDATE 1 and UPDATE 2 remarks.
Dear Michal I have had the same problem about log in items. Log in items can be added in two ways; one from LSSharedFileListItemRef which will be shown in Login item of preferences but this approach will only work for non-sandboxing app and if you are making sandbox app then you should go for another way of using ServiceManagement framework.
You can have look over below link which specify everything - :
Launching your app on system start
I am adding another reference of adding app on log in - :
Approach for sandbox app with helper application
May be you are having trouble implementing app on log in item but follow the steps appropriately and you will succeed.

Titanium showCamera and OpenPhotoGallery Function

I wish to ask is there anyone face the problem when you guys activate showCamera and open photo Gallery function of titanium in android. It will crash the app and restart app automatically. I have searched a lot of forum especially JIRA appcelator and titanium forum but most of the cases are unresolved. I have tried a lot of method in the forum but still the same. I wish to know is this a bug of titanium?
The best code to choose from camera or gallery
//Create a dialog with options
var dialog = Titanium.UI.createOptionDialog({
    //title of dialog
    title: 'Choose an image source...',
    //options
    options: ['Camera','Photo Gallery', 'Cancel'],
    //index of cancel button
    cancel:2
});
 
//add event listener
dialog.addEventListener('click', function(e) {
    //if first option was selected
    if(e.index == 0)
    {
        //then we are getting image from camera
        Titanium.Media.showCamera({
            //we got something
            success:function(event)
            {
                //getting media
                var image = event.media;
                 
                //checking if it is photo
                if(event.mediaType == Ti.Media.MEDIA_TYPE_PHOTO)
                {
                    //we may create image view with contents from image variable
                    //or simply save path to image
                    Ti.App.Properties.setString("image", image.nativePath);
                }
            },
            cancel:function()
            {
                //do somehting if user cancels operation
            },
            error:function(error)
            {
                //error happend, create alert
                var a = Titanium.UI.createAlertDialog({title:'Camera'});
                //set message
                if (error.code == Titanium.Media.NO_CAMERA)
                {
                    a.setMessage('Device does not have camera');
                }
                else
                {
                    a.setMessage('Unexpected error: ' + error.code);
                }
 
                // show alert
                a.show();
            },
            allowImageEditing:true,
            saveToPhotoGallery:true
        });
    }
    else if(e.index == 1)
    {
        //obtain an image from the gallery
        Titanium.Media.openPhotoGallery({
            success:function(event)
            {
                //getting media
                var image = event.media;
                // set image view
                 
                //checking if it is photo
                if(event.mediaType == Ti.Media.MEDIA_TYPE_PHOTO)
                {
                    //we may create image view with contents from image variable
                    //or simply save path to image
                    Ti.App.Properties.setString("image", image.nativePath);
                }  
            },
            cancel:function()
            {
                //user cancelled the action fron within
                //the photo gallery
            }
        });
    }
    else
    {
        //cancel was tapped
        //user opted not to choose a photo
    }
});
 
//show dialog
dialog.show();
Thanks
I'm using this code for opening the camera and it works correctly:
Titanium.Media.showCamera({
success:function(event)
{
//getting media
var image = event.media;
im=image;
//checking if it is photo
if(event.mediaType == Ti.Media.MEDIA_TYPE_PHOTO)
{
imgpath= image.nativePath;
$.userphoto.image=imgpath;//$.userphoto is an imageview
}
},
cancel:function()
{
//do somehting
},
error:function(error)
{
//error happened,
var a = Titanium.UI.createAlertDialog({title:'Camera'});
//set message
if (error.code == Titanium.Media.NO_CAMERA)
{
alert('No Cam');
}
else
{
alert('error');
}
},
mediaTypes:[Ti.Media.MEDIA_TYPE_VIDEO,Ti.Media.MEDIA_TYPE_PHOTO]
});
}
and this is the code i use for opening the photo gallery (also works fine):
Titanium.Media.openPhotoGallery({
success:function(event)
{
//check if photo
if(event.mediaType == Ti.Media.MEDIA_TYPE_PHOTO)
{
im=resize(event.media); //just a function to resize the photo
imgpath= event.media.nativePath;
$.userphoto.image=imgpath;
}
},
cancel:function()
{
//user cancelled
}
});
By the way now i'm using Titanium SDK 3.4.1 GA, but it also used to work on 3.1.3GA