Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(android): implement BridgeFragment for easier embedding using Fragments #2666

Merged
merged 5 commits into from
Apr 3, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion android/capacitor/src/main/java/com/getcapacitor/Bridge.java
Original file line number Diff line number Diff line change
Expand Up @@ -861,7 +861,12 @@ public String getServerBasePath() {
return this.localServer.getBasePath();
}

public void setServerBasePath(String path){
/**
* Tell the local server to load files from the given
* file path instead of the assets path.
* @param path
*/
public void setServerBasePath(String path) {
localServer.hostFiles(path);
webView.post(new Runnable() {
@Override
Expand All @@ -871,6 +876,20 @@ public void run() {
});
}

/**
* Tell the local server to load files from the given
* asset path.
* @param path
*/
public void setServerAssetPath(String path) {
localServer.hostAssets(path);
webView.post(new Runnable() {
@Override
public void run() {
webView.loadUrl(appUrl);
}
});
}

public String getLocalUrl() {
return localUrl;
Expand Down
197 changes: 197 additions & 0 deletions android/capacitor/src/main/java/com/getcapacitor/BridgeFragment.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
package com.getcapacitor;

import android.app.Activity;
import android.content.Context;
import android.content.res.TypedArray;
import android.net.Uri;
import android.os.Bundle;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.WebView;

import androidx.fragment.app.Fragment;

import com.getcapacitor.android.R;
import com.getcapacitor.cordova.MockCordovaInterfaceImpl;
import com.getcapacitor.cordova.MockCordovaWebViewImpl;

import org.apache.cordova.ConfigXmlParser;
import org.apache.cordova.CordovaPreferences;
import org.apache.cordova.PluginEntry;
import org.apache.cordova.PluginManager;

import java.util.ArrayList;
import java.util.List;

/**
* A simple {@link Fragment} subclass.
* Activities that contain this fragment must implement the
* {@link BridgeFragment.OnFragmentInteractionListener} interface
* to handle interaction events.
* Use the {@link BridgeFragment#newInstance} factory method to
* create an instance of this fragment.
*/
public class BridgeFragment extends Fragment {
private static final String ARG_START_DIR = "startDir";

private String startDir;

private OnFragmentInteractionListener mListener;

private WebView webView;
protected Bridge bridge;
protected MockCordovaInterfaceImpl cordovaInterface;
protected boolean keepRunning = true;
private ArrayList<PluginEntry> pluginEntries;
private PluginManager pluginManager;
private CordovaPreferences preferences;
private MockCordovaWebViewImpl mockWebView;
private int activityDepth = 0;
private String bridgeStartDir;

private String lastActivityPlugin;

private List<Class<? extends Plugin>> initialPlugins = new ArrayList<>();


public BridgeFragment() {
// Required empty public constructor
}

/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* @param startDir the directory to serve content from
* @return A new instance of fragment BridgeFragment.
*/
public static BridgeFragment newInstance(String startDir) {
BridgeFragment fragment = new BridgeFragment();
Bundle args = new Bundle();
args.putString(ARG_START_DIR, startDir);
fragment.setArguments(args);
return fragment;
}

protected void init(Bundle savedInstanceState) {
loadConfig(this.getActivity().getApplicationContext(), this.getActivity());
}

/**
* Load the WebView and create the Bridge
*/
protected void load(Bundle savedInstanceState) {
Log.d(LogUtils.getCoreTag(), "Starting BridgeActivity");

Bundle args = getArguments();
String startDir = null;

if (args != null) {
startDir = getArguments().getString(ARG_START_DIR);
}

webView = getView().findViewById(R.id.webview);
cordovaInterface = new MockCordovaInterfaceImpl(this.getActivity());
if (savedInstanceState != null) {
cordovaInterface.restoreInstanceState(savedInstanceState);
}

mockWebView = new MockCordovaWebViewImpl(getActivity().getApplicationContext());
mockWebView.init(cordovaInterface, pluginEntries, preferences, webView);

pluginManager = mockWebView.getPluginManager();
cordovaInterface.onCordovaInit(pluginManager);

if (preferences == null) {
preferences = new CordovaPreferences();
}

bridge = new Bridge(this.getActivity(), webView, initialPlugins, cordovaInterface, pluginManager, preferences);

if (startDir != null) {
bridge.setServerAssetPath(startDir);
}

if (savedInstanceState != null) {
bridge.restoreInstanceState(savedInstanceState);
}
this.keepRunning = preferences.getBoolean("KeepRunning", true);
}

public void loadConfig(Context context, Activity activity) {
ConfigXmlParser parser = new ConfigXmlParser();
parser.parse(context);
preferences = parser.getPreferences();
preferences.setPreferencesBundle(activity.getIntent().getExtras());
pluginEntries = parser.getPluginEntries();
}


@Override
public void onInflate(Context context, AttributeSet attrs, Bundle savedInstanceState) {
super.onInflate(context, attrs, savedInstanceState);

TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.bridge_fragment);
CharSequence c = a.getString(R.styleable.bridge_fragment_start_dir);

if (c != null) {
String startDir = c.toString();
Bundle args = new Bundle();
args.putString(ARG_START_DIR, startDir);
setArguments(args);
}
}

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_bridge, container, false);
}

@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
this.init(savedInstanceState);
this.load(savedInstanceState);
}

@Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof OnFragmentInteractionListener) {
mListener = (OnFragmentInteractionListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnFragmentInteractionListener");
}
}

@Override
public void onDetach() {
super.onDetach();
mListener = null;
}

/**
* This interface must be implemented by activities that contain this
* fragment to allow an interaction in this fragment to be communicated
* to the activity and potentially other fragments contained in that
* activity.
* <p>
* See the Android Training lesson <a href=
* "http://developer.android.com/training/basics/fragments/communicating.html"
* >Communicating with Other Fragments</a> for more information.
*/
public interface OnFragmentInteractionListener {
void onFragmentInteraction(Uri uri);
}
}
13 changes: 11 additions & 2 deletions android/capacitor/src/main/java/com/getcapacitor/Splash.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import android.animation.Animator;
import android.app.Activity;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.ColorStateList;
import android.graphics.Color;
import android.graphics.PixelFormat;
Expand Down Expand Up @@ -47,7 +48,14 @@ private static void buildViews(Context c) {
String splashResourceName = Config.getString(CONFIG_KEY_PREFIX + "androidSplashResourceName", "splash");

int splashId = c.getResources().getIdentifier(splashResourceName, "drawable", c.getPackageName());
Drawable splash = c.getResources().getDrawable(splashId, c.getTheme());

mlynch marked this conversation as resolved.
Show resolved Hide resolved
Drawable splash;
try {
splash = c.getResources().getDrawable(splashId, c.getTheme());
} catch (Resources.NotFoundException ex) {
Log.w(LogUtils.getCoreTag(), "No splash screen found, not displaying");
return;
}

if (splash instanceof Animatable) {
((Animatable) splash).start();
Expand Down Expand Up @@ -257,8 +265,9 @@ public void run() {

try {
wm.addView(splashImage, params);
} catch (IllegalStateException ex) {
} catch (IllegalStateException | IllegalArgumentException ex) {
Log.d(LogUtils.getCoreTag(), "Could not add splash view");
return;
}

splashImage.setAlpha(0f);
Expand Down
13 changes: 13 additions & 0 deletions android/capacitor/src/main/res/layout/fragment_bridge.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#F0FF1414"
tools:context="com.getcapacitor.BridgeFragment">

<com.getcapacitor.CapacitorWebView
android:id="@+id/webview"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />

</FrameLayout>
6 changes: 6 additions & 0 deletions android/capacitor/src/main/res/values/attrs.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="bridge_fragment">
<attr name="start_dir" format="string"/>
</declare-styleable>
</resources>
7 changes: 7 additions & 0 deletions example/android/app/src/main/assets/page1/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<html>
<head>
</head>
<body>
<h1>Hello from HTML</h1>
</body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.getcapacitor.myapp;

import android.net.Uri;
import android.os.Bundle;
import android.widget.TextView;

import androidx.appcompat.app.AppCompatActivity;
import androidx.viewpager.widget.ViewPager;

import com.getcapacitor.BridgeFragment;

public class SimpleFragmentActivity extends AppCompatActivity implements BridgeFragment.OnFragmentInteractionListener {
private TextView mTextMessage;
private ViewPager mViewPager;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fragment_simple);
}



@Override
public void onFragmentInteraction(Uri uri) {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillType="evenOdd"
android:pathData="M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z"
android:strokeWidth="1"
android:strokeColor="#00000000">
<aapt:attr name="android:fillColor">
<gradient
android:endX="78.5885"
android:endY="90.9159"
android:startX="48.7653"
android:startY="61.0927"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<android.widget.FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:capacitor="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">

<fragment
class="com.getcapacitor.BridgeFragment"
android:id="@+id/bridge_fragment"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
capacitor:start_dir="page1"
/>


</android.widget.FrameLayout>
2 changes: 2 additions & 0 deletions example/android/app/src/main/res/values/dimens.xml
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
<resources>
<dimen name="fab_margin">16dp</dimen>
<dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen>
</resources>
5 changes: 5 additions & 0 deletions example/android/app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,9 @@
<string name="app_name">MyApp</string>
<string name="title_activity_main">MyApp</string>
<string name="custom_url_scheme">com.getcapacitor.myapp</string>
<string name="title_activity_fragment">FragmentActivity</string>

<string name="title_home">Home</string>
<string name="title_dashboard">Dashboard</string>
<string name="title_notifications">Notifications</string>
</resources>
Loading