Introduction
Microsoft ALM API (https://docs.microsoft.com/en-us/sharepoint/dev/apis/alm-api-for-spfx-add-ins) only works on O365 to SpFx add-in deployment via code. "LoadAndInstallApp
" method works fine for ordinary app deployment (SP2013 era) to SP2016 (on premise) but it doesn't work for SpFx add-in.
Background
I had authored an automated tool to facilitate SharePoint site provisioning & deployment of sever side webparts on SP2010/2013 & O365 using CSOM. Recently, I started developing SpFx add-ins for a client & I wanted to enhance that tool for .sppkg package deployment too. Only problem, Microsoft's released ALM API (for automated Spfx deployment) does not work on SP2016, it only works on O365, leaving us with SP2013 era "LoadAndInstallApp
" method. Although, this method does not work with the .sppkg file we produce with
gulp package-solution
command. In order to make .sppkg file compatible with "LoadAndInstallApp
" method, we need to make some modifications to AppManifest.xml file within .sppkg file. I added an empty "StartPage
" node after "Title
" node & an empty "Internal
" node nested within "AppPrincipal
" node.
Using the Code
The first step is to upload the .sppkg file to App Catalog as is. You will write the code as you upload a document to any other SharePoint library. App Catalog is no different in this regard.
The second step is to deploy the app as you would deploy any SP2013 era app. The code to deploy the app is not related to this tip.
The third step is what this tip is about.
Code to augment AppManifest.xml file:
Package package = Package.Open(appFullPath, FileMode.Open);
Uri manifestUri = new Uri("/AppManifest.xml", UriKind.Relative);
Uri partUri = PackUriHelper.CreatePartUri(manifestUri);
PackagePart part = package.GetPart(partUri);
Stream partStream = part.GetStream();
StreamReader reader = new StreamReader(partStream);
string content = reader.ReadToEnd();
if (content.IndexOf("<startpage>") == -1)
content = content.Replace("</Title>", "</Title><startpage>/</startpage>");
if (content.IndexOf("<appprincipal>") == -1)
content = content.Replace("</Properties>", "</Properties><appprincipal><internal></internal></appprincipal>");
partStream.Position = 0;
partStream.SetLength(0);
StreamWriter writer = new StreamWriter(partStream);
writer.Write(content);
writer.Flush();
package.Close();
Code to deploy the spfx add-in to a site collection is as follows:
using (var packageStream = System.IO.File.OpenRead(appFullPath))
{
var appInstance = context.Web.LoadAndInstallApp(packageStream);
context.Load(appInstance);
context.ExecuteQuery();
return appInstance;
}