In my expo / react app I have some HTML from a website that I'm pulling from an api. I'd like to use links within that html to link to pages within the app. Some example html...
responseHtml = "<p>this is a paragraph Some Page<p>"
then I was thinking I would do some string replace so that the html ends up looking like this...
responseHtml = "<p>this is a paragraph Some Page<p>"
Then I would render the content in my app and the links would work if I did something like this...
<HTML onLinkPress={(event, href)=>{Linking.openURL(href)}} html="{responseHtml}" />
I cannot seem to find the right href value to make a successful click to a page within the app. I've tried using the full path, exp://127.0.0.1:19200/Article/some-page, I've tried relative links like /Article/some-page, and I've tried setting a schema value to "myapp" in the app.json and linking to it with myapp://Article/some-page
Have you tried to parse it ? I would use the react-native-htmlview library. There you can customize the Link handler. So you could open the link or pass it down as prop.
Your code could be look like this:
import React from 'react';
import HTMLView from 'react-native-htmlview';
class App extends React.Component {
render() {
const responseHTML = ``;
return (
<HTMLView
value={htmlContent}
stylesheet={{
fontWeight: '300',
color: '#FF3366', // make links coloured pink
}}
/>
);
}
}
If you want to do any custom actions with your link it could look like this:
return (
<HTMLView
value={this.props.putyourhtmlhere}
onLinkPress={(url) => console.log('clicked link: ', url)}
/>
);
Hope that helps
Related
I'm trying to load a image from users phone, crop it and then display. Im using the webview plugin to do that. It works as intended on android but not on IOS.
I've tried this from another question, which resloves to file not found error
itemSrc = itemSrc.replace(/^file:\/\//, '');
I also looked at NormalizeURL but that does not seem to work with Ionic 4
Heres some code
this.imagePicker.getPictures(options)
.then((results: string[]) => {
results.forEach(res => {
this.crop.crop(res, {quality: 50})
.then(
data =>{
//this is extracting the URL
this.user.photos.push(this.webview.convertFileSrc(data));
},
After that, the UI should display the cropped image, which it does on android, but not on IOS.
I used safari dev tools to inspect and this is the error:
[Error] Failed to load resource: unsupported URL (unsafe:ionic://localhost/_app_file_/Users/radmac/Library/Developer/CoreSimulator/Devices/8E6A6BFA-66FA-4DB3-B556-BCE9E2EFE33A/data/Containers/Data/Application/C39D8D99-0F67-4D33-9195-EE2B4D4E4707/tmp/cdv_photo_024.jpg, line 0)
So, I found the solution for this. Before that, You can read this blog post which is really helpful if you want to understand more about ionic native and images.
https://ionicframework.com/blog/storing-photos-with-the-cordova-camera-and-file-plugins/
the solution was to just wrap the webview converted src with dom sanitizer, like so,
const resolvedImg = this.webview.convertFileSrc(data);
this.user.photos.push(<string>this.sanitizer.bypassSecurityTrustUrl(resolvedImg));
Make sure to import the dom sanitizer.
import {DomSanitizer} from "#angular/platform-browser";
...
constructor(private sanitizer: DomSanitizer){
...
}
I load a webpage via the inappbrowser plugin for my Phonegap app.
The app shows a website and a webshop which are both accessible from the web as well.
I cannot add a button 'go back to app' (this wouldn't make sense when visiting the site from PC). So I want a custom navigation (I prefer bootstrap) in the phonegap app so I can navigate between multiple different websites.
Unfortunately the navigation gets hidden by the inappbrowser. Is there a way to show the app html navigation on top of the inappbrowser?
Thanks a lot!
adding absolute position, z-index 999999 and display block with css didn't help
One way you do could this is inject the button into your webpage by generating it in your Cordova app Webview:
var inAppBrowserRef = cordova.InAppBrowser.open("http://www.mypage.com", "_blank");
inAppBrowserRef.addEventListener('loadstop', function(e) {
inAppBrowserRef.executeScript({
code: '\
var body = document.querySelector("body");\
var button = document.createElement("div");\
button.innerHTML = "Return to app";\
button.classList.add("close_button");\
button.onclick = function() {\
webkit.messageHandlers.cordova_iab.postMessage(JSON.stringify({action: "closeIAB"}));\
};\
body.appendChild(button);\
'
});
});
You'd then add a listener for the message that's posted when the button is click which closes the inappbrowser:
inAppBrowserRef.addEventListener("message", function (params){
if(params.data.action === "closeIAB"){
inAppBrowserRef.close();
}
});
You could also inject the styling of the button from within your Cordova app:
inAppBrowserRef.insertCSS({
"code": "\
.close_button {\
position: fixed;\
bottom: 0;\
z-index: 500;\
width: 100%;\
background: white;\
color: black;\
padding: 10px;\
font-size: 20px;\
}"
});
Or if you prefer, add the button styling to the CSS in your webpage (if it's under your control).
Similarly, if you don't like the idea of creating the button HTML dynamically, you could include it as part of your webpage but hide it by default unless a particular class is injected by the app:
inAppBrowserRef.addEventListener('loadstop', function(e) {
inAppBrowserRef.executeScript({
code: '\
var body = document.querySelector("body");\
body.classList.add("is_app");\
'
});
});
And in your website CSS:
body:not(.is_app) .close_button{
display: none;
}
Note that the emulation of the postMessage API that has been added to cordova-plugin-inappbrowser for Android & iOS by this PR is not yet in the latest release version on npm (v3.0.0) so you'll need to install the plugin directly off the Github master branch (v3.1.0-dev):
cordova plugin add https://github.com/apache/cordova-plugin-inappbrowser
I did this long time ago another way. The in app browser opened a website with a additional GET parameter, so the website knows it's opened inside the app. Then in the website I generated a special button, with href containing a custom scheme and some command. (E.g. myapp://close-browser)
Then I configured the app to capture the custom url by using regular app scheme configuration. Once I captured the command in javascript, I closed the in app browser using it's API.
I have integrated fusion chart to my application in React Native. For iOS, Its working fine, But, In android while I tried to display graph, Its showing html content in the UI.
I have followed installation steps properly from github page.
//header declaration
const fusionChartiOSPath = require('../assets/fusioncharts.html');
const fusionChartAndroidPath = { uri: 'file:///android_asset/fusioncharts.html' };
//render method
<FusionCharts
type={type}
width={width}
height={height}
dataFormat={dataFormat}
dataSource={dataSource}
containerBackgroundColor={containerBackgroundColor}
libraryPath={
Platform.OS === 'ios'
? fusionChartiOSPath
: fusionChartAndroidPath
}
/>
But, In UI its showing like
<!DOCTYPE html>
<html>
....
Can anyone suggest me, Where I am doing wrong?
It's happening due to some file issue. Fixed
I have a mobile site and I want to make an android browser app where I want to open my site.
I have tried and react-native-browser. Something like..
import {
processColor, // make sure to add processColor to your imports if you want to use hex colors as shown below
} from 'react-native';
// at the top of your file near the other imports
var Browser = require('react-native-browser');
class SampleApp extends Component {
render() {
return (
<View style={{paddingTop:20, flex:1}}>
{Browser.open('https://google.com/')}
</View>
);
}
}
But got no success...
I just want to make a browser that opens my mobile site..
Is there any better way of doing this or if someone has any idea how to use react-native-browser ?
Thanks in advance
Looking at the source code, it seems this browser is only available on iOS.
you must search in this web https://js.coach/react-native?search=browser for example https://github.com/d-a-n/react-native-webbrowser
Why are you trying to look for an external library while there is a WebView Component already integrated with react-native itself?
WebView renders web content in a native view. You can use this
component to navigate back and forth in the web view's history and
configure various properties for the web content.
You can just add a WebView and open up the desired web url.
Example
import React, { Component } from 'react';
import { WebView } from 'react-native';
class MyWeb extends Component {
render() {
return (
<WebView
source={{uri: 'https://github.com/facebook/react-native'}}
style={{marginTop: 20}}
/>
);
}
}
You can use https://www.npmjs.com/package/react-native-webbrowser
Install:
npm i react-native-webbrowser --save
Use:
class SampleApp extends Component {
render() {
return (
<View style={{paddingTop:20, flex:1}}>
<Webbrowser
url="https://your-url.com"
hideHomeButton={true}
hideToolbar={true}
hideAddressBar={true}
hideStatusBar={true}
foregroundColor={'#efefef'}
backgroundColor={'#333'}
/>
</View>
);
}
Set all the hide's props to true to make your app display only the site
I'm having trouble getting the Webview on ReactNative to execute the injected JavaScript on a physical Android device. I've scoured the web as far as I could over the past 2 days and still haven't found a solution. Results for testing are as follows:
iOS simulator - All good
iPhone - All good
Android simulator - All good
Physical devices, Sony Xperia Z2, Sony Xperia Z5 Compact and LG G4 - NOTHING
My Webview is defined as follows:
<WebView
style={styles.webView}
source={{
html: html,
baseUrl: 'web/'
}}
injectedJavaScript={'render(' + JSON.stringify(this.state.data) + ');'}
javaScriptEnabledAndroid={true}
scrollEnabled={false}
bounces={false}
renderLoading={() => <LoadingIndicator />}
/>
I've tried specifying javaScriptEnabled as well, to no avail. I also tried smaller scripts to just colour elements on the page or post a message back to the app using window.postMessage, but nothing happens. I need to inject the data to the HTML, which will render graphs for me based on the supplied data. My last resort is to manually construct the HTML with the data appended as part of the markup being supplied to the Webview, but I'd really like to keep it simple and just get it to work the way it should.
I'm using the latest version of ReactNative (0.41) and the phones are running Android 6+.
I just discovered that the Android WebView appears to inject any JS as a single line, even if it includes line breaks. That means that missing semicolons can definitely cause issues, or, in my case, comments delimited by //. Using /* and */ for comments got my injected JavaScript working again.
Well, after leaving this question open for some time and finding a (not so elegant) solution to the problem, I decided I'd share what I ended up doing:
I declared the HTML to be passed to the WebView in a constant string along these lines: const html = '<html>...<script>...[INJECTEDSCRIPT]</script></html>';
I retrieved the data in the componentDidMount() event of the React component's lifecycle and set a state variable for it using this.setState({ data: retrievedData });
This, of course, forced the component to re-render itself, after which I now have the data available to "pass" to the WebView
Seeing as I couldn't find any elegant or usable way of using the injectedJavaScript property to work the way I want it to (as stated in the question), I resorted to replacing the [INJECTEDSCRIPT] value in the HTML constant with the serialized data.
Not the most elegant solution, I know, but it's the only one I could get working reliably across a multitude of devices and emulator configurations. Sample, edited for brevity, as below:
const html = `
<!DOCTYPE html>
<html>
<head>...</head>
<body>...</body>
<script>
var render = function (data) {
...
};
[INJECTEDSCRIPT]
</script>
</html>`;
export class GraphComponent extends Component {
constructor(props) {
super(props);
this.state = {};
}
componentDidMount = () => {
SERVICE.getData().done((data) => {
this.setState({ data: data });
});
}
render = () => {
if (!this.state.data)
return <LoadingIndicator />;
let serializedData = JSON.stringify(this.state.data);
return
<WebView
style={styles.webView}
source={{
html: html.replace('[INJECTEDSCRIPT]', 'render(' + serializedData + ');'),
baseUrl: 'web/'
}}
scrollEnabled={false}
bounces={false}
renderLoading={() => <LoadingIndicator />}
/>;
}
}
I have been struggling to get Javascript (pre-embed and injected) to be executed as well. So far, a simple and better solution is to use WebViewBridge. After, everything worked as expected. Here a link to the package: cnpmjs.org/package/react-native-webview-bridge.
Here a demo:
import React, {
Component
} from 'react';
import PropTypes from 'prop-types';
import {
Platform,
WebView,
ActivityIndicator,
} from 'react-native';
import WevViewBridge from 'react-native-webview-bridge';
// TODO: Keep in mind that you should ALWAYS edit
// two separate file and keep them matched.
const IOS_WEB_PAGE_SOURCE = './webPage/wordBody.html';
const ANDROID_WEB_PAGE_SOURCE = 'file:///android_asset/webPage/wordBody.html';
export default class WordBody extends Component {
static propTypes = {
data: PropTypes.object.isRequired,
}
_injectedScript = `
(function(){
let data = ${JSON.stringify(this.props.data)};
refresh(data);
})();
`;
render() {
/*
* We are using Platform.select here for two reasons:
* 0. Everythig work fine for IOS using `WebView` from RN
* 1. Android doesn't load web ressource with `require`
* 2. On Android, `WebView` from react-native doesn't
* execute JavaScript so we use `WebViewBridge`.
*/
return Platform.select({
ios: (<WebView
style = {{backgroundColor: 'rgba(0, 0, 0, 0)', flex:1,}}
scalesPageToFit
source = {require(IOS_WEB_PAGE_SOURCE)}
javaScriptEnabled={true}
originWhitelist={['*']}
injectedJavaScript = {this._injectedScript}
renderLoading={() => <ActivityIndicator/>}
/>),
android: (<WevViewBridge
style = {{backgroundColor: 'rgba(0, 0, 0, 0)', flex:1,}}
scalesPageToFit
source = {{uri:ANDROID_WEB_PAGE_SOURCE}}
javaScriptEnabled={true}
// originWhitelist={['*']}
injectedJavaScript = {this._injectedScript}
renderLoading={() => <ActivityIndicator/>}
/>)
});
};
}