UPDATE FOR THE READERS: the code discussed here is now available in this Codename One library (and it's in the CN1 Extensions Manager too...): https://github.com/jsfan3/CN1Libs-NativeLogsReader
Short question:
I wrote a working native Android code to get the native log of the device during the executing of my Codename One apps. I used the native interface functionality provided by Codename One. I need help to implement this interface also for iOS.
Long question...
First of all, I tried to get native logs (such as the ones provided by Android Studio and XCode) to ask help when I get odd behaviors in my apps... because the standard Codename One logs aren't enough in several cases (for example, I got issues with native components like using the Google Maps CN1Lib).
I'm new to Android Studio and I'm in trouble to get the Logcat of my Codename One apps, I also have serious difficulties to use the native sources provided by the build servers. Moreover, I haven't a Mac, so I cannot use XCode.
My language skills are restricted to the Codename One Java 8, I don't "speak" the Android native Java and I feel that the iOS native Objective-C is unreadable...
That's why, to help myself to provide accurate logs when I need to file some issues in the Github repository of Codename One, I tried to write native code to the get the native logs in a String (that I can manage in several easy ways, such as I can display it in a Form and I can send it by email to myself).
So... I was able to implement the code for Android: it works perfectly. I tested in several Android versions.
CallNativeCode.java
package ...;
import com.codename1.system.NativeInterface;
/**
* Native Code interface
*/
public interface CallNativeCode extends NativeInterface {
public void clearAndRestartLog();
public String readLog();
public String getFilePath();
}
CallNativeCodeImpl.java
package ...;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class CallNativeCodeImpl {
public String getFilePath() {
return null;
}
public void clearAndRestartLog() {
// https://developer.android.com/studio/command-line/logcat
try {
Runtime.getRuntime().exec("logcat -b all -c");
Runtime.getRuntime().exec("logcat");
} catch (IOException ex) {
// logcat non available?
}
}
// original code: https://stackoverflow.com/q/12692103
public String readLog() {
try {
Process process = Runtime.getRuntime().exec("logcat -d");
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(process.getInputStream()));
StringBuilder log = new StringBuilder();
String line = "";
while ((line = bufferedReader.readLine()) != null) {
log.append(line);
log.append("\n");
}
return log.toString();
} catch (IOException e) {
return "Log is not available.";
}
}
public boolean isSupported() {
return true;
}
}
It works so: in the init() of the main class of the Codename One app I added:
// Test of Native code
CallNativeCode callNativeCode = NativeLookup.create(CallNativeCode.class);
if (callNativeCode != null && callNativeCode.isSupported()) {
Log.p("Native code can be executed");
callNativeCode.clearAndRestartLog();
Log.p("Native LOG cleared and restarted");
} else {
Log.p("Native code cannot be executed");
}
then, when I want to get the native log of the app, I can execute:
String nativeLog = callNativeCode.readLog();
In this way, I get the same output of the Android Studio Logcat without the need to use Android Studio and without the need of a device connected to a computer.
I tried to replicate this functionality for iOS... but I'm in trouble, because I don't know Objective-C. I tried to redirect the native output log to a file and then to read that file (adapting some code that I found and trying to guess how it works)... but I'm not sure how to do it and my code doesn't compile on the iOS build server.
The following code is what I tried to do. How can it be fixed? Thanks
myPackageName_CallNativeCodeImpl.h
#import <Foundation/Foundation.h>
@interface cool_teammate_registration_CallNativeCodeImpl : NSObject {
}
-(NSString*)readLog;
-(NSString*)getFilePath;
-(void)clearAndRestartLog;
-(BOOL)isSupported;
@end
myPackageName_CallNativeCodeImpl.m
#import "myPackageName_CallNativeCodeImpl.h"
@implementation myPackageName_CallNativeCodeImpl
-(NSString*)getFilePath{
NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES);
NSString* documentsDirectory = [paths objectAtIndex:0];
NSString* fileName =[NSString stringWithFormat:@"%@.log",[NSDate date]];
NSString* logFilePath = [documentsDirectory stringByAppendingPathComponent:fileName];
return logFilePath;
}
-(NSString)readLog{
NSString* logFilePath = [self getFilePath];
NSString* content = [NSString stringWithContentsOfFile:logFilePath encoding:NSUTF8StringEncoding error:nil];
return content;
}
-(void)clearAndRestartLog{
// https://stackoverflow.com/questions/5179108/iphone-how-to-read-application-logs-from-device
NSString* logFilePath = [self getFilePath];
freopen([logFilePath cStringUsingEncoding:NSASCIIStringEncoding],"a+",stderr);
}
-(BOOL)isSupported{
return YES;
}
@end