iOS app-delegate method taking more than 17 sec - ios

I have a xamarin iOS app which has to accept audio files from other apps. For eg: it accepts audio (.mp3) file from mailing app. In the OpenURL method I have the function to save file and create a new entry in xml file. This task I suppose is taking longer than 17 sec and the app crashes.
There is a comment in AppDelegate.cs // You have 17 seconds to return from this method, or iOS will terminate your application.
Here is the code in AppDelegate.cs:
public override bool OpenUrl(UIApplication application, NSUrl url, string sourceApplication, NSObject annotation)
{
return this.Upload(url).Result;
}
async public Task<bool> Upload(NSUrl SharedUri)
{
await SomeUploadTask();
return true;
}

Can you try this,
I am not sure if this works or not.
Let's try not to block a method for more time.
public override bool OpenUrl(UIApplication app, NSUrl url, NSDictionary options)
{
Task.Run(() => SomeUploadTask());
return true;
}
private Task SomeUploadTask()
{
throw new NotImplementedException();
}

Related

Login with Xamarin.Auth in IOS Project is not working

I'm using Xamarin.Auth to login to google and facebook, It works fine with Android Project but seem like presenter is not working with IOS, it can't opon the browser for login.
Here is my code to call Presenter in viewmodel
var authenticator = new OAuth2Authenticator(
clientId,
constants.FacebookScope,
new Uri(constants.FacebookAuthorizeUrl),
new Uri(constants.FacebookAccessTokenUrl),
null,
true
);
authenticator.Completed += OnAuthCompleted;
authenticator.Error += OnAuthError;
AuthenticationState.Authenticator = authenticator;
var presenter = new Xamarin.Auth.Presenters.OAuthLoginPresenter();
presenter.Login(authenticator);
And Here is my AppDelegate in IOS project
public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
{
//
// This method is invoked when the application has loaded and is ready to run. In this
// method you should instantiate the window, load the UI into it and then make the window
// visible.
//
// You have 17 seconds to return from this method, or iOS will terminate your application.
//
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
FFImageLoading.Forms.Platform.CachedImageRenderer.Init();
Rg.Plugins.Popup.Popup.Init();
global::Xamarin.Forms.Forms.Init();
global::Xamarin.Auth.Presenters.XamarinIOS.AuthenticationConfiguration.Init();
//global::Xamarin.Auth.WebViewConfiguration.IOS.UserAgent = "moljac++";
XamEffects.iOS.Effects.Init();
FFImageLoading.Forms.Platform.CachedImageRenderer.Init();
CachedImageRenderer.InitImageSourceHandler();
LoadApplication(new App());
return base.FinishedLaunching(app, options);
}
public override bool OpenUrl
(
UIApplication application,
NSUrl url,
string sourceApplication,
NSObject annotation
)
{
// Convert iOS NSUrl to C#/netxf/BCL System.Uri - common API
Uri uri_netfx = new Uri(url.AbsoluteString);
// load redirect_url Page (send it back to Xamarin.Auth)
// for Url parsing and raising Complete or Error events
AuthenticationState.Authenticator.OnPageLoading(uri_netfx);
return true;
}
}

MockWebServer: llegalStateException: start() already called

I try to run a test with MockWebServer.
I would like to make a UI test with mocked response, so I could test for valid\invalid UI changes like logging in, or showing error in a login API.
However, each and every time I ran the code I got the following exception:
java.lang.IllegalStateException: start() already called
Code:
#RunWith(AndroidJUnit4.class)
public class UITestPlayground {
String testUrl = "http://testurl.com/";
MockWebServer server = new MockWebServer();
#Rule
public IntentsTestRule<LoginActivity> mIntentsRule = new IntentsTestRule<>(LoginActivity.class);
#Before
public void beforeHelper() throws IOException {
TestHelper.removeUserAndTokenIfAny(mIntentsRule.getActivity());
URLS.baseUrl = testUrl;
server.url(URLS.baseUrl);
//try to shutting down the server JUT IN CASE...
server.shutdown();
server.start();
}
#After
public void afterHelper() throws IOException {
server.shutdown();
}
#Test
public void invalidLoginDueNotValidJSONResponse() {
server.enqueue(new MockResponse().setBody("Something not valid JSON response"));
String emailToBeTyped = "tester#tester.com";
String passToBeTyped = "passtest";
ViewActions.closeSoftKeyboard();
// Type text and then press the button.
onView(withId(R.id.login_email_edit)).perform(typeText(emailToBeTyped));
ViewActions.closeSoftKeyboard();
onView(withId(R.id.login_pass_edit)).perform(typeText(passToBeTyped));
ViewActions.closeSoftKeyboard();
onView(withId(R.id.log_in_btn)).perform(click());
//TODO: check on valid error message appearing
}
}
What am I doing wrong? The .start() only called once, I even .shutdown() just in
case... I don't understand how could it called more than once.
Thanks in advance.
In the original example at github I have found that the order is reversed.
You actually start the server, THEN sets it's url.
And not setting the url then starting the server.
Interesting.

Loading more than URL in The same browser using jxbrowser

I'am using jxbrowser,
This code loads one URL in one browser and saves it's page .
public class JxBrowserDemo {
public JxBrowserDemo(String url) {
Browser browser = new Browser();
browser.addLoadListener(new LoadAdapter() {
#Override
public void onFinishLoadingFrame(FinishLoadingEvent event) {
if (event.isMainFrame()){
String filePath = "G:\\Test\\index"+System.currentTimeMillis()+".html";
String dirPath = "G:\\Test\\resources";
event.getBrowser().saveWebPage(filePath, dirPath, SavePageType.COMPLETE_HTML);
}
}
});
browser.loadURL(url);
if(!browser.isLoading())
{
browser.dispose();
}
}
public static void main(String args[])
{
JxBrowserDemo jxBrowserDemo=new JxBrowserDemo("www.google.com");
}
}
could I load more than URL in the same browser and save it's pages in Local Path ?
Thanks In advance ............
You can load one by one as many URLs as you want and save these web pages by the saveWebPage() method in the same browser.
You should completely load the web page, invoke the saveWebPage() method, wait until the web page is saved, and then repeat these actions with the next URL.
The dispose() method should be invoked when you don't need to perform any actions with this browser instance.

Xamarin way to open self signed certificate webpage in UIWebView

As the question title described, I want to open a self signed webpage within an UIWebview (Xamarin.iOS)
By default, self signed webpages do not load in an UIWebView.
Important requirements for the solution:
It should be accepted by Apple when I want to submit the app to the Apple app store (so a custom NSUrlRequest does not fit).
It should load css and javascript properly.
I found a possible solution on stackoverflow but this is for native iOS.
https://stackoverflow.com/a/11664147
I was also wondering if the solution described above requires to login using a NSUrlConnectionDelegate.
The desired solution should be that the user can fill-in the credentials by himself using the UIWebView.
Could someone provide the Xamarin solution for this? I tried it by myself but couldn't get it work.
Thanks in advance for your help.
I know this is quite an old post, but it was quite an interesting question, so I had to take a go at at. So if you still need it (most likely not) or if anyone finds this post, here are a ported version of the native UIWebView with support for self signed. It can be used as a regular UIWebView with the exception that it takes a hostname as additional parameter, which should be the hostname of the page where certificate check should be disabled.
public class InsecureWebView : UIWebView, INSUrlConnectionDataDelegate, IUIWebViewDelegate
{
public InsecureWebView(string baseUrl) : base()
{
Setup (baseUrl);
}
public InsecureWebView(CoreGraphics.CGRect rect, string baseUrl) : base(rect)
{
Setup (baseUrl);
}
public InsecureWebView(NSCoder coder, string baseUrl) : base(coder)
{
Setup (baseUrl);
}
public InsecureWebView(NSObjectFlag t, string baseUrl) : base(t)
{
Setup (baseUrl);
}
public InsecureWebView(IntPtr handler, string baseUrl) : base(handler)
{
Setup (baseUrl);
}
string baseUrl = null;
bool authenticated;
NSUrlRequest failedRequest;
private void Setup(string baseUrl)
{
this.Delegate = this;
this.baseUrl = baseUrl;
}
[Foundation.Export ("webView:shouldStartLoadWithRequest:navigationType:")]
public bool ShouldStartLoad (UIKit.UIWebView webView, Foundation.NSUrlRequest request, UIKit.UIWebViewNavigationType navigationType)
{
var result = authenticated;
if (!authenticated) {
failedRequest = request;
NSUrlConnection.FromRequest (request, this);
}
return result;
}
[Foundation.Export ("connection:willSendRequestForAuthenticationChallenge:")]
public void WillSendRequestForAuthenticationChallenge (NSUrlConnection connection, NSUrlAuthenticationChallenge challenge)
{
if (challenge.ProtectionSpace.AuthenticationMethod == NSUrlProtectionSpace.AuthenticationMethodServerTrust) {
var baseUrl = new NSUrl (this.baseUrl);
if (challenge.ProtectionSpace.Host == baseUrl.Host) {
challenge.Sender.UseCredential (NSUrlCredential.FromTrust (challenge.ProtectionSpace.ServerSecTrust), challenge);
}
}
challenge.Sender.ContinueWithoutCredential (challenge);
}
[Foundation.Export ("connection:didReceiveResponse:")]
public void DidReceivedResponse(NSUrlConnection connection, NSUrlResponse response)
{
authenticated = true;
connection.Cancel ();
LoadRequest (failedRequest);
}
}

How to notify progress for a YouTube video upload

I am working on a ASP.NET Web API with Angularjs for client side programming. My application users will be uploading/watching videos in my application. I want to upload these videos to YouTube (using YouTube API for server side).
For now I have completed the uploading part, but I am not sure how to show a process bar on client side browser with real indication of the progress of the video being uploaded. I can capture the progress on the server side as I am using the following code for uploading:
VideosResource.InsertMediaUpload insertRequest = youtube.Videos.Insert(video, "snippet, status", fileStream, "video/*");
insertRequest.ProgressChanged += insertRequest_ProgressChanged;
insertRequest.ResponseReceived += insertRequest_ResponseReceived;
insertRequest.Upload();
Here I can capture the ProgressChanged event to see the progress, but how can I notify my end user (browser) these progress updates?
You havea lot of ways, here are couple of them:
Make AJAX requests from client side to server in loop, and get progress. In this case you need to save progress in insertRequest_ProgressChanged into static storage (Static Dictionary of uploads).
Use SirnalR. This will allows you to make direct updates.
Anyway you need to store progress of your uploading in any storage.
For example you can create static class, something like:
public static class UploadingDispatcher
{
private static Dictionary<Guid, Int32> Uploads = new Dictionary<Guid, Int32>();
private static object syncRoot = new object();
public static void Add(Guid id)
{
lock (syncRoot)
{
Uploads.Add(id,0);
}
}
public static void Remove(Guid id)
{
lock (syncRoot)
{
Uploads.Remove(id);
}
}
public static int GetProgress(Guid id)
{
lock (syncRoot)
{
if (Uploads.ContainsKey(id))
{
return Uploads[id];
}
return 100;
}
}
public static Boolean SetProgress(Guid id, Int32 value)
{
lock (syncRoot)
{
if (Uploads.ContainsKey(id))
{
Uploads[id] = value;
return true;
}
return false;
}
}
}
Before your code you should create Upload by:
Guid uploadId = Guid.NewGuid();
UploadingDispatcher.Add(uploadId);
In your insertRequest_ProgressChanged method use UploadingDispatcher to update progress:
UploadingDispatcher.SetProgress(id);
You need to create separate action to get progress, like GetUploadingProgress. In this action method you can get progress by calling:
UploadingDispatcher.GetProgress(id);
To remove Upload from UploadingDispatcher after file is uploaded use:
UploadingDispatcher.Remove(id);

Resources