1

I'm building a jailbreak app in which it allows deb installs.

I'm stuck on showing the output or install process in another view controller, similar to iFile and Cydia's own installer.

Does anybody know how to get this to show?

What I have so far is a table view, tap file, action sheet pops up asking to install. Pressing install starts the install process and also opens another blank UIView. How would I pass that data to the opened view?

UPDATE 1 as requested:

Code for installing deb and pushing new view controller to display output:

//Deb file extension
NSString *debFileExtension = [fileName pathExtension];
NSLog(@"fileExtension is: %@", externalFileExtension);
NSSet *supportedFileExtensions = [NSSet setWithObjects:@"deb", nil];

if ([supportedFileExtensions containsObject:[debFileExtension lowercaseString]]) {
    documentController = nil;
    NSString *actionSheetTitle = fileName;

    BlockActionSheet *sheet = [BlockActionSheet sheetWithTitle:actionSheetTitle];

    [sheet addButtonWithTitle:@"Install" block:^{

        NSString *appsyncDebPath = [path stringByAppendingPathComponent:fileName];
        NSString *cmdString=[NSString stringWithFormat:@"/usr/bin/dpkg  -i %@",appsyncDebPath];
        const char  *cmdChar=[cmdString UTF8String];
        system(cmdChar);

        DebViewController * vc = [[DebViewController alloc] init];
        [self.navigationController pushViewController:vc animated:YES];
        [vc release];

        NSLog(@"Install pressed %@", cmdString);


    }];

    [sheet setDestructiveButtonWithTitle:@"Cancel" block:nil];
    [sheet showInView:self.view];
}

From that the DebViewController gets called. The issue is the displaying of the output or log or w/e in the new view.

Would a regular UIView work? Or do I need a specific view to receive it?

UPDATE 2: with suggested NSTask.

    NSTask *task1 = [[NSTask alloc] init];
    NSPipe *pipe1 = [NSPipe pipe];
    [task1 setLaunchPath: @"/usr/bin/dpkg"];
    [task1 setArguments: [NSArray arrayWithObjects: @"-i", nil]];
    [task1 setStandardOutput: pipe1];
    [task1 launch];

    NSFileHandle *file = [pipe1 fileHandleForReading];
    NSData * data = [file readDataToEndOfFile];

    NSString * string = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];
    NSLog(@"Result: %@", string);



    UITextView *txtview = [[UITextView alloc]initWithFrame:CGRectMake(0, 20, self.view.bounds.size.width, self.view.bounds.size.height)];
    txtview.text = string;
    //some other setup like setting the font for the UITextView...
    [txtview sizeToFit];

    [self.view addSubview:txtview];

UPDATE 3: Everything is working!! Minus 1 thing.

    NSString *debPath = [path stringByAppendingPathComponent:fileName];
    NSTask *task1 = [[NSTask alloc] init];
    NSPipe *pipe1 = [NSPipe pipe];
    [task1 setLaunchPath: @"/Applications/myapp.app/"];
    [task1 setArguments: [NSArray arrayWithObjects: @"/usr/bin/dpkg", @"-i", debPath, nil]];
    [task1 setStandardOutput: pipe1];
    [task1 launch];

    NSFileHandle *file = [pipe1 fileHandleForReading];
    NSData * data = [file readDataToEndOfFile];

    OutputViewController * debOutput = [[OutputViewController alloc] init];
    UINavigationController *vc = [[UINavigationController alloc] initWithRootViewController:debOutput];
    [self.navigationController presentViewController:vc animated:YES completion:nil];
    debOutput.output = [[NSString alloc] initWithData:data encoding: NSUTF8StringEncoding];

So the provided code above works as it should, and the receiving view controller displays the output.

Only thing is, that it's not displaying the full output of the deb install. almost like its shorting the lines. I have the output set up as follows:

UITextView *l = [[UITextView alloc] initWithFrame:CGRectMake(5, 0, self.view.frame.size.width-5, self.view.frame.size.height)];
l.editable = NO;
l.textAlignment = NSTextAlignmentLeft;
l.font=[UIFont boldSystemFontOfSize:14];
l.textColor = [UIColor whiteColor];
l.backgroundColor = [UIColor colorWithWhite:0.1f alpha:1.0f];
l.text = [NSString stringWithFormat: @"%@", output];
l.textContainer.lineBreakMode = NSLineBreakByWordWrapping;
[l release];

UPDATE 4: So what I ended up doing was loading some text in the viewDidLoad when the view first showed:

NSString *cmd0 = @"Running Debian Packager";
NSString *cmd1 = @"Executing Command: /usr/bin/dpkg -i";
NSString *cmd2 = @"Preparing - ";
NSString *cmd3 = @"Installing......Please wait...";

l.text = [NSString stringWithFormat:@"%@\n\n%@\n\n%@%@\n\n%@", cmd0, cmd1, cmd2, fileName, cmd3];
l.textContainer.lineBreakMode = NSLineBreakByWordWrapping;

[view addSubview:l];

Then called the deb install process in the viewDidAppear, which replaces the above code with the output:

//NSTask
NSString *debPath = [path stringByAppendingPathComponent:vc.fileName1];

NSTask *task1 = [[[NSTask alloc] init] autorelease];
NSPipe *pipe1 = [NSPipe pipe];
[task1 setLaunchPath: @"/Applications/myapp.app/process"];
[task1 setArguments: [NSArray arrayWithObjects:@"/usr/bin/dpkg", @"-i", debPath, @"2>/tmp/dpkg.log" ,nil]];
[task1 setStandardOutput: pipe1];
[task1 launch];

NSFileHandle *file = [pipe1 fileHandleForReading];
NSData *data = [file readDataToEndOfFile];

NSString *string = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease];


NSString *cmd3 = @"Success";
NSString *cmd4 = @"*If this package requires a respring, please do so above*";

NSString *dependencies = @"*You are seeing this message because this package requires the additional dependencies listed above*";
NSString *closeCydia = @"*If you are seeing this message, Cydia is probably open. Please close, and try to install the package again*";

//DPKG LOG FILE
NSError *error;
NSString *logPath = [NSString stringWithFormat:@"/tmp"];
NSString *dpkgLogFile = [logPath stringByAppendingPathComponent:@"dpkg.log"];
NSString *logContents = [NSString stringWithContentsOfFile:dpkgLogFile encoding:NSUTF8StringEncoding error:&error];

NSString *dependsString = @"dpkg: dependency problems";
NSString *lockString = @"dpkg: status database area is locked by another process";

if ([logContents containsString:lockString]) {
    l.text = [NSString stringWithFormat:@"%@\n%@", logContents, closeCydia];
    self.navigationController.navigationBar.topItem.rightBarButtonItem = nil;

}else if ([logContents containsString:dependsString]){
    l.text = [NSString stringWithFormat:@"%@\n%@\n%@", string, logContents, dependencies];
    self.navigationController.navigationBar.topItem.rightBarButtonItem = nil;

}else{
    l.text = [NSString stringWithFormat:@"%@\n%@%@\n\n%@", string, logContents, cmd3, cmd4];
}

[view addSubview:l];

Depending on what the deb installs, I customized the output, i.e. If it has depends, or if the process is locked because Cydia is open.

All in all I'm happy with the turnout. Thanks to Nate for the direction to use NSTask, worked like a charm.

The only thing to make it better is to have it print off or readout, similar to how Cydia goes through line by line.

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
ChrisOSX
  • 724
  • 2
  • 11
  • 28
  • You have to tell us how you're accomplishing the installation. Are you calling `dpkg` programmatically? Via `system()`? Some other way? Please show some code or be more specific. – Nate Dec 09 '14 at 00:05
  • OP updated as requested. – ChrisOSX Dec 09 '14 at 02:02

1 Answers1

1

Instead of using the system() command to run the dpkg command line, I would suggest using NSTask to run the command, which makes it easier to capture the output as a NSString. Once you have a string, you can copy it into a text view, or wherever you like.

NSTask is a private API on iOS, but it's public on OS X, so there's lots of documentation available. In order to use it in your project, just find a copy of the NSTask.h header and copy it into your project (and #import it, of course).

Here's an example of using NSTask to capture command line output in a UIApplication.

Or, another one.

If your install process may take a while, and you'd like your UI to be responsive while it's running, it would be a good idea to run the method that performs the task in the background (using GCD, for example), and then write the resulting string to your UIView (text field, etc.) back on the main/UI thread.

Community
  • 1
  • 1
Nate
  • 31,017
  • 13
  • 83
  • 207
  • Ok looking into NSTask, seems more flexible. I can play around with how to install, the main question is how to send the output in the current view controller, to my DebViewController, which would handle the output in a empty text window? – ChrisOSX Dec 09 '14 at 22:34
  • I'm not sure I understand what you're asking. Do you just want to know how to move string data from the current view controller, to `DebViewController`? Just have the current view controller save a reference to the `DebViewController` (right now, you're not) and give `DebViewController` some public method or property to pass it a string. Or, since it seems like you're just running the `dpkg` command when you create the `DebViewController`, have `DebViewController` run the command in an `NSTask`. Then, you simply pass the `appsyncDebPath` to `DebViewController` when you create it. – Nate Dec 09 '14 at 22:51
  • I think a simpler method would maybe be have a text view to pop over, almost like a view controller, but kept in the same view. Sorry for being a noob to this kind of stuff, but I have never done any type of scripting or NSTask related stuff. – ChrisOSX Dec 09 '14 at 23:09
  • OP Updated with suggest use of NSTask, although I'm not sure if I'm calling the install properly. The output I should be able to manage in that text view, just needs resizing. Unless you see something else I'm not getting. Thanks. – ChrisOSX Dec 10 '14 at 00:52
  • @ChrisOSX, I'll take a look later tonight. Thanks for adding the new code to the question. Although, I can already see that you're missing your last argument. Should be something like: `[task1 setArguments: [NSArray arrayWithObjects: @"-i", appsyncDebPath, nil]];` – Nate Dec 10 '14 at 01:35
  • OP Updated with more info. – ChrisOSX Dec 14 '14 at 17:48
  • @ChrisOSX, sorry, I tuned out when you clicked the "Accept" mark. Did you still need some help with this? I'm happy to assist if you do ... just wanted to confirm. – Nate Dec 21 '14 at 07:04
  • OP updated. As for the OP goes, nope. You have been more than enough help and I appreciate it. If you have an idea for the final Update that would be cool. As it doesn't really pertain to the original question, I could always ask a new question. – ChrisOSX Dec 21 '14 at 11:06